多维检索树KD-Tree

K维检索树类似于二叉检索树,不同的是,它能同时提供多维度属性的检索。K维(从0开始计维数)检索树的定义: K维检索树是一个n层的二叉树(根节点为第0层,依次往下为第1,2..n-1层),对于树中第n层的每个节点,其左子树所有节点的第n%k维属性小于或等于该节点的第n%k维属性;其右子树所有节点的第n%k维属性都大于或等于该节点的第n%k维属性。通俗的讲,就是将整个树的层数循环标记0k-1,在第0层比较第0为属性,在第1层比较第1层属性,依此类推。

 

假设A-G代表二维空间的点(x,y二维坐标标示),则依次插入A-G节点到树中会构成如下所示的树。


 

 

插入A

树为空,A作为根节点

插入B

A比较第0维属性,进入左子树,左子树为空,直接插入

插入C

A比较第0维属性,进入右子树,右子树为空,直接插入

插入D

A比较第0维属性,进入左子树,与B比较第1维属性,进入左子树

插入E

A比较第0维属性,进入左子树,与B比较第1维属性,进入右子树

插入F

A比较第0维属性,进入右子树,与C比较第1维属性,进入右子树

插入G

A比较第0维属性,进入左子树,与B比较第1维属性,进入左子树,D比较第0维属性,进入左子树

 

算法时间复杂度:

查找:从根节点逐层比较,直到遇到目标或者子树为空,时间复杂度为O(logN)

插入:从根节点逐层比较,按照定义的规则直到遇到叶子节点,时间复杂度为O(logN)

删除:对于叶子节点,或只有单分支子树的节点,直接删除,否则找到右子树的最左节点或左子树的最右节点,替换掉被删节点,算法复杂度O(logN)

优化:将树优化为平衡树,将树的节点导出至vector中,并清空树,将vector集合按第一维属性,分成两堆,左边比中间元素小,右边比中间元素大(nth-element),将中间元素插入到树中,递归将左右两堆的元素插入到左子树、右子树(比较时根据层数比较对应的维度值)。优化的时间复杂度为ONlogN)。

区间查找:从根节点起,检查根节点是否符合条件,如果符合加入至结果集中;如果左子树跟目标区间有交集,递归查找左子树;如果右子树跟目标区间有交集,查找右子树。(设定一个动态区间,初始时与目标区间相同,进入左子树,则要更新动态区间对应维度的上限;若进入右子树,则要更新动态区间对应维度的上限;通过判断动态和目标区间是否有交集可以看出需要进入左右子树,从而减少查找空间)。

 

更详细的了解参考论文:Multidimensional Binary Search Trees Used for Associative Searching

 

libkdtree++是一个C++实现的kdtree lib,提供了inserteraseoptimisefind_exact

find_within_rangefind_nearest等接口。

find_with_range(val, range, OutputIterator)不能满足需求,因只能指定每维属性在

val[k] – rangeval[k] + range的范围内。因为需要支持任意区间查找,而kdtree++没有提供

需要的接口,我在kdtree的实现中增加了find_within_range(vmin, vmax, OutputIterator)接口,

同时需要给Region添加一个构造函数。

 

 

 

posted @ 2013-04-19 14:12  ydzhang  阅读(670)  评论(0编辑  收藏  举报