python实现的简化版构建Kdtree(k=2)

news2024/11/16 8:50:40

Python Kdtree 使用示例

文章目录

    • Python Kdtree 使用示例
      • 一、关于 KDTree
      • 二、关于最近邻搜索
      • 三、复杂度分析
      • 四、python实现的简化版构建k-d tree(k=2)

一、关于 KDTree

  • 点云数据主要是, 表征 目标表面 的海量点集合, 并不具备传统实体网格数据的几何拓扑结构。
  • 点云数据处理中最为核心的问题就是, 建立离散点间的拓扑关系, 实现基于邻域关系的快速查找。
  • KDTree,即k-dimensional tree,是一种高维索引树形数据结构,常用于在大规模的高维数据空间进行最近邻查找(Nearest Neighbor)和近似最近邻查找(Approximate Nearest Neighbor),例如图像检索和识别中的高维图像特征向量的K近邻查找与匹配。
  • KDTree的每一级(level)在指定维度上分开所有的子节点。在树的根部,所有的子节点在第一个维度上被分开(第一维坐标小于根节点的点将被分在左边的子树中,大于根节点的点将被分在右边的子树中)。树的每一级都在下一个维度上分开,所有其他的维度用完之后就回到第一个维度,直到你准备分类的最后一个树仅仅由有一个元素组成

在这里插入图片描述

二、关于最近邻搜索

给定点p,查询数据集中与其距离最近点的过程即为最近邻搜索。
在这里插入图片描述

在这里插入图片描述

如在构建好的k-d tree上搜索(3,5)的最近邻时:

(1)首先从根节点(7,2)出发,将当前最近邻设为(7,2),对该k-d tree作深度优先遍历。以(3,5)为圆心,其到(7,2)的距离为半径画圆(多维空间为超球面),可以看出(8,1)右侧的区域与该圆不相交,所以(8,1)的右子树全部忽略。

(2) 接着走到(7,2)左子树根节点(5,4),与原最近邻对比距离后,更新当前最近邻为(5,4)。以(3,5)为圆心,其到(5,4)的距离为半径画圆,发现(7,2)右侧的区域与该圆不相交,忽略该侧所有节点,这样(7,2)的整个右子树被标记为已忽略。

(3) 遍历完(5,4)的左右叶子节点,发现与当前最优距离相等,不更新最近邻。所以(3,5)的最近邻为(5,4)。

三、复杂度分析

  • 新增节点:平均复杂度为O(logn),最坏复杂度O(n);
  • 删除节点:平均复杂度为O(logn),最坏复杂度O(n);
  • 最近邻搜索: 平均复杂度为O(logn) ,最坏复杂度O(n);

四、python实现的简化版构建k-d tree(k=2)

# -*- coding:utf-8 -*-

import numpy as np


class KdNode:
    """kd tree中的一个点,属性包括
    x:这个点的x值
    y:这个点的y值
    level:第几级树
    right:右节点
    left:左节点"""
    def __init__(self, x, y, level):
        self.x = x
        self.y = y
        self.level = level
        self.right = None
        self.left = None


class KdTree:
    def __init__(self):
        self._node = None
        # 初始化一个节点为None

    def insert(self, x, y):
        if self._node is None:
            self.add(x, y, node=self._node, level=1)
            # 添加根节点
        else:
            self.add(x, y, node=self._node, level=2)
            # 其他节点

    def add(self, x, y, node, level):
        if node is None:
            # 如果是添加根节点
            print('所创建的k-d树还未创建根节点,将自动把(%.4f,%.4f)设为根节点' % (x, y))
            self._node = KdNode(x, y, level)

        elif level % 2 == 1:
            if node.y < y:
                if node.right is None:
                    node.right = KdNode(x, y, level)
                else:
                    self.add(x, y, node.right, level + 1)
            elif node.y >= y:
                if node.left is None:
                    node.left = KdNode(x, y, level)
                else:
                    self.add(x, y, node.left, level + 1)

        elif level % 2 == 0:
            if node.x < x:
                # 大的放在右边
                if node.right is None:
                    # 如果右边还没有节点
                    node.right = KdNode(x, y, level)
                else:
                    # 如果右边有节点了,以已经存在了的这个结点为父节点,向下一级划分
                    self.add(x, y, node.right, level + 1)
            elif node.x >= x:
                # 小的或者等的放在左边
                if node.left is None:
                    node.left = KdNode(x, y, level)
                else:
                    self.add(x, y, node.left, level + 1)

    def append_infix(self, node, x, y, level):
        """中序遍历
        若树非空,则依次执行如下操作:
        ⑴遍历左子树;
        ⑵访问根结点;
        ⑶遍历右子树。"""
        if node is None:
            return

        self.append_infix(node.left, x, y, level)
        x.append(node.x)
        y.append(node.y)
        level.append(node.level)
        self.append_infix(node.right, x, y, level)

    def append_pre(self, node, x, y, level):
        """先序遍历
        若二叉树非空,则依次执行如下操作:
        ⑴ 访问根结点;
        ⑵ 遍历左子树;
        ⑶ 遍历右子树。"""
        if node is None:
            return

        x.append(node.x)
        y.append(node.y)
        level.append(node.level)
        self.append_pre(node.left, x, y, level)
        self.append_pre(node.right, x, y, level)

    def append_post(self, node, x, y, level):
        """后序遍历
        若二叉树非空,则依次执行如下操作:
        ⑴遍历左子树;
        ⑵遍历右子树;
        ⑶访问根结点。"""
        if node is None:
            return

        self.append_post(node.left, x, y, level)
        self.append_post(node.right, x, y, level)
        x.append(node.x)
        y.append(node.y)
        level.append(node.level)

    def print_kd_tree(self, traversal):
        x = []
        y = []
        level = []

        if traversal == "infix":
            self.append_infix(self._node, x, y, level)
        elif traversal == "pre":
            self.append_pre(self._node, x, y, level)
        elif traversal == "post":
            self.append_post(self._node, x, y, level)
        else:
            print("Parameter error")

        for each in range(len(x)):
            print("(%.4f, " % x[each] + "%.4f, " % y[each] + "%.d)" % level[each])


