平衡KD-Tree:哪种方法更有效?

时间:2013-06-10 10:07:34

标签: performance algorithm sorting tree kdtree

我正在尝试使用KD树平衡一组(百万+)3D点,我有两种方法。

方式1:

  1. 使用O(n)算法查找给定轴上的arraysize / 2nd最大元素并将其存储在当前节点

  2. 迭代向量中的所有元素,并将它们与我刚刚找到的元素进行比较,并将它们放在newArray1中,将那些较小的元素放在newArray2中

  3. 递归

  4. 方式2:

    1. 使用quicksort O(nlogn)沿给定轴对数组中的所有元素进行排序,取位于arraysize / 2的元素并将其存储在当前节点中。

    2. 然后将newArray1中索引0到arrayize / 2-1的所有元素,newArray2中的arraysize / 2和arraysize-1中的所有元素

    3. 递归

    4. 方式2似乎更“优雅”,但方式1似乎更快,因为中位数搜索和迭代都是O(n)所以我得到O(2n),它只是减少到O(n)。但与此同时,即使方式2是O(nlogn)时间进行排序,将数组拆分为2可以在恒定时间内完成,但它是否弥补了排序的O(nlogn)时间?

      我该怎么办?或者有更好的方法来做到这一点,我甚至没有看到?

3 个答案:

答案 0 :(得分:2)

方式3:

  1. 使用诸如QuickSelect之类的O(n)算法来确保位置长度/ 2处的元素是正确的元素,之前的所有元素都是较少的,之后的所有元素都比它大(不完全排序! ) - 这可能是你在你的方法1步骤1中使用的算法......

  2. 递归到每一半(中间元素除外)并重复下一个轴。

  3. 请注意,您实际上不需要创建“节点”对象。实际上,您可以将树保存在一个大型数组中。搜索时,使用第一个轴从长度/ 2开始。

    我已经看到ELKI正在使用这个技巧。它使用非常少的内存和代码,这使得树非常快。

答案 1 :(得分:0)

另一种方式:

为每个维度排序:O(K N log N)。这将只执行一次,我们将利用维度上的排序列表。

对于当前维度,找到O(1)时间的中位数,在O(N)时间内拆分中位数,在O(KN)时间内拆分每个维度的排序数组,并递归下一个维度。

通过这种方式,您将在开始时执行排序。并针对已知值对每个子树执行(K + 1)分割/过滤。对于小K,这种方法应该比其他方法更快。

注意:Anony-Mousse指出的技巧可以减少算法所需的额外空间。

答案 2 :(得分:0)

请注意,如果查询超矩形包含许多点(例如,所有这些点),那么树是否平衡无关紧要。如果查询超级域很小,则平衡树很有用。