9. k_d tree原理及python代码实现

      k_d tree其实就是多维二叉树(空间二叉树的一种特殊情况), 里面储存着k维的点的信息,是对k维空间进行划分的一种数据结构。本文看了博客KD-Tree详解: 从原理到编程实现_kdtree ts实现-CSDN博客,这篇博客写的很详细,只是这里对这篇博客进行了扩展。

        在点云操作中,常常需要从大量点云中找到距离输入点最近的点,如果使用线性搜索,逐个判断与输入点的距离,那么搜寻耗时将会与点云规模呈线性上升趋势,时间复杂度为O ( N ) O(N)O(N)。显然这不是我们想看到的,在数据结构与算法中,对一维数据常用的搜索方法是二分查找时间复杂度为O(logN),它本质上是构建一棵二叉搜索树,以空间换取时间。而KD-Tree(K-Dimension Tree),也就做K维树,则可以看做是二叉树在K维空间的扩展,它的搜索效率也能近似达到O(logN)。

1.k_d tree要解决的问题

假如有有如下的7个一维数据:

        假如我们要在X中找与2.5距离小于3.2的所有元素。那么我们可以用常规的思路解决这个问题。比如:

(1)对X中每个元素与2.5求距离,将所有距离小于3.2的元素提取出来,从而就解决了上面的问题;

(2)我们首先排序,比如进行升序排序,再用二分查找找到离2.5距离最近的元素,再从这个元素两边分别遍历,直到遇到与2.5距离大于等于3.2的元素则遍历终止。

        显然,方法(1)只需要每个元素与2.5做两次计算即可(一次差值计算,一次与3.2的大小比较计算),即需要计算14次即可解决问题;方法(2)首先做一次排序,然后用二分查找找到离2.5最近的元素,再遍历距离小于3.2的元素即可(不是遍历所有元素)。如果7个数没有区别,假如有几万个数据或者几十万个数据呢,方法(2)的优势就很明显了。

        k_d tree其实就是运用二分查找法的原理构造数据结构,以方便查找近邻数据、查找限定条件的数据等,数据量越大,这个数据结构的优势越明显,经常用于比近邻算法、DBSCAN算法等,尤其是点云数据的处理中。

2.一维数据的k_d tree构造

       我们再以上面的数据为例构造一个一维数据的二叉树。假设有如下的7个一维数据:

        得到的二叉树结构如下:

观察这个树结构很容易发现它的规律,它的构造步骤如下:

(1)将以上数据排序,如升序排序后:X = [1, 2, 3, 4, 5, 6, 7];

(2) 然后取X的最中间的值作为二叉树最顶端的值(如上图最顶端的值为4);

(3)其实步骤(2)将X分为左半部分 [1, 2, 3] 和右半部分 [5, 6, 7] ,再将这两个列表分别做步骤二的处理,得到两个数列最中间的值分别是2和6,分别放在4下面的左边和右边,就得到如下图:

(4)经过步骤(3)后,列表[1, 2, 3]又被分为[1]和[3]两部分,数列[5, 6, 7] 又被分为[5]和[7]两部分,对两部分重复上面的步骤即可得到下图:

在这里,对于一维数据的二叉树的构造就说完了,那么,假如我们构造一个如下列表的二叉树呢

X = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]

结果如下:

        通过这两个例子大家能找到规律了吧,这个结构的每个节点的离它距离较近的点都在它的附件节点上。

python代码如下:

class Node:
    def __init__(self, value, left, right):
        self.value = value
        self.left = left
        self.right = right

def make_tree(data):
    if len(data)==0:
        return None
    mid = len(data) // 2  # 取出中点
    data.sort()  # 按照升序排列
    node = Node(
        data[mid],
        make_tree(data[0:mid - 1]),   # 左子树
        make_tree(data[mid + 1: len(data)])   # 右子树
    )
    return node

if __name__ == '__main__':

    data = [3, 6, 5, 2, 4, 1, 7]
    node = make_tree(data)
    print(node.value)

运行结果如下:

也可以打印子树如下:

print(node.right.right.value)

运行结果如下:

2.二维数据的k_d tree构造

       假设有如下由七个二维数据组成的二维数据集:

      与一维数据类似,先进行排序,然后交叉进行构造数据结构如下:

python代码如下:

from operator import itemgetter

class Node:
    def __init__(self, value, left, right):
        self.value = value
        self.left = left
        self.right = right

def kd_tree(points, depth):
    if 0 == len(points):
        return None
    cutting_dim = depth % len(points[0])
    medium_index = len(points) // 2
    points.sort(key=itemgetter(cutting_dim))
    node = Node(points[medium_index],
                kd_tree(points[:medium_index], depth + 1),
                kd_tree(points[medium_index + 1:], depth + 1)
                )

    return node


if __name__ == '__main__':

    points = [(3, 7), (2, 6), (0, 5), (1, 8), (7, 5), (5, 4), (6, 7)]
    depth = 2
    node = kd_tree(points, depth)
    print(node.value)
    print(node.left.value)
    print(node.right.left.value)

        运行结果如下:

  • 14
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值