Kd树:仅存储在叶子中的数据与存储在叶子和节点中的数据

时间:2013-01-12 10:49:32

标签: c++ computer-science kdtree

我正在尝试实现一个Kd树来执行最近邻居并在C ++中近似最近邻搜索。到目前为止,我遇到了最基本的Kd树的两个版本。

  1. 数据存储在节点和叶子中的那个,例如here
  2. 数据仅存储在树叶中的文件,例如here
  3. 它们似乎基本相同,具有相同的渐近性质。

    我的问题是:为什么选择一个而不是另一个?

    到目前为止,我认为有两个原因:

    1. 在节点中存储数据的树也较浅1级。
    2. 仅在叶子中存储数据的树更容易    实施delete data功能
    3. 在决定选择哪一个之前,我还应该考虑其他一些原因吗?

1 个答案:

答案 0 :(得分:4)

您可以将节点标记为已删除,并将任何结构更改推迟到下一个树重建。 k-d-trees会随着时间的推移而降级,因此您需要经常进行树重建。 k-d-tree适用于不会改变的低维数据集,或者您可以轻松负担得起重建(近似)最佳树的位置。

至于实现树,我建议使用简约结构。我通常使用节点。我使用数据对象引用数组。轴由当前搜索深度定义,无需将其存储在任何位置。左和右邻居由数组的二叉搜索树给出。 (否则,只需添加一个byte数组,数据集大小的一半,用于存储您使用的轴)。加载树由专门的QuickSort完成。理论上它是O(n^2)最坏情况,但是如果有一个良好的启发式算法,例如5的中位数,你可以非常可靠地得到O(n log n)并且只需要很小的常量开销。

虽然它对C / C ++没有那么多,但在许多其他语言中,你将为管理大量对象付出相当大的代价。 type*[]是您找到的最便宜的数据结构,特别是它不需要大量的管理工作。要将元素标记为已删除,您可null,并在遇到null时搜索双方。对于插入,我首先在缓冲区中收集它们。当修改计数器达到阈值时,重建。

这就是它的重点:如果你的树真的很便宜重建(就像使用几乎预先排序的数组一样便宜!)那么频繁重建树并不会有害。 通过简短的“插入列表”进行线性扫描非常适合CPU缓存。跳过null也非常便宜。

如果你想要一个更加动态的结构,我建议你看看R * -trees。它们实际上是为了平衡插入和删除,并在面向磁盘的块结构中组织数据。但即使对于R树,也有报道称保持插入缓冲区等以推迟结构变化可以提高性能。在许多情况下,批量加载也有很大帮助!