kd树(k-dimensional树的简称),是一种分割k维数据空间的数据结构,主要应用于多维空间关键数据的近邻查找(Nearest Neighbor)和近似最近邻查找(Approximate Nearest Neighbor)。node
其实KDTree就是二叉查找树(Binary Search Tree,BST)的变种。二叉查找树的性质以下:
1)若它的左子树不为空,则左子树上全部结点的值均小于它的根结点的值;
2)若它的右子树不为空,则右子树上全部结点的值均大于它的根结点的值;
3)它的左、右子树也分别为二叉排序树;
例如:
算法
若是咱们要处理的对象集合是一个K维空间中的数据集,咱们首先须要肯定是:怎样将一个K维数据划分到左子树或右子树?数组
在构造1维BST树相似,只不过对于Kd树,在当前节点的比较并非经过对K维数据进行总体的比较,而是选择某一个维度d,而后比较两个K维数据在该维度 d上的大小关系,即每次选择一个维度d来对K维数据进行划分,至关于用一个垂直于该维度d的超平面将K维数据空间一分为二,平面一边的全部K维数据 在d维度上的值小于平面另外一边的全部K维数据对应维度上的值。也就是说,咱们每选择一个维度进行如上的划分,就会将K维数据空间划分为两个部分,若是我 们继续分别对这两个子K维空间进行如上的划分,又会获得新的子空间,对新的子空间又继续划分,重复以上过程直到每一个子空间都不能再划分为止。以上就是构造 Kd-Tree的过程,上述过程当中涉及到两个重要的问题:数据结构
一、在哪一个维度上进行划分?
一种选取轴点的策略是median of the most spread dimension pivoting strategy,统计样本在每一个维度上的数据方差,挑选出对应方差最大值的那个维度。数据方差大说明沿该坐标轴方向上数据点分散的比较开。这个方向上,进行数据分割能够得到最好的平衡。
二、怎样确保创建的树尽可能地平衡?
给定一个数组,怎样才能获得两个子数组,这两个数组包含的元素 个数差很少且其中一个子数组中的元素值都小于另外一个子数组呢?方法很简单,找到数组中的中值(即中位数,median),而后将数组中全部元素与中值进行 比较,就能够获得上述两个子数组。一样,在维度d上进行划分时,划分点(pivot)就选择该维度d上全部数据的中值,这样获得的两个子集合数据个数就基本相同了。3d
1)、在K维数据集合中选择具备最大方差的维度k,而后在该维度上选择中值m为pivot对该数据集合进行划分,获得两个子集合;同时建立一个树结点node,用于存储;
2)、对两个子集合重复(1)步骤的过程,直至全部子集合都不能再划分为止;rest
举个例子:
假设有6个二维数据点{(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)},数据点位于二维空间内(以下图中黑点所示)。kd树算法就是要肯定图1中这些分割空间的分割线(多维空间即为分割平面,通常为超平面)。下面就要经过一步步展现kd树是如何肯定这些分割线的。
对象
例1:查找点Q(2.1,3.1)
以下图所示,红色的点即为要查找的点。经过图4二叉搜索,顺着搜索路径很快就能找到当前的最邻近点(2,3)。
在上述搜索过程当中,产生的搜索路径节点有<(7,2),(5,4),(2,3)>。为了找到真正的最近邻,还须要进行'回溯'操做,首先以(2,3)做为当前最近邻点nearest,计算其到查询点Q(2.1,3.1)的距离dis为0.1414,而后回溯到其父节点(5,4),并判断在该父节点的其余子节点空间中是否有距离查询点Q更近的数据点。以(2.1,3.1)为圆心,以0.1414为半径画圆,如图6所示。发现该圆并不和超平面y = 4交割,即这里:|Q(k) - m|=|3.1 - 4|=0.9 > 0.1414,所以不用进入(5,4)节点右子空间中去搜索。
再回溯到(7,2),以(2.1,3.1)为圆心,以0.1414为半径的圆更不会与x = 7超平面交割,所以不用进入(7,2)右子空间进行查找。至此,搜索路径中的节点已经所有回溯完,结束整个搜索,返回最近邻点(2,3),最近距离为0.1414。blog
例2:查找点Q(2,4.5)
以下图所示,一样通过图4的二叉搜索,可得当前的最邻近点(4,7),产生的搜索路径节点有<(7,2),(5,4),(4,7)>。首先以(4,7)做为当前最近邻点nearest,计算其到查询点Q(2,4.5)的距离dis为3.202,而后回溯到其父节点(5,4),并判断在该父节点的其余子节点空间中是否有距离查询点Q更近的数据点。以(2,4.5)为圆心,觉得3.202为半径画圆,如图7所示。发现该圆和超平面y = 4交割,即这里:|Q(k) - m|=|4.5 - 4|=0.5 < 3.202,所以进入(5,4)节点右子空间中去搜索。因此,将(2,3)加入到搜索路径中,如今搜索路径节点有<(7,2), (2, 3)>。同时,注意:点Q(2,4.5)与父节点(5,4)的距离也要考虑,因为这两点间的距离3.04 < 3.202,因此将(5,4)赋给nearest,而且dist=3.04。
接下来,回溯至(2,3)叶子节点,点Q(2,4.5)和(2,3)的距离为1.5,比距离(5,4)要近,因此最近邻点nearest更新为(2,3),最近距离dis更新为1.5。回溯至(7,2),如图8所示,以(2,4.5)为圆心1.5为半径做圆,并不和x = 7分割超平面交割,即这里:|Q(k) - m|=|2 - 7|=5 > 1.5。至此,搜索路径回溯完。返回最近邻点(2,3),最近距离1.5。
排序
Kd树在维度较小时(好比20、30),算法的查找效率很高,然而当数据维度增大(例如:K≥100),查找效率会随着维度的增长而迅速降低。假设数据集的维数为D,通常来讲要求数据的规模N知足N>>2的D次方,才能达到高效的搜索。递归
为了可以让Kd树知足对高维数据的索引,Jeffrey S. Beis和David G. Lowe提出了一种改进算法——Kd-tree with BBF(Best Bin First),该算法可以实现近似K近邻的快速搜索,在保证必定查找精度的前提下使得查找速度较快。