📜  四叉树

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

四叉树是用于有效存储二维空间上点数据的树。在这棵树中,每个节点最多具有四个子节点。
我们可以使用以下步骤从二维区域构造四叉树:

  1. 将当前的二维空间划分为四个框。
  2. 如果一个盒子中包含一个或多个点,则创建一个子对象,在其中存储盒子的二维空间
  3. 如果一个框不包含任何点,则不要为其创建子级
  4. 为每个孩子递归。

四叉树用于图像压缩,其中每个节点包含其每个子节点的平均颜色。您在树中遍历的深度越深,图像的细节越多。
四叉树还用于在二维区域中搜索节点。例如,如果您想找到最接近给定坐标的点,则可以使用四叉树来完成。

插入函数
插入功能用于将节点插入现有的四叉树。此函数首先检查给定的节点是否在当前四边形的边界内。如果不是,那么我们立即停止插入。如果它在边界内,则根据其位置选择适当的子级以包含此节点。
此函数为O(Log N),其中N为距离的大小。

搜索函数
搜索函数用于在给定的四边形中定位节点。还可以对其进行修改,以将最近的节点返回给定点。通过获取给定点,与子四边形的边界进行比较并递归,可以实现此函数。
此函数为O(Log N),其中N为距离的大小。

下面给出的程序演示了在四叉树中存储节点。

// C++ Implementation of Quad Tree
#include 
#include 
using namespace std;
  
// Used to hold details of a point
struct Point
{
    int x;
    int y;
    Point(int _x, int _y)
    {
        x = _x;
        y = _y;
    }
    Point()
    {
        x = 0;
        y = 0;
    }
};
  
// The objects that we want stored in the quadtree
struct Node
{
    Point pos;
    int data;
    Node(Point _pos, int _data)
    {
        pos = _pos;
        data = _data;
    }
    Node()
    {
        data = 0;
    }
};
  
// The main quadtree class
class Quad
{
    // Hold details of the boundary of this node
    Point topLeft;
    Point botRight;
  
    // Contains details of node
    Node *n;
  
    // Children of this tree
    Quad *topLeftTree;
    Quad *topRightTree;
    Quad *botLeftTree;
    Quad *botRightTree;
  
public:
    Quad()
    {
        topLeft = Point(0, 0);
        botRight = Point(0, 0);
        n = NULL;
        topLeftTree  = NULL;
        topRightTree = NULL;
        botLeftTree  = NULL;
        botRightTree = NULL;
    }
    Quad(Point topL, Point botR)
    {
        n = NULL;
        topLeftTree  = NULL;
        topRightTree = NULL;
        botLeftTree  = NULL;
        botRightTree = NULL;
        topLeft = topL;
        botRight = botR;
    }
    void insert(Node*);
    Node* search(Point);
    bool inBoundary(Point);
};
  
// Insert a node into the quadtree
void Quad::insert(Node *node)
{
    if (node == NULL)
        return;
  
    // Current quad cannot contain it
    if (!inBoundary(node->pos))
        return;
  
    // We are at a quad of unit area
    // We cannot subdivide this quad further
    if (abs(topLeft.x - botRight.x) <= 1 &&
        abs(topLeft.y - botRight.y) <= 1)
    {
        if (n == NULL)
            n = node;
        return;
    }
  
    if ((topLeft.x + botRight.x) / 2 >= node->pos.x)
    {
        // Indicates topLeftTree
        if ((topLeft.y + botRight.y) / 2 >= node->pos.y)
        {
            if (topLeftTree == NULL)
                topLeftTree = new Quad(
                    Point(topLeft.x, topLeft.y),
                    Point((topLeft.x + botRight.x) / 2,
                        (topLeft.y + botRight.y) / 2));
            topLeftTree->insert(node);
        }
  
        // Indicates botLeftTree
        else
        {
            if (botLeftTree == NULL)
                botLeftTree = new Quad(
                    Point(topLeft.x,
                        (topLeft.y + botRight.y) / 2),
                    Point((topLeft.x + botRight.x) / 2,
                        botRight.y));
            botLeftTree->insert(node);
        }
    }
    else
    {
        // Indicates topRightTree
        if ((topLeft.y + botRight.y) / 2 >= node->pos.y)
        {
            if (topRightTree == NULL)
                topRightTree = new Quad(
                    Point((topLeft.x + botRight.x) / 2,
                        topLeft.y),
                    Point(botRight.x,
                        (topLeft.y + botRight.y) / 2));
            topRightTree->insert(node);
        }
  
        // Indicates botRightTree
        else
        {
            if (botRightTree == NULL)
                botRightTree = new Quad(
                    Point((topLeft.x + botRight.x) / 2,
                        (topLeft.y + botRight.y) / 2),
                    Point(botRight.x, botRight.y));
            botRightTree->insert(node);
        }
    }
}
  
// Find a node in a quadtree
Node* Quad::search(Point p)
{
    // Current quad cannot contain it
    if (!inBoundary(p))
        return NULL;
  
    // We are at a quad of unit length
    // We cannot subdivide this quad further
    if (n != NULL)
        return n;
  
    if ((topLeft.x + botRight.x) / 2 >= p.x)
    {
        // Indicates topLeftTree
        if ((topLeft.y + botRight.y) / 2 >= p.y)
        {
            if (topLeftTree == NULL)
                return NULL;
            return topLeftTree->search(p);
        }
  
        // Indicates botLeftTree
        else
        {
            if (botLeftTree == NULL)
                return NULL;
            return botLeftTree->search(p);
        }
    }
    else
    {
        // Indicates topRightTree
        if ((topLeft.y + botRight.y) / 2 >= p.y)
        {
            if (topRightTree == NULL)
                return NULL;
            return topRightTree->search(p);
        }
  
        // Indicates botRightTree
        else
        {
            if (botRightTree == NULL)
                return NULL;
            return botRightTree->search(p);
        }
    }
};
  
// Check if current quadtree contains the point
bool Quad::inBoundary(Point p)
{
    return (p.x >= topLeft.x &&
        p.x <= botRight.x &&
        p.y >= topLeft.y &&
        p.y <= botRight.y);
}
  
// Driver program
int main()
{
    Quad center(Point(0, 0), Point(8, 8));
    Node a(Point(1, 1), 1);
    Node b(Point(2, 5), 2);
    Node c(Point(7, 6), 3);
    center.insert(&a);
    center.insert(&b);
    center.insert(&c);
    cout << "Node a: " <<
        center.search(Point(1, 1))->data << "\n";
    cout << "Node b: " <<
        center.search(Point(2, 5))->data << "\n";
    cout << "Node c: " <<
        center.search(Point(7, 6))->data << "\n";
    cout << "Non-existing node: "
        << center.search(Point(5, 5));
    return 0;
}

输出:

Node a: 1
Node b: 2
Node c: 3
Non-existing node: 0

锻炼:
实现四叉树,该四叉树将4个最接近的节点返回给定点。

其他参考:
http://jimkang.com/quadtreevis/
https://zh.wikipedia.org/wiki/四树