算法笔记:KD树
1 引入原因
- K近邻算法需要在整个数据集中搜索和测试数据x最近的k个点,如果一一计算,然后再排序,开销过大
- 引入KD树的作用就是对KNN搜索和排序的耗时进行改进
2 KD树
2.1 主体思路
- 以空间换时间,利用训练样本集中的样本点,沿各维度依次对k维空间进行划分,建立二叉树
- 利用分治思想提高算法搜索效率
- 二分查找的算法复杂度是O(logN)
,KD树的搜索效率与之接近(取决于所构造kd-tree是否接近平衡树)

- 上图为为训练样本对空间的划分以及对应的kd树
- 绿色实心五角星为测试样本,通过kd-tree的搜索算法,快速找到与其最近邻的3个训练样本点(空心五角星标注的点)
2.2 KD树的建立
2.2.1 以一个例子引入
- 比如我有6个点:(2,3),(4,7),(5,4),(7,2),(8,1),(9,6)
- 1) 数据有两个维度,分别计算x,y方向上数据的方差
- x方向上的方差最大
- ——>先沿着X轴方向进行split
- 注:这一步也可以不要,因为KD树适用的问题大多是维度小于20的,所以按照维度顺序一个一个来也没有问题
- 2)根据x轴方向的值2,5,9,4,8,7排序选出中位数为7
- x≤7的和x >7的被分开了
- x≤7的和x >7的被分开了
- 3) 被分开的左半区和右半区分别选出y轴方向的中位数(偶数选小的那个)
- 4)左上方三个点再根据x轴分一刀(其他三个区域已经各只剩一个点了)
- 最终得到的KD树
2.2.2 伪代码
def kd_tree_construct:input: x: 训练样本集dim: 当前节点的分割维度(子节点的分割维度=(dim+1)%样本的维度)output: node: 构造好的kd tree的根节点if 只有一个数据点:创建一个叶子结点node包含这一单一的点node.point = x[0]node.son1 = Nonenode.son2 = Nonereturn nodeelse:记dim维度上的中位点为x(对x中的数据按dim维排序,取中位点,偶数个则取较小的那个)记xl为左集合(dim维小于p点的所有点)记xr为右集合(dim维大于p点的所有点)创建带有两个孩子的node:node.point = pnode.son1 = fit_kd_tree(xl)node.son2 = fit_kd_tree(xr)return node
2.3 KD树上的最近邻查找
2.3.1 伪代码
def kd_tree_search:global:Q, 缓存k个最近邻点(初始时包含一个无穷远点)q, 与Q对应,保存Q中各点与测试点的距离input: k, 寻找k个最近邻t, 测试点node, 当前节点(一开始时根节点)dim, 当前节点的分割维度(子节点的分割维度=(dim+1)%数据点的维度)output: 无if distance(t, node.point) < max(q):将node.point添加到Q,并同步更新q若Q内超过k个近邻点,则移出与测试点距离最远的那个点,并同步更新qif t[dim]-max(q) < node.point[dim]:kd_tree_search(k,t,node.son1)if t[dim]+max(q) > node.point[dim]:kd_tree_search(k,t,node.son2)
2.3.1 以一个例子开始
2.3.1.1 例子1
搜索(2.1,3.1)
记k=1

- 第1步:将(7,2)加入Q中,maxq=5.02,更新Q
- 2.1-5.02≤7
- 搜索左儿子
- 第2步:将(5.4)加入Q中,maxq=3.04,更新Q
- 3.1-3.04≤4
- 搜索下儿子
- 第3步:将(2,3)加入Q中,maxq=0.1414,更新Q
- 已经是叶子节点了,结束
- 3.1-3.04≥4
- 搜索上儿子
- 第4步:将(4,7)加入Q中,maxq=4.338>0.1414,不更新Q,仍为0.1414
- 已经是叶子节点了,结束
- 3.1-3.04≤4
- 2.1-5.02≥7
- 搜索右儿子
- 第5步,将(9,6)加入Q中,maxq=7.484>0.1414,不更新Q,仍为0.1414
- 3.1+7.484>6
- 搜索上儿子
- 没有上儿子,结束
- 2.1-5.02≤7
- 算法结束,最近的点是(2,3),q=0.1414
2.3.1.2 例子2 回溯时改变最近邻点
假设我们要查询的点是2,4.5
同样记k=1

