我正在尝试实现一个Kd树来执行最近邻居并在C ++中近似最近邻搜索。到目前为止,我遇到了最基本的Kd树的两个版本。
答案 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树,也有报道称保持插入缓冲区等以推迟结构变化可以提高性能。在许多情况下,批量加载也有很大帮助!