几何数据结构之四叉树与八叉树

news2025/1/20 23:21:14

几何数据结构之四叉树与八叉树

    • 四叉树的定义
    • 四叉树深度的计算公式推导
      • 假设:
      • 计算过程:
        • 1. 划分空间:
        • 2. 节点容纳的最小距离:
        • 3. 解出深度:
        • 4. 考虑常数项:
      • 总结:
    • 八叉树

四叉树的定义

四叉树(Quadtree):是一颗包含树根(Root)的树,每个节点包含四个子节点。我们常见用于描述四叉树的形式如下图:

在这里插入图片描述
它一个节点可以存储四个子节点的数据。当然,我们还可以采用其他形式来描述四叉树。

如下图所示:

在这里插入图片描述
树中每个节点有四个子节点,我们可以把每个节点看作一个正方形,最外围的正方形,包含四个第二大的正方形,同样的,第二大的也包含四个第三大正方形。
当然,我们可以以象限来描述它,一个正方形,被十字叉分为了四个象限,一个象限就代表了一个节点,我们可以不断的递归的去取正方形的边长中点,直到正方形中只存在一个点的。

四叉树是一种空间划分数据结构,通常用于存储二维平面中的点。四叉树将空间递归地划分为四个象限(子区域),并将点插入到对应的子区域中。

插入过程:
每个节点表示一个矩形区域,如果该区域可以容纳更多的点,它就会插入点;如果已经达到阈值(例如最多只能容纳 4 个点),则会进行分割,将区域划分为 4 个子区域。
子区域的插入:每当点超出当前节点的边界时,应该递归到下一个合适的子区域中。如果某个点仍然位于当前节点的范围内,则将其插入到当前节点。
子节点的划分:当节点满了(即点数量超过设定阈值),它将自己分割成 4 个子节点,每个子节点管理一个象限的区域。

四叉树深度的计算公式推导

假设:

  1. 初始区域的边长是 ( S )。
  2. 每个节点容纳的最小距离是 ( C ),即空间中任意两个点之间的最小距离为 ( C ),所以每个子区域将尽可能容纳这种最小距离的点。

计算过程:

1. 划分空间:

四叉树的每一层将空间分为四个象限(子区域)。如果在深度为 ( d ) 的层次,空间被划分为 ( 4^d ) 个子区域,那么每个子区域的大小将是:

子区域边长 = S 2 d \text{子区域边长} = \frac{S}{2^d} 子区域边长=2dS

2. 节点容纳的最小距离:

每个子区域容纳的最小点间距是 ( C ),所以在每个子区域中,至少应该有足够的空间容纳这种最小距离的点。为了确保每个子区域中有两个点之间的最小距离不小于 ( C ),我们有以下条件:

S 2 d ≥ C \frac{S}{2^d} \geq C 2dSC

这意味着每个子区域的边长必须大于等于最小点距离 ( C ),否则就需要进一步划分。

3. 解出深度:

根据上面的不等式,求得最小深度 ( d ):

S 2 d ≥ C ⇒ 2 d ≤ S C ⇒ d ≤ log ⁡ 2 ( S C ) \frac{S}{2^d} \geq C \quad \Rightarrow \quad 2^d \leq \frac{S}{C} \quad \Rightarrow \quad d \leq \log_2 \left( \frac{S}{C} \right) 2dSC2dCSdlog2(CS)

4. 考虑常数项:

实际应用中,可能还需要考虑额外的调整常数项,通常为 3 2 \frac{3}{2} 23,用于补偿一些实现中的空间管理开销或其他实际细节。因此,四叉树的深度可以表示为:

深度 = log ⁡ 2 ( S C ) + 3 2 \text{深度} = \log_2 \left( \frac{S}{C} \right) + \frac{3}{2} 深度=log2(CS)+23

总结:

  • ( S ) 是初始区域的边长。
  • ( C ) 是任意两个点之间的最小距离,即每个子区域内元素间的最小间距。
  • 最终的四叉树深度大致为:

深度 = log ⁡ 2 ( S C ) + 3 2 \text{深度} = \log_2 \left( \frac{S}{C} \right) + \frac{3}{2} 深度=log2(CS)+23

四叉树大量使用与碰撞检测上面。

下面是简单实现四叉树的代码:

#include <iostream>
#include <vector>
#include <memory>

using namespace std;

// 定义一个点(Point)类,表示一个二维空间中的点
class Point
{
public:
    int x, y;  // 点的 x 和 y 坐标