- 第1步:将(7,2)加入Q中,maxq=5.59,更新Q
- 2-5.59≤7
- 搜索左儿子
- 第2步:将(5.4)加入Q中,maxq=3.04,更新Q
- 4.5-3.04≤4
- 搜索下儿子
- 第3步:将(2,3)加入Q中,maxq=1.5,更新Q
- 4.5+3.04≥4
- 搜索上儿子
- 第4步:将(4,7)加入Q中,maxq=3.20>1.5,不更新Q,仍为1.5
- 4.5-3.04≤4
- 2+5.59 >7
- 搜索右儿子
- 第5步,将(9,6)加入Q中,maxq=7.16>1.5,不更新Q,仍为1.5
- 4.5+7.16>6
- 搜索上儿子
- 没有上儿子,结束
- 4.5+7.16>6
- 2-5.59≤7
- 算法结束,最近的点是(2,3),距离为1.5
参考内容:KNN的核心算法kd-tree和ball-tree - 简书 (jianshu.com)
k-d tree算法 - J_Outsider - 博客园 (cnblogs.com)
相关文章:
算法笔记:KD树
1 引入原因 K近邻算法需要在整个数据集中搜索和测试数据x最近的k个点,如果一一计算,然后再排序,开销过大 引入KD树的作用就是对KNN搜索和排序的耗时进行改进 2 KD树 2.1 主体思路 以空间换时间,利用训练样本集中的样本点&…...
plumelog介绍与应用-一个简单易用的java分布式日志系统
官方文档:http://www.plumelog.com/zh-cn/docs/FASTSTART.html 简介 无代码入侵的分布式日志系统,基于log4j、log4j2、logback搜集日志,设置链路ID,方便查询关联日志基于elasticsearch作为查询引擎高吞吐,查询效率高全…...
百度网盘删除“我的应用数据”文件夹
百度网盘删除“我的应用数据”文件夹电脑端方法-2023.2.27成功 - 哔哩哔哩 (bilibili.com) 百度网盘怎样删除我的应用数据文件夹-手机端方法-2023.3.24日成功 - 哔哩哔哩 (bilibili.com)...
多店铺智能客服,助力店铺销量倍增
近年来电商发展得非常快速,市场竞争也是愈发激烈了。商家不仅需要提高产品和服务的质量,还要争取为自己获取更多的曝光,以此来分散运营的风险和降低经营的成本,所以越来越多的商家也开始转向多平台多店铺运营。但即使运营多个平台…...
会话跟踪技术
cookie 是通过在浏览器第一次请求服务器时,在响应中放入cookie,浏览器接收到cookie后保存在本地,之后每次请求服务器时都将cookie携带到请求头中,用来验证用户身份与状态等。 缺点: 移动端app没有cookiecookie保存在…...
递归算法学习——子集
目录 一,题目解析 二,例子 三,题目接口 四,解题思路以及代码 1.完全深度搜索 2.广度搜索加上深度优先搜索 五,相似题 1.题目 2.题目接口 3.解题代码 一,题目解析 给你一个整数数组 nums ,…...
学习笔记:ROS使用经验(ROS报错)
报错:进程崩溃 ] process has died [pid 734, exit code -5, cmd /root/catkin_ws/devel/lib/pose_graph/pose_graph __name:pose_graph __log:/root/.ros/log/31b0ae1c-3295-11ee-bda9-02429b5737dc/pose_graph-5.log]. log file: /root/.ros/log/31b0ae1c-3295-11…...
设计模式二十四:访问者模式(Visitor Pattern)
用于将数据结构与数据操作分离,使得可以在不修改数据结构的情况下,定义新的操作。访问者模式的核心思想是,将数据结构和操作进行解耦,从而使得新增操作时不必修改数据结构,只需添加新的访问者。主要目的是在不改变数据…...
使用gn+Ninja构建项目
使用下载编译好的gn和ninja报错 先下载了gn的源码[gn.googlesource.com/gn],然后编译报错,就直接下载了了编译号的gn和Ninja,然后写了Helloworld应用的BUILD.gn,然后将"gn\examples\simple_build\build"拷贝至当前目录…...
VMware虚拟机连不上网络
固定ip地址 进入网络配置文件 cd /etc/sysconfig/network-scripts 打开文件 vi ifcfg-ens33 编辑 BOOTPROTO设置为static,有3个值(decp、none、static) BOOTPROTO"static" 打开网络 ONBOOT"yes" 固定ip IPADDR1…...
安防视频监控/视频集中存储/云存储平台EasyCVR平台无法取消共享通道该如何解决?
视频汇聚/视频云存储/集中存储/视频监控管理平台EasyCVR能在复杂的网络环境中,将分散的各类视频资源进行统一汇聚、整合、集中管理,实现视频资源的鉴权管理、按需调阅、全网分发、云存储、智能分析等,视频智能分析平台EasyCVR融合性强、开放度…...
算法通关村-----如何基于数组和链表实现栈
实现栈的基本方法 push(T t)元素入栈 T pop() 元素出栈 Tpeek() 查看栈顶元素 boolean isEmpty() 栈是否为空 基于数组实现栈 import java.util.Arrays;public class ArrayStack<T> {private Object[] stack;private int top;public ArrayStack() {this.stack new…...
day-05 TCP半关闭 ----- DNS ----- 套接字的选项
一、优雅的断开套接字连接 之前套接字的断开都是单方面的。 (一)基于TCP的半关闭 Linux的close函数和windows的closesocket函数意味着完全断开连接。完全断开不仅不能发送数据,从而也不能接收数据。在某些情况下,通信双方的某一方…...
区块链金融项目怎么做?
区块链技术的兴起引发了金融领域的变革,为金融行业带来了前所未有的机遇与挑战。在这个快速发展的领域中,如何在区块链金融领域做出卓越的表现?本文将从专业性和思考深度两个方面,探讨区块链金融的发展路径,并为读者提…...
Redis与数据库保持一致
参考链接 先更新数据库,再更新redis 存在漏洞,如果更新Redis失败,仍然会导致不一致 先删Redis,再更新数据库并同步数据到Redis 存在漏洞,多线程情况下,线程1删除redis后,还是有可能被其他线程读取旧的数据…...
idea中vue项目 npm安装插件后node modules中找不到
从硬盘中重新加载一下...
已知两地经纬度,计算两地直线距离
文章目录 1 原理公式2 代码实现2.1 JavaScript2.2 C2.3 Python2.4 MATLAB 1 原理公式 在地球上,计算两点之间的直线距离通常使用地理坐标系(例如WGS84)。计算两地直线距离的公式是根据经纬度之间的大圆距离(Great Circle Distanc…...
我想开通期权?如何开通期权账户?
场内期权的合约由交易所统一标准化定制,大家面对的同一个合约对应的价格都是一致的,比较公开透明,期权开户当天不能交易的,期权开户需要满足20日日均50万及半年交易经验即可操作,下文科普我想开通期权?如何…...
ChatGPT对软件测试的影响
ChatGPT 是一个经过预训练的 AI 语言模型,可以通过聊天的方式回答问题,或者与人闲聊。它能处理的是文本类的信息,输出也只能是文字。它从我们输入的信息中获取上下文,结合它被训练的大模型,进行分析总结,给…...
minion在ubuntu上的搭建步骤
在Ubuntu上搭建MinIO可以按照以下步骤进行: 下载MinIO服务器二进制文件: 通过浏览器访问 https://min.io/download 或使用以下命令获取最新的MinIO二进制文件:wget https://dl.min.io/server/minio/release/linux-amd64/minio赋予二进制文件…...
C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
LeetCode - 199. 二叉树的右视图
题目 199. 二叉树的右视图 - 力扣(LeetCode) 思路 右视图是指从树的右侧看,对于每一层,只能看到该层最右边的节点。实现思路是: 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...
Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...
c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...
永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...



