kd-tree vs octree for 3d radius search

时间:2013-08-01 15:20:40

标签: search data-structures kdtree octree

我正在试图弄清楚哪种结构对于点,kd树或八叉树进行多次半径搜索会更好?在this question中已经提到过,但没有答案。在我看来,由于八叉树具有固定的叶子大小,它已经可以计算出我需要访问的分支,而对于kd-tree,你必须迭代地访问分支,直到覆盖半径。

3 个答案:

答案 0 :(得分:5)

我已经为此目的亲自和精确地实施了对八叉树的投票。我发现用八叉树获得更有效的结果要容易得多。我说更容易,因为我认为通过这些微妙的区别,它实际上更多的是关于实现者而不是数据结构。但我认为对于大多数人来说,你可以更轻松地优化八叉树。

其中一个原因是因为K-D树本身就更深,因为二次树一次分裂在一个维度上。如果您正在寻找叶子上的精确匹配元素,那么更深层的性质可能会有所帮助,就像光线/三角形交叉点在树下的单一,明确的路径一样。当深度树仔细分割时,它与搜索质量的想法相匹配,这很有用。

如果您正在搜索最大半径范围内的最近点,而您最终会花费大部分时间来上下移动,那么拥有一个深度精心分割的树是没有用的。树,从叶到父母到兄弟姐妹到祖父母到父母兄弟等等。如果您可以以缓存友好的方式访问所有内容,那么有点平坦,并且您可以轻松地使八叉树缓存友好,就像连续存储所有8个孩子一样,此时您可以这样做:

struct OctreeNode
{
    // Index of first child node. To get to the 4th node,
    // we just access nodes[first_child+3], e.g.
    int first_child;
    ...
};

所以无论如何,如果这两种选择,我会在这种情况下投票给八叉树。此外,对于这种类型的邻近搜索,您也不一定希望八叉树太深。即使我们不得不用较浅的树来查看更多的点而不是最佳点,这可能比必须经常上下树更好。如果您存储在叶子中的点是连续的,它确实有帮助。完成构建树后,您可以通过后处理实现这一目标。

请注意,两种解决方案都必须查看兄弟节点。距离点最近的点不一定是驻留在同一叶节点中的点。在某些情况下,根据数据的性质,只有三维网格才能真正达到最佳状态,因为使用3D网格,您甚至无需费心去从孩子到父母再到兄弟姐妹。 3D网格在内存使用方面似乎具有爆炸性,但如果将网格单元的内存开销降低到32位索引,则不一定非必要。在这种情况下,100x100x100网格需要不到4兆字节。

答案 1 :(得分:2)

对于3D和固定查询半径,八叉树是一个不错的选择。如果你需要在磁盘上工作,其他数据结构可能会更好,但k-d-tree也不会在这里发光。

为什么不尝试两种方法,看看哪种方法更适合您的数据?

答案 2 :(得分:2)

在我的项目中,我使用八叉树进行范围搜索,它工作效率高,易于实现。但是从未将它与KD-Tree进行比较。 据我所知,此操作的kd树中最坏的情况时间复杂度对于三维数据是O(n ^(2/3)),而八叉树只能保证O(n)。因此,如果您关心最糟糕的时间复杂性,请选择KD Tree。 (我不关心最糟糕的时间复杂性,如果我知道在我的数据集中这将永远不会发生。)