我正在查看 KD树最近邻搜索的维基百科页面。
维基百科中给出的伪代码在点为2-D(x,y)时起作用。
我想知道,当点是3-D(x,y,z)时,我应该做出什么改变。
我google了很多,甚至在堆栈溢出中经历了类似的问题链接,但我没有找到任何地方的3-d实现,所有先前的问题都需要2-D点作为输入,而不是3-D点我正在寻找。
用于构建KD树的Wiki中的伪代码是::
function kdtree (list of points pointList, int depth)
{
// Select axis based on depth so that axis cycles through all valid values
var int axis := depth mod k;
// Sort point list and choose median as pivot element
select median by axis from pointList;
// Create node and construct subtrees
var tree_node node;
node.location := median;
node.leftChild := kdtree(points in pointList before median, depth+1);
node.rightChild := kdtree(points in pointList after median, depth+1);
return node;
}
如何在构建KD树后立即找到最近邻居?
谢谢!
答案 0 :(得分:5)
您完全按照维基百科页面“最近邻搜索”标题下的描述找到最近的邻居。这里的描述适用于任何数量的维度。那就是:
答案 1 :(得分:2)
我最近为三维空间中的最近邻搜索编写了一个KDTree,并遇到了同样的问题,了解NNS,尤其是3.2维基。我最终使用这个算法似乎适用于我的所有测试:
这是最初的叶子搜索:
public Collection<T> nearestNeighbourSearch(int K, T value) {
if (value==null) return null;
//Map used for results
TreeSet<KdNode> results = new TreeSet<KdNode>(new EuclideanComparator(value));
//Find the closest leaf node
KdNode prev = null;
KdNode node = root;
while (node!=null) {
if (KdNode.compareTo(node.depth, node.k, node.id, value)<0) {
//Greater
prev = node;
node = node.greater;
} else {
//Lesser
prev = node;
node = node.lesser;
}
}
KdNode leaf = prev;
if (leaf!=null) {
//Used to not re-examine nodes
Set<KdNode> examined = new HashSet<KdNode>();
//Go up the tree, looking for better solutions
node = leaf;
while (node!=null) {
//Search node
searchNode(value,node,K,results,examined);
node = node.parent;
}
}
//Load up the collection of the results
Collection<T> collection = new ArrayList<T>(K);
for (KdNode kdNode : results) {
collection.add((T)kdNode.id);
}
return collection;
}
这是从最近的叶节点开始的递归搜索:
private static final <T extends KdTree.XYZPoint> void searchNode(T value, KdNode node, int K, TreeSet<KdNode> results, Set<KdNode> examined) {
examined.add(node);
//Search node
KdNode lastNode = null;
Double lastDistance = Double.MAX_VALUE;
if (results.size()>0) {
lastNode = results.last();
lastDistance = lastNode.id.euclideanDistance(value);
}
Double nodeDistance = node.id.euclideanDistance(value);
if (nodeDistance.compareTo(lastDistance)<0) {
if (results.size()==K && lastNode!=null) results.remove(lastNode);
results.add(node);
} else if (nodeDistance.equals(lastDistance)) {
results.add(node);
} else if (results.size()<K) {
results.add(node);
}
lastNode = results.last();
lastDistance = lastNode.id.euclideanDistance(value);
int axis = node.depth % node.k;
KdNode lesser = node.lesser;
KdNode greater = node.greater;
//Search children branches, if axis aligned distance is less than current distance
if (lesser!=null && !examined.contains(lesser)) {
examined.add(lesser);
double nodePoint = Double.MIN_VALUE;
double valuePlusDistance = Double.MIN_VALUE;
if (axis==X_AXIS) {
nodePoint = node.id.x;
valuePlusDistance = value.x-lastDistance;
} else if (axis==Y_AXIS) {
nodePoint = node.id.y;
valuePlusDistance = value.y-lastDistance;
} else {
nodePoint = node.id.z;
valuePlusDistance = value.z-lastDistance;
}
boolean lineIntersectsCube = ((valuePlusDistance<=nodePoint)?true:false);
//Continue down lesser branch
if (lineIntersectsCube) searchNode(value,lesser,K,results,examined);
}
if (greater!=null && !examined.contains(greater)) {
examined.add(greater);
double nodePoint = Double.MIN_VALUE;
double valuePlusDistance = Double.MIN_VALUE;
if (axis==X_AXIS) {
nodePoint = node.id.x;
valuePlusDistance = value.x+lastDistance;
} else if (axis==Y_AXIS) {
nodePoint = node.id.y;
valuePlusDistance = value.y+lastDistance;
} else {
nodePoint = node.id.z;
valuePlusDistance = value.z+lastDistance;
}
boolean lineIntersectsCube = ((valuePlusDistance>=nodePoint)?true:false);
//Continue down greater branch
if (lineIntersectsCube) searchNode(value,greater,K,results,examined);
}
}
可以找到完整的java源代码here。
答案 2 :(得分:0)
我想知道,当得分时,我应该做些什么改变 3-d(X,Y,Z)。
您获得此行的当前轴
var int axis := depth mod k;
现在,根据轴,您可以通过比较相应的属性来找到中位数。例如。如果axis = 0,则与x属性进行比较。实现此目的的一种方法是在执行搜索的例程中传递比较器函数。