八叉树:插入与搜索详解

八叉树是一种树数据结构,其中每个内部节点最多可以拥有 8 个子节点。就像二叉树将空间划分为两个部分一样,八叉树将空间最多划分为八个部分,我们称之为“八分体”。它主要用于存储需要占用大量空间的 3D 点。如果八叉树的所有内部节点都恰好包含 8 个子节点,那么我们就称它为完全八叉树。它在高分辨率图形领域(如 3D 计算机图形)也非常有用。

我们可以通过以下步骤从 3D 体积生成八叉树:

  • 将当前的 3D 体积划分为 8 个盒子
  • 如果任何盒子包含不止一个点,则将其进一步划分为更小的盒子
  • 不要分割包含一个或零个点的盒子
  • 重复此过程,直到所有盒子都只包含一个或零个点

上述步骤如下图所示。

!Imagination of above algorithm

如果 S 是每个维度上的点数,那么八叉树中形成的节点数由以下公式给出:(S^{3} -1)/7

八叉树中的插入

  • 为了在八叉树中插入一个节点,首先我们要检查该节点是否存在。如果节点已经存在,我们直接返回;否则,我们进行递归操作。
  • 首先,我们从根节点开始,并将其标记为当前节点。
  • 然后,我们要找到可以存储该点的子节点。
  • 如果该节点为空,我们将其替换为我们要插入的节点,并将其设为叶子节点。
  • 如果该节点是叶子节点,我们将其转换为内部节点;如果它已经是内部节点,则进入其子节点。此过程递归执行,直到找到一个空节点为止。
  • 此函数的时间复杂度为 O(log(N)),其中 N 是节点的数量。

八叉树中的搜索

  • 此函数用于搜索树中是否存在某个点。
  • 从根节点开始,如果找到包含给定点的节点,则递归搜索并返回 true;如果遇到空节点、边界点或空点,则返回 false。
  • 如果找到内部节点,则进入该节点。此函数的时间复杂度也是 O(log N),其中 N 是节点的数量。

下面是上述方法的实现

CPP14


// c++ 中的八叉树实现

#include

#include

using namespace std;

#define TopLeftFront 0

#define TopRightFront 1

#define BottomRightFront 2

#define BottomLeftFront 3

#define TopLeftBottom 4

#define TopRightBottom 5

#define BottomRightBack 6

#define BottomLeftBack 7

// 点的结构体

struct Point {

int x;

int y;

int z;

Point()

: x(-1), y(-1), z(-1)

{

}

Point(int a, int b, int c)

: x(a), y(b), z(c)

{

}

};

// 八叉树类

class Octree {

// 如果 point == NULL,节点是内部节点。

// 如果 point == (-1, -1, -1),节点是空的。

Point* point;

// 表示立方体的边界

Point topLeftFront, bottomRightBack;

vector children;

public:

// 构造函数

Octree()

{

// 声明空节点

point = new Point();

}

// 带有三个参数的构造函数

Octree(int x, int y, int z)

{

// 声明点节点

point = new Point(x, y, z);

}

// 带有六个参数的构造函数

Octree(int x1, int y1, int z1, int x2, int y2, int z2)

{

// 这用于构造定义了边界的八叉树

if (x2 < x1

|| y2 < y1

|| z2 < z1) {

cout << "边界点无效" << endl;

return;

}

point = nullptr;

topLeftFront

= new Point(x1, y1, z1);

bottomRightBack

= new Point(x2, y2, z2);

// 将子节点赋值为 null

children.assign(8, nullptr);

for (int i = TopLeftFront;

i <= BottomLeftBack;

++i)

children[i] = new Octree();

}

// 在八叉树中插入一个点的函数

void insert(int x,

int y,

int z)

{

// 如果该点已经存在于八叉树中

if (find(x, y, z)) {

cout << "点已存在于树中" << endl;

return;

}

// 如果该点越界

if (x x

|| x > bottomRightBack->x

|| y y

|| y > bottomRightBack->y

|| z z

|| z > bottomRightBack->z) {

cout << "点越界" << endl;

return;

}

// 二分搜索以插入该点

int midx = (topLeftFront->x

+ bottomRightBack->x)

/ 2;

int midy = (topLeftFront->y

+ bottomRightBack->y)

/ 2;

int midz = (topLeftFront->z

+ bottomRightBack->z)

/ 2;

int pos = –

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。如需转载,请注明文章出处豆丁博客和来源网址。https://shluqu.cn/21724.html
点赞
0.00 平均评分 (0% 分数) - 0