    // 构造函数,初始化 x 和 y 坐标
    Point(int x, int y) : x(x), y(y) {}
};

// 定义一个边界(Boundary)类,表示一个矩形区域
class Boundary
{
public:
    int x, y, width, height;  // 矩形的中心坐标 (x, y),宽度和高度

    // 构造函数,初始化矩形的中心坐标、宽度和高度
    Boundary(int x, int y, int width, int height)
        : x(x), y(y), width(width), height(height) {}

    // 判断一个点是否在矩形区域内
    bool contains(const Point& point) const
    {
        return point.x >= x - width / 2 && point.x <= x + width / 2 &&
            point.y >= y - height / 2 && point.y <= y + height / 2;
    }

    // 判断一个矩形区域是否与当前矩形区域相交
    bool intersects(const Boundary& range) const
    {
        return !(range.x - range.width / 2 > x + width / 2 ||
            range.x + range.width / 2 < x - width / 2 ||
            range.y - range.height / 2 > y + height / 2 ||
            range.y + range.height / 2 < y - height / 2);
    }
};

// 定义四叉树(QuadTree)类,用于存储二维空间中的点
class QuadTree
{
private:
    Boundary boundary;  // 当前节点的矩形区域
    int capacity;  // 当前节点的最大容量(每个节点最多存储多少个点)
    vector<Point> points;  // 当前节点存储的点
    unique_ptr<QuadTree> northeast;  // 东北子节点
    unique_ptr<QuadTree> northwest;  // 西北子节点
    unique_ptr<QuadTree> southeast;  // 东南子节点
    unique_ptr<QuadTree> southwest;  // 西南子节点

public:
    // 构造函数,初始化边界和容量
    QuadTree(const Boundary& boundary, int capacity)
        : boundary(boundary), capacity(capacity) {}

    // 将当前节点划分为四个子节点
    void subdivide()
    {
        int subWidth = boundary.width / 2;  // 子节点的宽度
        int subHeight = boundary.height / 2;  // 子节点的高度
        int x = boundary.x;  // 父节点的 x 坐标
        int y = boundary.y;  // 父节点的 y 坐标

        // 创建四个子节点,分别对应东北、西北、东南、西南
        northeast = make_unique<QuadTree>(Boundary(x + subWidth / 2, y - subHeight / 2, subWidth, subHeight), capacity);
        northwest = make_unique<QuadTree>(Boundary(x - subWidth / 2, y - subHeight / 2, subWidth, subHeight), capacity);
        southeast = make_unique<QuadTree>(Boundary(x + subWidth / 2, y + subHeight / 2, subWidth, subHeight), capacity);
        southwest = make_unique<QuadTree>(Boundary(x - subWidth / 2, y + subHeight / 2, subWidth, subHeight), capacity);
    }

    // 插入一个点到四叉树中
    bool insert(const Point& point)
    {
        // 如果点超出了当前节点的边界,返回 false
        if (!boundary.contains(point))
        {
            cout << "Point (" << point.x << ", " << point.y << ") is out of bounds." << endl;
            return false;
        }

        // 如果当前节点的点数未超出容量,则直接插入点
        if (points.size() < capacity)
        {
            points.push_back(point);  // 将点加入当前节点的点集合中
            cout << "Point (" << point.x << ", " << point.y << ") inserted in current node." << endl;
            return true;
        }

        // 如果当前节点已超出容量,进行分割
        if (northeast == nullptr)
        {
            cout << "Subdividing node at (" << boundary.x << ", " << boundary.y << ")" << endl;
            subdivide();  // 划分子节点
        }

        // 递归地将点插入到四个子节点中
        if (northeast->insert(point)) return true;
        if (northwest->insert(point)) return true;
        if (southeast->insert(point)) return true;
        if (southwest->insert(point)) return true;

        return false;
    }

    // 打印当前节点及其所有子节点中的点
    void printPoints() const
    {
        // 打印当前节点存储的点
        for (const auto& point : points)
        {
            cout << "(" << point.x << ", " << point.y << ")" << endl;
        }

        // 递归地打印四个子节点中的点
        if (northeast != nullptr) northeast->printPoints();
        if (northwest != nullptr) northwest->printPoints();
        if (southeast != nullptr) southeast->printPoints();
        if (southwest != nullptr) southwest->printPoints();
    }
};

