K-d树:最近邻搜索算法

时间:2012-11-22 05:08:27

标签: algorithm nearest-neighbor kdtree

这是我对它的理解: 1.根据ELEMENT是否位于左侧或右侧子树(如果存在),向下递取树,取左或右子树。 2.将CURRENT_BEST设置为您到达的第一个叶节点。 3.当您重新计算时,检查ELEMENT是否靠近分裂超平面而不是CURRENT_BEST。如果是这样,请将CURRENT_BEST设置为当前节点。

这是我从Wikipedia和我的班级得到的部分,以及我不理解的部分: 4.检查3.在3中单挑出的分裂点的另一个子树中的任何节点是否比分裂点更接近ELEMENT。

我不明白为什么我们需要做4.因为任何可能位于分裂节点的一个子树中的点必须更接近分裂节点而不是另一个子树中的任何一点。

显然我对算法的理解是有缺陷的,所以非常感谢帮助。

3 个答案:

答案 0 :(得分:8)

步骤4是步骤3中的'else',如果飞机比点更近,你会怎么做。只是因为你找到的点与你找到邻居的点在同一个矩形中并不意味着它是最接近的。

想象一下以下场景:你的kD树中有两个点,A和B. A位于其矩形的中间,而B位于边缘之上,位于A旁边的分区区域。你现在搜索C点的最近邻居,它恰好是B的旁边,但恰好是边缘的另一边,在A的分区区域,由于初始深度优先搜索,你选择的第一个点将是A.选择与搜索点在同一分区中的任何内容。然而,B实际上更接近,所以即使你选择A,你需要检查B是否更接近,否则你的kD-Tree实际上不会给你正确的结果。

一种可视化的好方法是把它画出来:

  

一个------------- C-- | --B

A是我们在DFS中找到的第一个点,C是我们想要的最近邻点,B是实际的最近邻居,|是我们的分裂飞机。

考虑它的另一种方法是在点C周围绘制一个半径为dist(A,C)的圆。如果任何其他矩形有自己的任何部分落入该圆,那么它们有可能保持一个点它可能比A更接近C,所以必须检查它们。如果你现在找到B,你可以减小圆的半径(因为B更接近),以便更少的矩形有可能相交,并且一旦你检查了所有与你的圆相交的矩形(减少你的圆半径作为你的找到更近的邻居)你可以明确地说没有更近的点。

答案 1 :(得分:2)

我写了一个基本的C++ implementation on github。它有迭代和递归版本。

答案 2 :(得分:-4)

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;
}