Balancing KD-Tree: Which approach is more efficient?
我正在尝试用一个kd树平衡一组(百万以上)3d点数,我有两种方法。
方式1:
使用O(N)算法沿给定轴查找arraysize/2-最大元素并将其存储在当前节点
对向量中的所有元素进行迭代,并将它们与我刚找到的元素进行比较,将较小的元素放在newarray1中,较大的元素放在newarray2中。
递归
方式2:
使用quicksort o(nlogn)沿给定轴对数组中的所有元素进行排序,将元素置于arraysize/2位置并将其存储在当前节点中。
然后将索引0中的所有元素放入newarray1中的arraysize/2-1,将索引0中的所有元素放入newarray2中的arraysize/2中的元素放入newarraysize-1。
递归
方法2看起来更"优雅",但是方法1看起来更快,因为中间搜索和迭代都是O(n),所以我得到O(2n),它只减少到O(n)。但同时,即使方法2是o(nlogn)排序时间,也可以在恒定时间内将数组拆分为2,但它是否弥补了o(nlogn)排序时间?
我该怎么办?还是有更好的方法来做这件事,我甚至看不见?
第三条路怎么样:
使用o(n)算法(如quickselect)确保位置长度/2处的元素是正确的元素,之前的所有元素都小于,之后的所有元素都大于它(不完全排序!)-这可能是你用你的方式使用的算法1步骤1无论如何…
递归到每一半(中间元素除外),并用下一个轴重复。
请注意,实际上不需要生成"node"对象。实际上,可以将树保持在一个大数组中。搜索时,从第一个轴的长度/2开始。
我见过埃尔基用这个把戏。它使用很少的内存和代码,这使得树非常快。
请注意,如果查询超矩形包含多个点(例如,所有点),那么树是否平衡并不重要。如果查询超矩形很小,则平衡树很有用。
另一种方式:
对每个维度进行排序:o(k n log n)。这将只执行一次,我们将使用维度上的排序列表。
对于当前维度,查找o(1)时间中的中位数,拆分o(n)时间中的中位数,同时拆分o(kn)时间中每个维度的排序数组,并在下一个维度中递归。
这样,您将在开始时执行排序。并对每个子树执行(k+1)拆分/筛选,以获取已知值。对于小K,这种方法应该比其他方法更快。
注意:使用Anony mouse所指出的技巧可以减少算法所需的额外空间。