if __name__ == "__main__":
    my_kd_tree = KdTree()

    x_list = np.random.uniform(0, 10, 10)
    # 随机生成10个(0, 10)的浮点数
    y_list = np.random.uniform(0, 10, 10)

    for i in range(len(x_list)):
        my_kd_tree.insert(x_list[i], y_list[i])
        # 每来一个新的结点,都是从根节点开始,顺着向下找自己的位置
    my_kd_tree.print_kd_tree("infix")



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1415295.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【云原生】Docker私有仓库搭建以及四大容器重启策略

目录 一、registry私有仓库 步骤一&#xff1a;先拉取registry的镜像 步骤二&#xff1a;修改docker的配置文件重启 步骤三&#xff1a;基于registry镜像启动一个容器&#xff0c;可以设置为always重启策略 步骤四&#xff1a;修改想要上传的镜像的标签并上传验证 步骤五&…

vulnhub靶场之Five86-2

一.环境搭建 1.靶场描述 Five86-2 is another purposely built vulnerable lab with the intent of gaining experience in the world of penetration testing. The ultimate goal of this challenge is to get root and to read the one and only flag. Linux skills and fa…

LVGL移植准备

一.LVGL移植关键&#xff08;框架&#xff09; 显示驱动&#xff1a;实现与目标平台兼容的显示驱动程序&#xff0c;包括初始化显示设备、绘制像素和设置显示区域等功能。确保与LVGL库进行交互的正确性和有效性。 输入设备驱动&#xff1a;适配目标平台的输入设备驱动程序&…

世界渲染大赛多久一届?

世界渲染大赛&#xff0c;又名世界3D渲染挑战赛&#xff0c;是国外艺术家Pwnisher开启的知名赛事&#xff0c;非常受欢迎。在这个比赛中&#xff0c;你可以看到世界各地不同艺术家进行的创意和主题比拼&#xff0c;有极高的欣赏价值和审美标准。 那么这个比赛举办时间是多少呢&…

C#反射详解

一、反射是什么 1、C#编译运行过程 高级语言->编译->dll/exe文件->CLR/JIT->机器码 2、原理解析 metadata&#xff1a;元数据数据清单&#xff0c;记录了dll中包含了哪些东西,是一个描述。 IL&#xff1a;中间语言&#xff0c;编译把高级语言编译后得到的C#中…

JS之隐式转换与布尔判定

大家思考一下 [ ] [ ] &#xff1f; 答案是空字符串 为什么呢&#xff1f; 当做加法运算的时候&#xff0c;发现左右两端存在非原始类型&#xff0c;也就是引用类型对象&#xff0c;就会对对象做隐式类型转换 如何执行的&#xff1f;或者说怎么查找的&#xff1f; 第一步&…

网络安全02--负载均衡下的webshell连接

目录 一、环境准备 1.1ubentu虚拟机一台&#xff0c;docker环境&#xff0c;蚁剑 1.2环境压缩包&#xff08;文件已上传资源&#xff09;&#xff1a; 二、开始复原 2.1上传ubentu&#xff1a; 2.2解压缩 2.3版本20没有docker-compose手动下载&#xff0c;包已上传资源 …

netty源码前置一:Nio

NIO算是实现Reactor设计模式&#xff08;单Selector 单工作线程&#xff09;底层window用的是select&#xff0c;linux用的是epoll 网络NIO代码实现&#xff1a; public NIOServer(int port) throws Exception {selector Selector.open();serverSocket ServerSocketChannel.…

逻辑回归(Logistic Regression)和正则化

