iKd-Tree学习
📌iKdTree:增量式KdTree数据结构
KdTree
- 一般来说,KdTree的作用就是 **“k近邻搜索”和“k范围内近邻搜索”**
KdTree的问题
-
随着节点的“插入”和“删除”,KdTree也得改变,因为KdTree是由无数个节点组成的;
-
在SLAM中,更关心的是KdTree如何删除;
-
KdTree不断地插入新的节点,删除过旧的节点,那么在这个过程中,会导致kdTree结构被破坏(一个完整的结构,其中一部分被删除了,结构肯定被破坏了,而且“树”的平衡性也会被破坏)
-
所谓 “平衡性”,就是“树”的左右两侧,节点数差大于阈值;
-
删除一个中间节点意味着该节点下方的所有节点都要重构新的subtree,因此删除是一个很低效的操作;
-
-
当KdTree的结构被破坏的时候,搜索效率大幅度下降;
-
针对KdTree,大量的时间并不是花在“搜索”上,而是消耗在“树的构建”,因为每次“删除节点”,都需要重新构建“树”,非常的耗时;
iKd-Tree
“树”结构完整性
-
针对Kd-Tree的“结构被破坏,不得不重建”的问题,iKdTree设计了“增量式动态Kd-Tree0”算法,可以实现较好的“搜索/插入/删除”操作,而且不会破坏系统的“平衡性”;
-
在传统的Kd-Tree中,删除一个中间节点意味着该节点下方的所有节点都要重构新的subtree,因此删除是一个很低效的操作;
-
但是,在增量式iKd-Tree中:
-
要删除一个节点,先是将这个“要删除”的节点标记为删除,被标记为删除的节点在“KNN近邻搜索”的时候会被 “跳过”,but!“树”的结构还是存在的;
-
只有当iKd-Tree结构被“彻底重构”的时候,才会借机将这些节点从“tree结构”中删除;
-
“树”结构平衡性
-
所谓的平衡性,就是“树”的左右两侧,当发生节点删除后,某一侧可能会大量的点被删除,因为删除某个节点,该节点的子节点可能也要被删除;
-
针对 **“平衡性”的问题,iKd-Tree有对应的解决方案 **:
-
(1)方案一:当“树”的结构较小的时候,即使重构,也不会特别麻烦,时间可以忽略不计,直接将节点全部打散,删除“已经被标记的节点”,对剩下的节点执行传统“Kd-Tree”创建的操作;
-
(2)方案二:当“树”的结构很大的时候,就不能忽略重构的耗时,如果在主线程进行重构,那么就会导致iKd-Tree一直被占用,LIO/VIO系统不能访问“树”的查询与删除,算法阻塞;
-
因此,在方案二中,iKd-Tree设计了 **“并行线程”的方案,即在开一个额外的线程 **,主线程已经对“树”进行删除、增减操作,如果要删除的节点正在“被另一个线程重构”,则将此节点缓存到OperationLogger的容器中;
-
等到“额外的线程完成了重构”,再从OperationLogger的容器中拿出对应的节点来“补上”,从而保证每个节点都不会被落下;
-
-
参考
https://zhuanlan.zhihu.com/p/529926254
https://blog.youkuaiyun.com/weixin_43910370/article/details/121705356