KD tree

本文深入解析Kd-Tree数据结构,一种源于二叉查找树的高维索引树,广泛应用于图像检索和识别的高维特征向量查找。文章详细介绍了Kd-Tree的构造原理、与传统二叉树的区别,以及如何通过Kd-Tree实现高效近邻查找算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在处理点云数据时,由于数据量比较大,search操作往往非常耗时。因此引入kd-tree。

1.定义

Kd-Tree是从BST(Binary search tree)发展而来,是一种高维索引树形数据结构,常用于大规模高维数据密集的查找比对的使用场景中,主要是最近邻查找(Nearest Neighbor)以及近似最近邻查找(Approximate Nearest Neighbor)。在计算机视觉(CV)中主要是图像检索和识别中的高维特征向量的查找和比对。

在介绍Kd-Tree之前,首先介绍下它的父系结构——BST。二叉查找树,是一种具有如下性质的二叉树:

  • 若它的左子树不为空,则它的左子树节点上的值皆小于它的根节点。
  • 若它的右子树不为空,则它的右子树节点上的值皆大于它的根节点。
  • 它的左右子树也分别是二叉查找树

如果是一维数据,我们可以用二叉查找树来进行存储,但是如果是多维的数据,用传统的二叉查找树就不能够满足我们的要求了,因此后来才发展出了满足多维数据的Kd-Tree数据结构。

2.构造Kd-tree

看第一层,比较位是第一位,也就是3,(2,3,7)中2>3,所以像左生长,(4,3,4)中4>3所以向右生长。到了第二层,这里只看(2,3,7),他的比较位是y也就是3了,那么(2,1,3)中1<3所以像左生长,(2,,4,5)中4>3所以想向右生长。

                                     

3.Kd-Tree与一维二叉查找树之间的差别:

二叉查找树:数据存放在树中的每一个结点(根结点、中间结点、叶子结点)中;

Kd-Tree:数据仅仅存放在叶子结点,而根结点和中间结点存放一些空间划分信息(比如划分维度、划分值);

4.利用Kd-Tree的近邻查找算法 

(1)将查询数据Q从根结点開始,依照Q与各个结点的比較结果向下訪问Kd-Tree,直至达到叶子结点。

当中Q与结点的比較指的是将Q相应于结点中的k维度上的值与m进行比較,若Q(k) < m,则訪问左子树。否则訪问右子树。达到叶子结点时,计算Q与叶子结点上保存的数据之间的距离。记录下最小距离相应的数据点。记为当前“近期邻点”Pcur和最小距离Dcur。

(2)进行回溯(Backtracking)操作,该操作是为了找到离Q更近的“近期邻点”。

即推断未被訪问过的分支里是否还有离Q更近的点。它们之间的距离小于Dcur。

假设Q与其父结点下的未被訪问过的分支之间的距离小于Dcur,则觉得该分支中存在离P更近的数据,进入该结点,进行(1)步骤一样的查找过程,假设找到更近的数据点,则更新为当前的“近期邻点”Pcur,并更新Dcur。

假设Q与其父结点下的未被訪问过的分支之间的距离大于Dcur,则说明该分支内不存在与Q更近的点。

回溯的推断过程是从下往上进行的,直到回溯到根结点时已经不存在与P更近的分支为止。

5.C++实现

基于github上的一个项目进行实现的,需要依赖opencv库,能处理二维和三维的数据。https://github.com/gentlemanman/OpenCV_Algorithm

 

参考:

https://www.cnblogs.com/zfyouxi/p/4795584.html

https://blog.youkuaiyun.com/u011021773/article/details/78311565

### KDTree 数据结构实现及应用 #### 什么是KDTreeKDTree(K-Dimensional Tree,K维)是一种用于多维空间中数据点的快速点查找的数据结构。它属于计算几何领域中的二叉结构[^1]。 #### KDTree的优点 - **搜索效率高**:通过分割空间的方式减少不必要的比较操作。 - **自平衡特性**:即使在动态插入和删除的情况下,仍然能够维持较高的性能。 - **易于实现**:相较于其他复杂的多维索引结构,其算法逻辑较为简单[^2]。 #### KDTree的核心原理 KDTree基于二叉搜索的思想构建,在每次分裂时选择一个维度作为当前层的划分依据,并将该维度上的中间值设为节点,从而形成左子和右子。这种分治策略使得后续查询可以迅速定位目标区域而无需遍历整个数据集[^4]。 #### Python实现示例 以下是利用Python实现的一个简单的KDTree构造过程: ```python import random class Node: def __init__(self, point=None, axis=None): self.point = point self.axis = axis self.left_child = None self.right_child = None def kdtree(points, depth=0): n = len(points) if n == 0: return None # 当前轴由深度决定 (假设二维情况) axis = depth % 2 # 对当前轴进行排序并取中位数 sorted_points = sorted(points, key=lambda point: point[axis]) median_index = n // 2 median_point = sorted_points[median_index] node = Node(median_point, axis) # 构建左右子 node.left_child = kdtree(sorted_points[:median_index], depth + 1) node.right_child = kdtree(sorted_points[median_index + 1:], depth + 1) return node if __name__ == "__main__": points = [(random.randint(0, 10), random.randint(0, 10)) for _ in range(7)] root = kdtree(points) ``` 上述代码展示了如何创建一棵基本的KDTree。其中`kdtree()`函数递归地按照不同维度对输入点集合进行拆分直到叶子节点为止。 #### 应用场景 - **范围搜索**:给定一个多边形或者矩形边界,寻找落在这个区域内所有的点。 - **最近邻搜索**:找到离某个特定位置最近的那个样本点。 - **碰撞检测**:应用于游戏开发等领域来判断物体之间是否存在接触可能性。 - **地理信息系统(GIS)**:比如在外卖平台里用来管理各个餐馆的位置信息以便用户能方便快捷地获取附近可选店铺列表等服务功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值