八叉树是一种树数据结构,其中每个内部节点最多可以有8个子节点。就像将空间划分为两个部分的二叉树一样,Octree将空间划分为最多八部分,称为辛烷。它用于存储占用大量空间的3-D点。如果八叉树的所有内部节点恰好包含8个子节点,则称为完整八叉树。对于高分辨率图形(例如3D计算机图形)也很有用。
通过执行以下步骤,可以从3D体积中形成Octree:
- 将当前3D体积划分为八个框
- 如果任何一个框具有多个点,则将其进一步分成多个框
- 请勿分割其中包含一或零个点的框
- 重复执行此过程,直到所有盒子中包含一个或零个点
以上步骤如图所示。
如果S是每个维中的点数,则由该公式给出在Octree中形成的节点数 。
插入八进制:
- 为了在Octree中插入一个节点,首先,我们检查一个节点是否存在,如果一个节点存在,然后返回,否则我们递归进行。
- 首先,我们从根节点开始并将其标记为当前节点
- 然后我们找到可以存储点的子节点
- 如果该节点为空,则替换为我们要插入的节点并将其设为叶节点
- 如果该节点是叶节点,则使其成为内部节点,如果它是内部节点,则转到子节点。递归执行此过程,直到找不到空节点
- 该函数的时间复杂度为
其中N是节点数
在八进制中搜索:
- 该函数用于搜索树是否存在的点
- 从根节点开始,如果找到具有给定点的节点,则进行递归搜索;如果遇到空节点或边界点或空点,则返回true,然后返回false
- 如果找到内部节点,请转到该节点。此函数的时间复杂度也是O(Log N),其中N是节点数
下面是上述方法的实现
// Implemetation of Octree in 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
// Structure of a point
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)
{
}
};
// Octree class
class Octree {
// if point == NULL, node is internal node.
// if point == (-1, -1, -1), node is empty.
Point* point;
// Represent the boundary of the cube
Point *topLeftFront, *bottomRightBack;
vector children;
public:
// Constructor
Octree()
{
// To declare empty node
point = new Point();
}
// Constructor with three arguments
Octree(int x, int y, int z)
{
// To declare point node
point = new Point(x, y, z);
}
// Constructor with six arguments
Octree(int x1, int y1, int z1, int x2, int y2, int z2)
{
// This use to construct Octree
// with boundaries defined
if (x2 < x1
|| y2 < y1
|| z2 < z1) {
cout << "bounday poitns are not valid" << endl;
return;
}
point = nullptr;
topLeftFront
= new Point(x1, y1, z1);
bottomRightBack
= new Point(x2, y2, z2);
// Assigning null to the children
children.assign(8, nullptr);
for (int i = TopLeftFront;
i <= BottomLeftBack;
++i)
children[i] = new Octree();
}
// Function to insert a point in the octree
void insert(int x,
int y,
int z)
{
// If the point already exists in the octree
if (find(x, y, z)) {
cout << "Point already exist in the tree" << endl;
return;
}
// If the point is out of bounds
if (x < topLeftFront->x
|| x > bottomRightBack->x
|| y < topLeftFront->y
|| y > bottomRightBack->y
|| z < topLeftFront->z
|| z > bottomRightBack->z) {
cout << "Point is out of bound" << endl;
return;
}
// Binary search to insert the point
int midx = (topLeftFront->x
+ bottomRightBack->x)
/ 2;
int midy = (topLeftFront->y
+ bottomRightBack->y)
/ 2;
int midz = (topLeftFront->z
+ bottomRightBack->z)
/ 2;
int pos = -1;
// Checking the octant of
// the point
if (x <= midx) {
if (y <= midy) {
if (z <= midz)
pos = TopLeftFront;
else
pos = TopLeftBottom;
}
else {
if (z <= midz)
pos = BottomLeftFront;
else
pos = BottomLeftBack;
}
}
else {
if (y <= midy) {
if (z <= midz)
pos = TopRightFront;
else
pos = TopRightBottom;
}
else {
if (z <= midz)
pos = BottomRightFront;
else
pos = BottomRightBack;
}
}
// If an internal node is encountered
if (children[pos]->point == nullptr) {
children[pos]->insert(x, y, z);
return;
}
// If an empty node is encountered
else if (children[pos]->point->x == -1) {
delete children[pos];
children[pos] = new Octree(x, y, z);
return;
}
else {
int x_ = children[pos]->point->x,
y_ = children[pos]->point->y,
z_ = children[pos]->point->z;
delete children[pos];
children[pos] = nullptr;
if (pos == TopLeftFront) {
children[pos] = new Octree(topLeftFront->x,
topLeftFront->y,
topLeftFront->z,
midx,
midy,
midz);
}
else if (pos == TopRightFront) {
children[pos] = new Octree(midx + 1,
topLeftFront->y,
topLeftFront->z,
bottomRightBack->x,
midy,
midz);
}
else if (pos == BottomRightFront) {
children[pos] = new Octree(midx + 1,
midy + 1,
topLeftFront->z,
bottomRightBack->x,
bottomRightBack->y,
midz);
}
else if (pos == BottomLeftFront) {
children[pos] = new Octree(topLeftFront->x,
midy + 1,
topLeftFront->z,
midx,
bottomRightBack->y,
midz);
}
else if (pos == TopLeftBottom) {
children[pos] = new Octree(topLeftFront->x,
topLeftFront->y,
midz + 1,
midx,
midy,
bottomRightBack->z);
}
else if (pos == TopRightBottom) {
children[pos] = new Octree(midx + 1,
topLeftFront->y,
midz + 1,
bottomRightBack->x,
midy,
bottomRightBack->z);
}
else if (pos == BottomRightBack) {
children[pos] = new Octree(midx + 1,
midy + 1,
midz + 1,
bottomRightBack->x,
bottomRightBack->y,
bottomRightBack->z);
}
else if (pos == BottomLeftBack) {
children[pos] = new Octree(topLeftFront->x,
midy + 1,
midz + 1,
midx,
bottomRightBack->y,
bottomRightBack->z);
}
children[pos]->insert(x_, y_, z_);
children[pos]->insert(x, y, z);
}
}
// Function that returns true if the point
// (x, y, z) exists in the octree
bool find(int x, int y, int z)
{
// If point is out of bound
if (x < topLeftFront->x
|| x > bottomRightBack->x
|| y < topLeftFront->y
|| y > bottomRightBack->y
|| z < topLeftFront->z
|| z > bottomRightBack->z)
return 0;
// Otherwise perform binary search
// for each ordinate
int midx = (topLeftFront->x
+ bottomRightBack->x)
/ 2;
int midy = (topLeftFront->y
+ bottomRightBack->y)
/ 2;
int midz = (topLeftFront->z
+ bottomRightBack->z)
/ 2;
int pos = -1;
// Deciding the position
// where to move
if (x <= midx) {
if (y <= midy) {
if (z <= midz)
pos = TopLeftFront;
else
pos = TopLeftBottom;
}
else {
if (z <= midz)
pos = BottomLeftFront;
else
pos = BottomLeftBack;
}
}
else {
if (y <= midy) {
if (z <= midz)
pos = TopRightFront;
else
pos = TopRightBottom;
}
else {
if (z <= midz)
pos = BottomRightFront;
else
pos = BottomRightBack;
}
}
// If an internal node is encountered
if (children[pos]->point == nullptr) {
return children[pos]->find(x, y, z);
}
// If an empty node is encountered
else if (children[pos]->point->x == -1) {
return 0;
}
else {
// If node is found with
// the given value
if (x == children[pos]->point->x
&& y == children[pos]->point->y
&& z == children[pos]->point->z)
return 1;
}
return 0;
}
};
// Driver code
int main()
{
Octree tree(1, 1, 1, 5, 5, 5);
tree.insert(1, 2, 3);
tree.insert(1, 2, 3);
tree.insert(6, 5, 5);
cout << (tree.find(1, 2, 3)
? "Found\n"
: "Not Found\n");
cout << (tree.find(3, 4, 4)
? "Found\n"
: "Not Found\n");
tree.insert(3, 4, 4);
cout << (tree.find(3, 4, 4)
? "Found\n"
: "Not Found\n");
return 0;
}
输出:
Point already exist in the tree
Point is out of bound
found
not found
found
应用范围:
- 它用于3D计算机图形游戏
- 它还可用于查找3D空间中最近的相邻对象
- 它也用于颜色量化
其他参考:
https://zh.wikipedia.org/wiki/八叉树