📜  八度|插入和搜索

📅  最后修改于: 2021-04-17 09:54:52             🧑  作者: Mango

八叉树是一种树数据结构,其中每个内部节点最多可以有8个子节点。就像将空间划分为两个部分的二叉树一样,Octree将空间划分为最多八部分,称为辛烷。它用于存储占用大量空间的3-D点。如果八叉树的所有内部节点恰好包含8个子节点,则称为完整八叉树。对于高分辨率图形(例如3D计算机图形)也很有用。

通过执行以下步骤,可以从3D体积中形成Octree:

  1. 将当前3D体积划分为八个框
  2. 如果任何一个框具有多个点,则将其进一步分成多个框
  3. 请勿分割其中包含一或零个点的框
  4. 重复执行此过程,直到所有盒子中包含一个或零个点

以上步骤如图所示。 想像上面的算法

如果S是每个维中的点数,则由该公式给出在Octree中形成的节点数(S^{3} -1)/7

插入八进制:

  • 为了在Octree中插入一个节点,首先,我们检查一个节点是否存在,如果一个节点存在,然后返回,否则我们递归进行。
  • 首先,我们从根节点开始并将其标记为当前节点
  • 然后我们找到可以存储点的子节点
  • 如果该节点为空,则替换为我们要插入的节点并将其设为叶节点
  • 如果该节点是叶节点,则使其成为内部节点,如果它是内部节点,则转到子节点。递归执行此过程,直到找不到空节点
  • 该函数的时间复杂度为O(log(N))其中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

应用范围:

  1. 它用于3D计算机图形游戏
  2. 它还可用于查找3D空间中最近的相邻对象
  3. 它也用于颜色量化

其他参考:

https://zh.wikipedia.org/wiki/八叉树