Kd树:数据只存储在叶子上vs存储在叶子和节点上
Kd tree: data stored only in leaves vs stored in leaves and nodes
我试图实现一个Kd树来执行最近邻和近似最近邻搜索在c++中。到目前为止,我遇到了最基本的Kd树的两个版本。
- 数据存储在节点和叶子中,如这里
- 数据仅存储在叶子中的一种,例如这里
它们似乎基本相同,具有相同的渐近性质。
我的问题是:选择一个而不是另一个是否有一些原因?
到目前为止,我认为有两个原因:
- 在节点中存储数据的树也较浅1层。
- 只在叶子中存储数据的树更容易实现
delete data
功能
在决定做哪一个之前,还有其他我应该考虑的原因吗?
只需将节点标记为已删除,并将任何结构更改推迟到下一次树重建。k-d树会随着时间的推移而退化,所以你需要频繁地重建树。k-d树对于没有变化的低维数据集非常有用,或者您可以轻松地重建(近似)最优树。
至于实现树,我建议使用一个简约的结构。我通常使用而不是节点。我使用了一个数据对象引用数组。轴是由当前搜索深度定义的,不需要将其存储在任何地方。左邻域和右邻域由数组的二叉搜索树给出。(否则,只需添加一个byte
数组,即数据集大小的一半,用于存储您使用的轴)。加载树是由专门的快速排序完成的。理论上它是O(n^2)
的最坏情况,但有一个好的启发式,如5的中间值,你可以得到O(n log n)
相当可靠,并以最小的常数开销。
虽然它对C/c++没有那么大的作用,但在许多其他语言中,您将为管理大量对象付出相当大的代价。type*[]
是您能找到的最便宜的数据结构,特别是它不需要大量的管理工作。要将一个元素标记为已删除,您可以将其null
,并在遇到null
时搜索两侧。对于插入,我首先将它们收集到缓冲区中。当修改计数器达到阈值时,重新构建。
这就是它的全部意义:如果你的树重建真的很便宜(就像使用一个几乎预先排序的数组一样便宜!),那么频繁地重建树是没有坏处的。线性扫描在一个短的"插入列表"是非常CPU缓存友好。跳过null
s也很便宜。
如果你想要一个更动态的结构,我建议你看看R*-树。它们实际上是为了平衡插入和删除,并在面向磁盘的块结构中组织数据。但即使是对于r树,也有报道称保留插入缓冲区等来推迟结构变化可以提高性能。在许多情况下,散装装载也很有帮助!
- 将字符串存储在c++中的稳定内存中
- std::原子加载和存储都需要吗
- C++:将控制台输出存储在宏中更好吗
- 使用QProcess执行命令,并将结果存储在QStringList中
- 访问存储在向量C++中的结构的多态成员
- 如何从存储在std::映射中的std::集中删除元素
- 存储模板类型以强制转换回派生<T>
- 类型总是使用其大小存储在内存中吗
- 当字符串存储在变量中时,如何将字符串转换为wchar_t
- 使用无符号字符数组有效存储内存
- 如何在cpp.中使用协议缓冲区存储大缓冲区/数组(char/int)
- 使用 pqxx 将 std::vector 存储在 postgresql 中,并从数据库中检索它
- 带结构的二维矢量:如何存储元素
- 添加存储在向量中的大整数的函数出现问题
- 从文件中读取多个字节,并将它们存储在C++中进行比较
- 在std::vector上存储带有模板的类实例
- 谷歌测试中的期望值存储在哪里
- 为什么C中的通用链表中存储的数据已损坏
- 查找存储在二叉搜索树的所有非叶子中的数据总和?(返回整数的独立递归函数
- Kd树:数据只存储在叶子上vs存储在叶子和节点上