k-d tree算法

k-d树(k-dimensional树的简称),是一种分割k维数据空间的数据结构。主要应用于多维空间关键数据的搜索(如:范围搜索和最近邻搜索)。


应用背景
  • SIFT算法中做特征点匹配的时候就会利用到k-d树。而特征点匹配实际上就是一个通过距离函数在高维矢量之间进行相似性检索的问题。针对如何快速而准确地找到查询点的近邻,现在提出了很多高维空间索引结构和近似查询的算法,k-d树就是其中一种。
  • 索引结构中相似性查询有两种基本的方式:一种是范围查询(range searches),另一种是K近邻查询(K-neighbor searches)。范围查询就是给定查询点和查询距离的阈值,从数据集中找出所有与查询点距离小于阈值的数据;K近邻查询是给定查询点及正整数K,从数据集中找到距离查询点最近的K个数据,当K=1时,就是最近邻查询(nearest neighbor searches)。
  • 特征匹配算子大致可以分为两类。一类是线性扫描法,即将数据集中的点与查询点逐一进行距离比较,也就是穷举,缺点很明显,就是没有利用数据集本身蕴含的任何结构信息,搜索效率较低,第二类是建立数据索引,然后再进行快速匹配。因为实际数据一般都会呈现出簇状的聚类形态,通过设计有效的索引结构可以大大加快检索的速度。索引树属于第二类,其基本思想就是对搜索空间进行层次划分。根据划分的空间是否有混叠可以分为Clipping和Overlapping两种。前者划分空间没有重叠,其代表就是k-d树;后者划分空间相互有交叠,其代表为R树。(这里只介绍k-d树)

k-d树算法

  • k-d树算法可以分为两大部分,一部分是有关k-d树本身这种数据结构建立的算法,另一部分是在建立的k-d树上如何进行最邻近查找的算法。

k-d树中每个节点的数据类型

域名 数据类型 描述
Node-data 数据矢量 数据集中某个数据点,是n维矢量(这里也就是k维)
Range 空间矢量 该节点所代表的空间范围
split 整数 垂直于分割超平面的方向轴序号
Left k-d树 由位于该节点分割超平面左子空间内所有数据点所构成的k-d树
Right k-d树 由位于该节点分割超平面右子空间内所有数据点所构成的k-d树
parent k-d树 父节点

构建k-d树的伪码

算法:构建k-d树(createKDTree)
输入:数据点集Data-set和其所在的空间Range
输出:Kd,类型为k-d tree
1.If Data-set为空,则返回空的k-d tree

2.调用节点生成程序:

  (1)确定split域:对于所有描述子数据(特征矢量),统计它们在每个维上的数据方差。以SURF特征为例,描述子为64维,可计算64个方差。挑选出最大值,对应的维就是split域的值。数据方差大表明沿该坐标轴方向上的数据分散得比较开,在这个方向上进行数据分割有较好的分辨率;

  (2)确定Node-data域:数据点集Data-set按其第split域的值排序。位于正中间的那个数据点被选为Node-data。此时新的Data-set' = Data-set\Node-data(除去其中Node-data这一点)。

3.dataleft = {d属于Data-set' && d[split] ≤ Node-data[split]}

   Left_Range = {Range && dataleft}

   dataright = {d属于Data-set' && d[split] > Node-data[split]}

   Right_Range = {Range && dataright}

4.left = 由(dataleft,Left_Range)建立的k-d tree,即递归调用createKDTree(dataleft,Left_

   Range。并设置left的parent域为Kd;

   right = 由(dataright,Right_Range)建立的k-d tree,即调用createKDTree(dataleft,Left_

   Range)。并设置right的parent域为Kd

标准k-d树查询算法

算法:k-d树最邻近查找

输入:Kd,    //k-d tree类型

     target  //查询数据点

输出:nearest, //最邻近数据点

     dist      //最邻近数据点和查询点间的距离

1. If Kd为NULL,则设dist为infinite并返回

2. //进行二叉查找,生成搜索路径

   Kd_point = &Kd;                   //Kd-point中保存k-d tree根节点地址

   nearest = Kd_point -> Node-data;  //初始化最近邻点

   while(Kd_point)

     push(Kd_point)到search_path中; //search_path是一个堆栈结构,存储着搜索路径节点指针

 /*** If Dist(nearest,target) > Dist(Kd_point -> Node-data,target)

       nearest  = Kd_point -> Node-data;    //更新最近邻点

       Max_dist = Dist(Kd_point,target);  //更新最近邻点与查询点间的距离  ***/

     s = Kd_point -> split;                       //确定待分割的方向

     If target[s] <= Kd_point -> Node-data[s]     //进行二叉查找

       Kd_point = Kd_point -> left;

     else

       Kd_point = Kd_point ->right;

   nearest = search_path中最后一个叶子节点; //注意:二叉搜索时不比计算选择搜索路径中的最邻近点,这部分已被注释

   Max_dist = Dist(nearest,target);    //直接取最后叶子节点作为回溯前的初始最近邻点

3. //回溯查找

   while(search_path != NULL)

     back_point = 从search_path取出一个节点指针;   //从search_path堆栈弹栈

     s = back_point -> split;                   //确定分割方向

     If Dist(target[s],back_point -> Node-data[s]) < Max_dist   //判断还需进入的子空间

       If target[s] <= back_point -> Node-data[s]

         Kd_point = back_point -> right;  //如果target位于左子空间,就应进入右子空间

       else

         Kd_point = back_point -> left;    //如果target位于右子空间,就应进入左子空间

       将Kd_point压入search_path堆栈;

     If Dist(nearest,target) > Dist(Kd_Point -> Node-data,target)

       nearest  = Kd_point -> Node-data;                 //更新最近邻点

       Min_dist = Dist(Kd_point -> Node-data,target);  //更新最近邻点与查询点间的距离

转自:http://www.cnblogs.com/eyeszjwang/articles/2429382.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
K-D Tree(K-Dimensional Tree算法是一种基于分治法的数据结构,用于高维空间的搜索和排序。它的基本思想是将多维空间中的点以某种方式分割成更小的子空间,然后在每个子空间中递归地进行搜索。这样可以大大降低搜索的复杂度。 具体来说,K-D Tree算法可以分为以下几步: 1. 选择一个维度,将数据点按照该维度的值进行排序。 2. 找到该维度的中位数,将其作为当前节点,并将数据点分为左右个子集。 3. 递归地构建左子和右子,每次选择一个新的维度进行划分。 4. 最终得到一个K-D Tree。 在搜索时,我们可以从根节点开始,按照一定的规则向下遍历,直到找到目标点或者无法继续向下搜索。具体的规则是: 1. 如果目标点在当前节点的左子中,则继续向左子搜索。 2. 如果目标点在当前节点的右子中,则继续向右子搜索。 3. 如果目标点和当前节点在选定的维度上的值相等,则说明已经找到目标点。 分治法是一种常见的算法思想,它将一个大规模的问题分解成若干个小规模的子问题,每个子问题独立地求解,然后将这些子问题的解合并起来得到原问题的解。分治法通常包含三个步骤:分解、求解、合并。 具体来说,分治法可以分为以下几步: 1. 分解:将原问题分成若干个子问题,每个子问题规模较小且结构与原问题相同。 2. 求解:递归地求解每个子问题,直到问题规模足够小可以直接求解。 3. 合并:将所有子问题的解合并成原问题的解。 分治法的优点是可以有效地降低算法的时间复杂度。但是它的缺点是需要额外的空间来存储子问题的解,而且分解和合并的过程也需要耗费一定的时间。因此,需要根据实际情况选择合适的算法
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值