int main()
{
    // 扩大根节点的边界为 20x20
    Boundary boundary(0, 0, 20, 20); 

    // 创建一个四叉树,根节点的容量为 4
    QuadTree qt(boundary, 4);

    // 插入一些点到四叉树
    qt.insert(Point(2, 3));
    qt.insert(Point(3, 5));
    qt.insert(Point(6, 7));
    qt.insert(Point(8, 1));
    qt.insert(Point(1, 1));
    qt.insert(Point(4, 4));

    // 打印树中的所有点
    cout << "Points in the tree:" << endl;
    qt.printPoints();

    return 0;
}

八叉树

八叉树原理与四叉树类似,它可以理解为一个下图:
在这里插入图片描述
一个立方体被三个平面分成了八块,它的实现与原理与四叉树类似,在此不过多赘述。

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

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

相关文章

(一)相机标定——四大坐标系的介绍、对应转换、畸变原理以及OpenCV完整代码实战(C++版)

一、四大坐标系介绍 1&#xff0c;世界坐标系 从这个世界&#xff08;world&#xff09;的视角来看物体 世界坐标系是3D空间坐标&#xff0c;每个点的位置用 ( X w , Y w , Z w ) (X_w,Y_w,Z_w) (Xw​,Yw​,Zw​)表示 2&#xff0c;相机坐标系 相机本身具有一个坐标系&…

嵌入式知识点总结 C/C++ 专题提升(一)-关键字

针对于嵌入式软件杂乱的知识点总结起来&#xff0c;提供给读者学习复习对下述内容的强化。 目录 1.C语言宏中"#“和"##"的用法 1.1.(#)字符串化操作符 1.2.(##)符号连接操作符 2.关键字volatile有什么含意?并举出三个不同的例子? 2.1.并行设备的硬件寄存…

重塑商业智能:大数据改变商业的十种方式

在过去几年间&#xff0c;大数据一直在改变许多公司的运营方式。大数据指的是大量且多样的数据集&#xff0c;当这些数据被妥善收集和分析时&#xff0c;人们能够从中获取有价值的洞察信息。随着大数据逐渐应用于中小型企业&#xff0c;它有望彻底变革企业运营模式。以下将介绍…

基于Spring Boot的车间调度管理系统

基于 Spring Boot 的车间调度管理系统 一、系统概述 基于 Spring Boot 的车间调度管理系统是一个为制造企业车间生产活动提供智能化调度和管理解决方案的软件系统。它利用 Spring Boot 框架的便捷性和高效性&#xff0c;整合车间内的人员、设备、物料、任务等资源&#xff0c…

Ubuntu 24.04 LTS 安装 tailscale 并访问 SMB共享文件夹

Ubuntu 24.04 LTS 安装 tailscale 安装 Tailscale 官方仓库 首先&#xff0c;确保系统包列表是最新的&#xff1a; sudo apt update接下来&#xff0c;安装 Tailscale 所需的仓库和密钥&#xff1a; curl -fsSL https://tailscale.com/install.sh | sh这会自动下载并安装 …

Ubuntu 22.04 TLS 忘记root密码,重启修改的解决办法

1.想办法进入这个界面&#xff0c;我这里是BIOS引导的是按Esc按一下就行&#xff0c;UEFI的貌似是按Shift不得而知&#xff0c;没操作过。下移到Advanced options for Ubuntu&#xff0c;按enter 2.根据使用的内核版本&#xff0c;选择带「recovery mode」字样的内核版本&#…

故障诊断 | BWO白鲸算法优化KELM故障诊断(Matlab)

目录 效果一览文章概述BWO白鲸算法优化KELM故障诊断一、引言1.1、研究背景及意义1.2、故障诊断技术的现状1.3、研究目的与内容二、KELM基本理论2.1、KELM模型简介2.2、核函数的选择2.3、KELM在故障诊断中的应用三、BWO白鲸优化算法3.1、BWO算法基本原理3.2、BWO算法的特点3.3、…

TCP状态转移图详解

状态 描述 LISTEN represents waiting for a connection request from any remote TCP and port. SYN-SENT represents waiting for a matching connection request after having sent a connection request. SYN-RECEIVED represents waiting for a confirming connect…

LabVIEW 水电站厂内经济运行系统

基于 LabVIEW 的水电站经济运行系统&#xff0c;主要针对农村小水电站运行管理的不足进行改进&#xff0c;通过精确控制发电与用水量&#xff0c;最小化耗水量并优化负荷分配&#xff0c;提升水电站的运营效率和经济效益。 ​ LabVIEW 在系统中的功能特点 强大的图形化编程环…

蓝桥杯训练—矩形面积交