1.分类问题 案例&#xff1a; 在分类问题中&#xff0c;我们尝试预测的是结果是否属于某一个类&#xff08;例如正确或错误&#xff09;。分类问题的例子有&#xff1a;判断一封电子邮件是否是垃圾邮件&#xff1b;判断一次金融交易是否是欺诈&#xff1b;之前我们也谈到了肿瘤…

Python网络爬虫实战——实验4:Python爬虫代理的使用

【实验内容】 本实验主要介绍在爬虫采集数据的过程中代理的使用。 【实验目的】 1、掌握代理使用的基本场景&#xff1b; 2、解决IP封锁问题&#xff1b; 3、提高爬虫访问效率&#xff1b; 【实验步骤】 步骤1选择代理服务提供商 步骤2配置爬虫使用代理 步骤3 采集数据生成…

Ubuntu添加AppImage到桌面及应用程序菜单

将AppImage添加到桌面&#xff0c;以PicGo为例 效果&#xff1a; 在桌面创建PicGo.desktop文件&#xff0c;输入以下内容&#xff1a; [Desktop Entry] EncodingUTF-8 TypeApplication #应用名称 NamePicGo #图标路径 Icon/usr/local/AppImage/icons/PicGo.png #启动是否开启…

cmake设置Debug版本和Release版本的输出路径

项目背景&#xff1a;指定可执行文件和动态库输出路径都在bin目录文件夹下&#xff0c;由于项目中存在osg插件&#xff0c;然后我在项目中需要重写osg的插件&#xff0c;这时候就会遇到指定输出路径的问题&#xff0c;由于需要输出到osgPlugins-3.6.5文件夹下&#xff0c;所以使…

嘿嘿,vue之输出土味情话

有点好玩&#xff0c;记录一下。通过按钮调用网站接口&#xff0c;然后解构数据输出土味情话。 lovetalk.vue: <!--vue简单框架--> <template> <!-- 这是一个div容器&#xff0c;用于显示土味情话 --> <div class"talk"> <!-- 当点…

【现代密码学基础】详解完美安全与香农定理

目录 一. 介绍 二. 完美安全的密钥与消息空间 三. 完美安全的密钥长度 四. 最优的完美安全方案 五. 香农定理 &#xff08;1&#xff09;理论分析 &#xff08;2&#xff09;严格的正向证明 &#xff08;3&#xff09;严格的反向证明 六. 小结 一. 介绍 一次一密方案…

正则匹配 | 正则实际应用探索分享

这并不是一篇教正则基础的文章&#xff0c;其正则式不能对您进行使用后的结果负责&#xff0c;请以研究的眼光看待本篇文章。 技术就是懒人为了更好的懒才会想办法搞的东西&#xff0c;我最近因为某些原因需要频繁删除注释 我就想到通过替换的正则功能快速删除文件中的简单注…

Qslog开源库使用

Qslog源码下载地址&#xff1a;https://github.com/victronenergy/QsLog 1.QSLOG使用方式 &#xff08;1&#xff09;源码集成 在你的工程中&#xff0c;直接包含QsLog.pri文件&#xff0c;进行源码集成。当然你也可以包含QsLog.pri后&#xff0c;编译为xx.dll&#xff0c;在…

数据可视化练习

文章目录 试题示例 试题示例 绘制下图所示的表格 根据下表的数据&#xff0c;将班级名称一列作为x轴的刻度标签&#xff0c;将男生和女生两列的数据作为刻度标签对应的数值&#xff0c;使用bar()函数绘制下图所示的柱形图。 方式一 import numpy as np import matplotlib.p…

CUDA编程- - GPU线程的理解 thread,block,grid - 再次学习

GPU线程的理解 thread,block,grid 一、从 cpu 多线程角度理解 gpu 多线程1、cpu 多线程并行加速2、gpu多线程并行加速2.1、cpu 线程与 gpu 线程的理解&#xff08;核函数&#xff09;2.1.1 、第一步&#xff1a;编写核函数2.1.2、第二步&#xff1a;调用核函数&#xff08;使用…

跟着cherno手搓游戏引擎【12】渲染context和首个三角形

渲染上下文&#xff1a; 目的&#xff1a;修改WindowsWindow的结构&#xff0c;把glad抽离出来 WindowsWindow.h:新建m_Context #pragma once #include "YOTO/Window.h" #include <YOTO/Renderer/GraphicsContext.h> #include<GLFW/glfw3.h> #include…

iperf3网络带宽性能测试工具 局域网网络最大带宽高阶教程

iperf3 是一个 TCP, UDP, 和 SCTP (传输层协议)网络带宽测量工具&#xff0c;iperf 是一个用于主动测量 IP 网络上最大可用带宽的工具. 它支持与时间、协议和缓冲区相关的各种参数的调优. 对于每个测试&#xff0c;它报告测量的吞吐量/比特率(带宽), 丢包率和其他参数&#xff…