点云处理---二叉树

二叉树

对于一维数据,可以使用二叉树进行存储以及查找。
1.二叉树特点:
小放左边
大放右边
子树仍然满足二叉树特点
2.关键问题:
搜索过程中怎么跳过不必要的搜索空间?
利用worst distace存储当前搜索的最大距离,只对那些和worst distance距离相交的区域进行搜索。
怎么停止搜索?
只需要对完整包含了worst distance的分割空间进行搜索,搜索完该空间就可以停止搜索。
3.二叉树时间复杂度、空间复杂度
时间复杂度为:O(logn),最坏O(n)
4.二叉树构建

'''
二叉树插入
input:
  key: 键值
  value: 在原数组中的位置

output:
  root: 插入之后的二叉树
'''
def insert(root, key, value=-1):
  # root为空,则建立节点
    if root == None:
        root = Node(key, value)
    else:
        # root不为空,且当前插入的节点值小于当前节点值,插入左子树
        if key < root.key:
            root.left = insert(root.left, key, value)
        # 插入右子树
        elif key > root.key:
            root.right = insert(root.right, key, value)
        # 相同则跳过
        else:
            pass
    return root

5.二叉树的KNN查找
在搜索过程当中,最坏距离开始设置为无穷大值,在搜索过程中,不断的缩小最坏距离,小于最坏距离的区域就不再需要进行查找。关键就在与怎么确定最坏距离:使用一个result_set容器进行存储最坏距离的存储。最坏距离存储在容器中最后一个位置,每一次插入点之后都进行更新。
在这里插入图片描述

class DistIndex:
    def __init__(self, distance, index):
        self.distance = distance
        self.index = index
# 富比较方法,可以实现对复杂类的比较

    def __lt__(self, other):
        return self.distance < other.distance


class KNNResultsets:
    def __init__(self, capacity):
        # 容量设定k
        self.capacity = capacity
        # 已经搜索到的点数count
        self.count = 0
        # 已经搜索到的点的最远距离
        self.worst_dist = 1e10
        # 存储点的距离列表
        self.dist_index_list = []
        # 对k个近邻点的距离都进行初始化,先初始化成最大值
        for i in range(capacity):
            self.dist_index_list.append(DistIndex(self.worst_dist, 0))
        self.comparision = 0

    def size(self):
        return self.count

    def full(self):
        return self.count == self.capacity

    def worst_Dist(self):
        return self.worst_dist

    def add_point(self, dist, index):
        # 设定容器大小为k,注意初始时刻容器中的距离都为最大值
        # 当前点距离和容器中的点的距离进行比较,每次都把当前点插入到对应的位置
        self.comparision += 1
        # 当前点距离大于最坏距离,说明这个点不需要进行搜索
        if dist > self.worst_dist:
            return
        # 点数小于k,就加入
        if self.count < self.capacity:
            self.count += 1
        # 调整新加入的元素的位置
        i = self.count-1  # index
        while(i > 0):
            if self.dist_index_list[i-1].distance > dist:
                # 挪出一个空格出来
                self.dist_index_list[i] = copy.deepcopy(
                    self.dist_index_list[i-1])
                i -= 1
            else:
                break
        # 插入新元素,更新最坏距离
        self.dist_index_list[i].distance = dist
        self.dist_index_list[i].index = index
        **#最后一个位置是最坏距离**
        self.worst_dist = self.dist_index_list[self.capacity-1].distance

    def __str__(self):
        output = ''
        for i, dist_index in enumerate(self.dist_index_list):
            output += '%d--%.2f\n' % (dist_index.index, dist_index.distance)
        output += 'in total %d iteration' % self.comparision
        return output

KNN_search

def knn_search(root: Node, result_set: KNNResultsets, key):
    if root == None:
        return False
    # 先把root加入到查找结果中
    result_set.add_point(math.fabs(root.key-key), root.value)
    # 如果二叉树中刚好有k个和key相等的节点,此时最坏距离为0,可以提前终止
    if result_set.worst_dist == 0:
        return True
    # root.key>key,先从root的左边开始
    if root.key >= key:
        if knn_search(root.left, result_set, key):
            return True
        # 左边没有找够,去右边找或者说右边的最坏距离小于遍历完左边之后的最坏距离
        elif math.fabs(root.key-key) < result_set.worst_Dist():
            return knn_search(root.right, result_set, key)
        return False
    else:
        if knn_search(root.right, result_set, key):
            return True
        # 右边没有找够,去左边找
        elif math.fabs(root.key-key) < result_set.worst_Dist():
            return knn_search(root.left, result_set, key)
        return False

6.二叉树radius查找

radius查找不同之处在于最坏距离是固定的。

class RadiusNNResultSet:
    def __init__(self, radius):
        self.radius = radius
        self.count = 0
        self.comparision = 0
        self.worst_dist = radius
        self.dist_index_list = []

    def size(self):
        return self.count

    def worst_Dist(self):
        return self.worst_dist

    def add_point(self, dist, index):
        self.comparision += 1
        if dist > self.worst_dist:
            return
        # 将点加入到集合中
        self.count += 1
        self.dist_index_list.append(DistIndex(dist, index))

    def __str__(self):
        self.dist_index_list.sort()
        output = ''
        for i, dist_index in enumerate(self.dist_index_list):
            output += '%d - %.2f\n' % (dist_index.index, dist_index.distance)
        output += 'In total %d neighbors within %f.\nThere are %d comparison operations.' \
                  % (self.count, self.radius, self.comparision)
        return output

radius查找:

def radius_search(root: Node, result_set: RadiusNNResultSet, key):
    if root == None:
        return False
    result_set.add_point(math.fabs(root.key-key), root.value)
    if root.key >= key:
        if radius_search(root.left, result_set, key):
            return True
        elif math.fabs(root.key-key) < result_set.worst_Dist():
            return radius_search(root.right, result_set, key)
        return False
    else:
        if radius_search(root.right, result_set, key):
            return True
        elif math.fabs(root.key-key) < result_set.worst_Dist():
            return radius_search(root.left, result_set, key)
        return False

main函数调用

def main():
    # generate data
    data_size = 10
    # 随机排列生成一个列表元素
    data = np.random.permutation(data_size).tolist()
    root = None
    for value, key in enumerate(data):
        root = insert(root, key, value)

    inordef(root)
    root1 = copy.deepcopy(root)
    res1 = search_iteration(root, 3)
    res2 = search_recursion(root, 3)
    print('itera search idx is:', res1.value,
          'and the recursion search idx is', res2.value)

    search_key = 2
    resset = KNNResultsets(capacity=4)
    knn_search(root1, resset, search_key)
    print(resset)

    resset_radius = RadiusNNResultSet(2)
    radius_search(root1, resset_radius, 5)
    print(resset_radius)


if __name__ == '__main__':
    main()

numpy相关函数记录:

data=np.random.permutation(data_size).tolist()
#随机排列一个数组,data_size是一个数字的话就是排列range(data_size)
#tolist是将数组转换成列表
for value,key in enumerate(data):
#enumerate:迭代可迭代的对象:包括列表、字符串、字典等
#可以返回键值以及相应的元素内容

point_indices_mid=math.ceil()
#向上取整
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值