kd树的结构

转自:https://zhuanlan.zhihu.com/p/23966698

 
 

kd树是一个二叉树结构,它的每一个节点记录了【特征坐标,切分轴,指向左枝的指针,指向右枝的指针】。

其中,特征坐标是线性空间的一个点 (x_1,x_2,...,x_n)

切分轴由一个整数r表示,这里1 \le r \le n,是我们在n维空间沿第r维进行一次分割。

节点的左枝和右枝分别都是kd树,并且满足:如果y是左枝的一个特征坐标,那么y_r \le x_r,并且如果z是右枝的一个特征坐标,那么z_r \ge x_r

给定一个数据样本集S \subseteq R^n和切分轴r,以下递归算法将构建一个以S为数据集的kd树,每一次循环制作一个节点:

——如果|S|=1,记录S中唯一的数据为当前节点的特征数据(特征坐标),并且不设左枝和右枝(|S|是指集合S中元素的数量)。

——如果|S|>1

--将S内所有的点按第r个坐标的大小进行排序 ;

--选出该排序后的中位元素(如果一共有偶数个元素,则选择中位左边或者中位右边的元素,左或右并无影响),作为当前节点的特征坐标,并且记录切分轴r;

--将S_L设为在S中排在中位元素之前的元素;S_R设为在S中所有排列在中位元素后的元素;

--当前节点的左枝设为以S_L为数据集并且r为切分轴制作出的kd树,当前节点的右枝设为以S_R为数据集并且r为切分轴制作出的kd树。再设r\leftarrow(r+1)\ mod\ n(这里,我们想轮流沿着每个维度进行分割;mod\ n是因为一共有n个维度,在沿着最后一个维度进行分割之后再重新回到第一个维度)。





kd 树上的 kNN 算法

给定一个构建于一个样本集的 kd 树,下面的算法可以寻找距离某个点 p 最近的 k 个样本。

零、设 L 为一个有 k 个空位的列表,用于保存已搜寻到的最近点。
一、根据 p 的坐标值和每个节点的切分向下搜索(也就是说,如果树的节点是照 x_r=a 进行切分,并且 p 的 r 坐标小于 a,则向左枝进行搜索;反之则走右枝)。
二、当达到一个底部节点时,将其标记为访问过。如果 L 里不足 k 个点,则将当前节点的特征坐标加入 L ;如果 L 不为空并且当前节点的特征与 p 的距离小于 L 里最长的距离,则用当前特征替换掉 L 中离 p 最远的点。
三、如果当前节点不是整棵树最顶端节点,执行 (a);反之,输出 L,算法完成。
a. 向上爬一个节点。如果当前(向上爬之后的)节点未曾被访问过,将其标记为被访问过,然后执行 (1) 和 (2);如果当前节点被访问过,再次执行 (a)。
1. 如果此时 L 里不足 kk 个点,则将节点特征加入 L;如果 L 中已满 k 个点,且当前节点与 p 的距离小于 L 里最长的距离,则用节点特征替换掉 L 中离最远的点。
2. 计算 p 和当前节点切分线的距离。如果该距离大于等于 L 中距离 p 最远的距离并且 L 中已有 k 个点,则在切分线另一边不会有更近的点,执行 (三);如果该距离小于 L 中最远的距离或者 L 中不足 k 个点,则切分线另一边可能有更近的点,因此在当前节点的另一个枝从 (一) 开始执行。


猜你喜欢

转载自blog.csdn.net/qq_38250162/article/details/80464840