概述
kd-tree用来维护n维空间中的点的一种数据结构。
支持插入、删除、查询k临近(包括最远点对和最近点对)。
算法
kd-tree本质是一颗二叉树。
每一层选择一个维度,找到当前维度的中点(让树尽量平衡),经过这个点,在当前维度切割,分成左右两个子树。
通常维度的选择是顺次循环的,较易实现。
更优的方法是找到方差最大的维度划分。
kd-tree的每一个节点可以理解为是维护一个n维立方体。
i.e.一维是一条线段,二维是一个矩形,三维就是一个长方体。
实际上我们就是这样实现的。
节点中需要维护:
- 划分点的坐标
- 每一个维度的坐标范围
- 孩子的指针
构建
类似于平衡树的构建方式。
灵活运用STL函数nth_element
找到当前维度的中点。
递归建树。
构建复杂度 O(nlogn)
最远最近点对查询
还是递归查询。
到达一个节点首先更新答案。
然后判断进入哪个子树继续查询。
怎么判断呢?
求一下两个子树可能的最优取值,先走那个较优的子树。
具体来说,比如你要求平面上的最远点,你就找询问坐标和两个子树所表示的矩形的最远距离,先走距离较大的那个。
如果最优的值都比当前答案优了,我们就可以不去递归了。
为什么上面说先走呢?
因为另一棵子树中仍可能有点更新答案,所以还需递归另一棵子树。
感觉很暴力对不对……
就是暴力优化= =
复杂度被证明最坏是 O(n√) 的。
但是我还没有找到什么地方有详细的证明。
插入
一脉相承。
插入一个点,判断当前维度应该被分到左子树还是右子树。
递归进行,发现不能递归下去了,就插在那个位置。
复杂度