文章目录 一、题目二、示例三、解析四、代码 一、题目 平面上有两个矩形&#xff0c;它们的边平行于直角坐标系的X轴或Y轴&#xff0c;对于每个矩形&#xff0c;我们给出它的一对相对顶点的坐标&#xff0c;请你编程写出两个矩形的交的面积 输入格式&#xff1a; 输入包含两行…

Flask简介与安装以及实现一个糕点店的简单流程

目录 1. Flask简介 1.1 Flask的核心特点 1.2 Flask的基本结构 1.3 Flask的常见用法 1.3.1 创建Flask应用 1.3.2 路由和视图函数 1.3.3 动态URL参数 1.3.4 使用模板 1.4 Flask的优点 1.5 总结 2. Flask 环境创建 2.1 创建虚拟环境 2.2 激活虚拟环境 1.3 安装Flask…

基于机器学习的电信用户流失预测与数据分析可视化

完整源码项目包获取→点击文章末尾名片&#xff01; 背景描述 根据IBM商业社区分享团队描述&#xff0c;该数据集为某电信公司在加利福尼亚为7000余位用户&#xff08;个人/家庭&#xff09;提供电话和互联网服务的相关记录。描述用户基本情况&#xff0c;包括每位用户已注册的…

InVideo AI技术浅析(五):生成对抗网络

一、特效生成 1. 工作原理 特效生成是计算机视觉中的高级应用,旨在通过算法生成高质量的视觉特效,如风格迁移、图像到图像的翻译等。InVideo AI 使用生成对抗网络(GAN)来实现这一功能。GAN 通过生成器和判别器两个网络的对抗训练,生成逼真的视觉特效。 2. 关键技术模型…

Linux操作系统的灵魂,深度解析MMU内存管理

在计算机的奇妙世界里&#xff0c;我们每天使用的操作系统看似流畅自如地运行着各类程序&#xff0c;背后实则有着一位默默耕耘的 “幕后英雄”—— 内存管理单元&#xff08;MMU&#xff09;。它虽不常被大众所熟知&#xff0c;却掌控着计算机内存的关键命脉&#xff0c;是保障…

线性代数概述

矩阵与线性代数的关系 矩阵是线性代数的研究对象之一&#xff1a; 矩阵&#xff08;Matrix&#xff09;是一个按照长方阵列排列的复数或实数集合&#xff0c;是线性代数中的核心概念之一。矩阵的定义和性质构成了线性代数中矩阵理论的基础&#xff0c;而矩阵运算则简洁地表示和…

Reactor 模式在 Edis、Nginx 和 Netty 中的应用与高性能网络模式解析

文章目录 参考文章Reactor 模式在 Edis、Nginx 和 Netty 中的应用与高性能网络模式解析一、Reactor 模式二、Redis 中的 Reactor 模式三、Nginx 中的 Reactor 模式四、Netty 中的 Reactor 模式五、Reactor 模式的优势六、总结 参考文章 redis&#xff0c;nginx&#xff0c;net…

企业级NoSQL数据库Redis

1.浏览器缓存过期机制 1.1 最后修改时间 last-modified 浏览器缓存机制是优化网页加载速度和减少服务器负载的重要手段。以下是关于浏览器缓存过期机制、Last-Modified 和 ETag 的详细讲解&#xff1a; 一、Last-Modified 头部 定义&#xff1a;Last-Modified 表示服务器上资源…

【自动驾驶BEV感知之Transformer】

欢迎大家关注我的B站&#xff1a; 偷吃薯片的Zheng同学的个人空间-偷吃薯片的Zheng同学个人主页-哔哩哔哩视频 (bilibili.com) 本文为深蓝学院《BEV感知理论与实践》 的学习笔记 以图书馆看书举例 query&#xff1a;查询&#xff0c;感兴趣的东西 Key&#xff1a;索引&…

http转化为https生成自签名证书

背景 项目开发阶段前后交互采用http协议&#xff0c;演示环境采用htttps协议 &#xff0c;此处为个人demo案例 组件 后端&#xff1a;springBoot 前端&#xff1a;vue web 服务&#xff1a;tomcat 部署环境&#xff1a;linux 生成自签名证书 创建目录 存储证书位置 # mkdir -p…

AAPM:基于大型语言模型代理的资产定价模型,夏普比率提高9.6%

“AAPM: Large Language Model Agent-based Asset Pricing Models” 论文地址&#xff1a;https://arxiv.org/pdf/2409.17266v1 Github地址&#xff1a;https://github.com/chengjunyan1/AAPM 摘要 这篇文章介绍了一种利用LLM代理的资产定价模型&#xff08;AAPM&#xff09;…