四叉树空间索引原理及其实现

今天依然在放假中,在此将以前在学校写的四叉树的东西拿出来和大家分享。

四叉树索引的基本思想是将地理空间递归划分为不同层次的树结构。它将已知范围的空间等分成四个相等的子空间,如此递归下去,直至树的层次达到一定深度或者满足某种要求后停止分割。四叉树的结构比较简单,并且当空间数据对象分布比较均匀时,具有比较高的空间数据插入和查询效率,因此四叉树是GIS中常用的空间索引之一。常规四叉树的结构如图所示,地理空间对象都存储在叶子节点上,中间节点以及根节点不存储地理空间对象。

四叉树示意图

四叉树对于区域查询,效率比较高。但如果空间对象分布不均匀,随着地理空间对象的不断插入,四叉树的层次会不断地加深,将形成一棵严重不平衡的四叉树,那么每次查询的深度将大大的增多,从而导致查询效率的急剧下降。

本节将介绍一种改进的四叉树索引结构。四叉树结构是自顶向下逐步划分的一种树状的层次结构。传统的四叉树索引存在着以下几个缺点:

(1)空间实体只能存储在叶子节点中,中间节点以及根节点不能存储空间实体信息,随着空间对象的不断插入,最终会导致四叉树树的层次比较深,在进行空间数据窗口查询的时候效率会比较低下。

(2)同一个地理实体在四叉树的分裂过程中极有可能存储在多个节点中,这样就导致了索引存储空间的浪费。

(3)由于地理空间对象可能分布不均衡,这样会导致常规四叉树生成一棵极为不平衡的树,这样也会造成树结构的不平衡以及存储空间的浪费。

相应的改进方法,将地理实体信息存储在完全包含它的最小矩形节点中,不存储在它的父节点中,每个地理实体只在树中存储一次,避免存储空间的浪费。首先生成满四叉树,避免在地理实体插入时需要重新分配内存,加快插入的速度,最后将空的节点所占内存空间释放掉。改进后的四叉树结构如下图所示。四叉树的深度一般取经验值4-7之间为最佳。

图改进的四叉树结构

为了维护空间索引与对存储在文件或数据库中的空间数据的一致性,作者设计了如下的数据结构支持四叉树的操作。

(1)四分区域标识

分别定义了一个平面区域的四个子区域索引号,右上为第一象限0,左上为第二象限1,左下为第三象限2,右下为第四象限3。

typedef enum

{

UR = 0,// UR第一象限

UL = 1, // UL为第二象限

LL = 2, // LL为第三象限

LR = 3  // LR为第四象限

}QuadrantEnum;

(2)空间对象数据结构

空间对象数据结构是对地理空间对象的近似,在空间索引中,相当一部分都是采用MBR作为近似。

/*空间对象MBR信息*/

typedef struct SHPMBRInfo

{

int nID;       //空间对象ID号

MapRect Box;    //空间对象MBR范围坐标

}SHPMBRInfo;

nID是空间对象的标识号,Box是空间对象的最小外包矩形(MBR)。

(3)四叉树节点数据结构

四叉树节点是四叉树结构的主要组成部分,主要用于存储空间对象的标识号和MBR,也是四叉树算法操作的主要部分。

/*四叉树节点类型结构*/

typedef struct QuadNode

{

MapRect            Box;                   //节点所代表的矩形区域

int                nShpCount;        //节点所包含的所有空间对象个数

SHPMBRInfo* pShapeObj;          //空间对象指针数组

int         nChildCount;            //子节点个数

QuadNode *children[4];             //指向节点的四个孩子

}QuadNode;

Box是代表四叉树对应区域的最小外包矩形,上一层的节点的最小外包矩形包含下一层最小外包矩形区域;nShpCount代表本节点包含的空间对象的个数;pShapeObj代表指向空间对象存储地址的首地址,同一个节点的空间对象在内存中连续存储;nChildCount代表节点拥有的子节点的数目;children是指向孩子节点指针的数组。

上述理论部分都都讲的差不多了,下面就贴上我的C语言实现版本代码。

头文件如下:

#ifndef __QUADTREE_H_59CAE94A_E937_42AD_AA27_794E467715BB__
#define __QUADTREE_H_59CAE94A_E937_42AD_AA27_794E467715BB__

/* 一个矩形区域的象限划分::

UL(1)   |    UR(0)
----------|-----------
LL(2)   |    LR(3)
以下对该象限类型的枚举
*/
typedef enum
{
    UR = 0,
    UL = 1,
    LL = 2,
    LR = 3
}QuadrantEnum;

/*空间对象MBR信息*/
typedef struct SHPMBRInfo
{
    int nID;        //空间对象ID号
    MapRect Box;    //空间对象MBR范围坐标
}SHPMBRInfo;

/* 四叉树节点类型结构 */
typedef struct QuadNode
{
    MapRect        Box;            //节点所代表的矩形区域
    int            nShpCount;        //节点所包含的所有空间对象个数
    SHPMBRInfo* pShapeObj;        //空间对象指针数组
    int        nChildCount;        //子节点个数
    QuadNode  *children[4];        //指向节点的四个孩子
}QuadNode;

/* 四叉树类型结构 */
typedef struct quadtree_t
{
    QuadNode  *root;
    int         depth;           // 四叉树的深度
}QuadTree;

    //初始化四叉树节点
    QuadNode *InitQuadNode();

    //层次创建四叉树方法(满四叉树)
    void CreateQuadTree(int depth,GeoLayer *poLayer,QuadTree* pQuadTree);

    //创建各个分支
    void CreateQuadBranch(int depth,MapRect &rect,QuadNode** node);

    //构建四叉树空间索引
    void BuildQuadTree(GeoLayer*poLayer,QuadTree* pQuadTree);

    //四叉树索引查询(矩形查询)
    void SearchQuadTree(QuadNode* node,MapRect &queryRect,vector<int>& ItemSearched);

    //四叉树索引查询(矩形查询)并行查询
    void SearchQuadTreePara(vector<QuadNode*> resNodes,MapRect &queryRect,vector<int>& ItemSearched);

    //四叉树的查询(点查询)
    void PtSearchQTree(QuadNode* node,double cx,double cy,vector<int>& ItemSearched);

    //将指定的空间对象插入到四叉树中
    void Insert(long key,MapRect &itemRect,QuadNode* pNode);

    //将指定的空间对象插入到四叉树中
    void InsertQuad(long key,MapRect &itemRect,QuadNode* pNode);

    //将指定的空间对象插入到四叉树中
    void InsertQuad2(long key,MapRect &itemRect,QuadNode* pNode);

    //判断一个节点是否是叶子节点
    bool IsQuadLeaf(QuadNode* node);

    //删除多余的节点
    bool DelFalseNode(QuadNode* node);

    //四叉树遍历(所有要素)
    void TraversalQuadTree(QuadNode* quadTree,vector<int>& resVec);

    //四叉树遍历(所有节点)
    void TraversalQuadTree(QuadNode* quadTree,vector<QuadNode*>& arrNode);

    //释放树的内存空间
    void ReleaseQuadTree(QuadNode** quadTree);

    //计算四叉树所占的字节的大小
    long CalByteQuadTree(QuadNode* quadTree,long& nSize);

#endif

源文件如下:

#include "QuadTree.h"

QuadNode *InitQuadNode()
{
    QuadNode *node = new QuadNode;
    node->Box.maxX = 0;
    node->Box.maxY = 0;
    node->Box.minX = 0;
    node->Box.minY = 0;

    for (int i = 0; i < 4; i ++)
    {
        node->children[i] = NULL;
    }
    node->nChildCount = 0;
    node->nShpCount = 0;
    node->pShapeObj = NULL;

    return node;
}

void CreateQuadTree(int depth,GeoLayer *poLayer,QuadTree* pQuadTree)
{
    pQuadTree->depth = depth;

    GeoEnvelope env;    //整个图层的MBR
    poLayer->GetExtent(&env);

    MapRect rect;
    rect.minX = env.MinX;
    rect.minY = env.MinY;
    rect.maxX = env.MaxX;
    rect.maxY = env.MaxY;

    //创建各个分支
    CreateQuadBranch(depth,rect,&(pQuadTree->root));

    int nCount = poLayer->GetFeatureCount();
    GeoFeature **pFeatureClass = new GeoFeature*[nCount];
    for (int i = 0; i < poLayer->GetFeatureCount(); i ++)
    {
        pFeatureClass[i] = poLayer->GetFeature(i);
    }

    //插入各个要素
    GeoEnvelope envObj;    //空间对象的MBR
    //#pragma omp parallel for
    for (int i = 0; i < nCount; i ++)
    {
        pFeatureClass[i]->GetGeometry()->getEnvelope(&envObj);
        rect.minX = envObj.MinX;
        rect.minY = envObj.MinY;
        rect.maxX = envObj.MaxX;
        rect.maxY = envObj.MaxY;
        InsertQuad(i,rect,pQuadTree->root);
    }

    //DelFalseNode(pQuadTree->root);
}

void CreateQuadBranch(int depth,MapRect &rect,QuadNode** node)
{
    if (depth != 0)
    {
        *node = InitQuadNode();    //创建树根
        QuadNode *pNode = *node;
        pNode->Box = rect;
        pNode->nChildCount = 4;

        MapRect boxs[4];
        pNode->Box.Split(boxs,boxs+1,boxs+2,boxs+3);
        for (int i = 0; i < 4; i ++)
        {
            //创建四个节点并插入相应的MBR
            pNode->children[i] = InitQuadNode();
            pNode->children[i]->Box = boxs[i];

            CreateQuadBranch(depth-1,boxs[i],&(pNode->children[i]));
        }
    }
}

void BuildQuadTree(GeoLayer *poLayer,QuadTree* pQuadTree)
{
    assert(poLayer);
    GeoEnvelope env;    //整个图层的MBR
    poLayer->GetExtent(&env);
    pQuadTree->root = InitQuadNode();

    QuadNode* rootNode = pQuadTree->root;

    rootNode->Box.minX = env.MinX;
    rootNode->Box.minY = env.MinY;
    rootNode->Box.maxX = env.MaxX;
    rootNode->Box.maxY = env.MaxY;

    //设置树的深度(    根据等比数列的求和公式)
    //pQuadTree->depth = log(poLayer->GetFeatureCount()*3/8.0+1)/log(4.0);
    int nCount = poLayer->GetFeatureCount();

    MapRect rect;
    GeoEnvelope envObj;    //空间对象的MBR
    for (int i = 0; i < nCount; i ++)
    {
        poLayer->GetFeature(i)->GetGeometry()->getEnvelope(&envObj);
        rect.minX = envObj.MinX;
        rect.minY = envObj.MinY;
        rect.maxX = envObj.MaxX;
        rect.maxY = envObj.MaxY;
        InsertQuad2(i,rect,rootNode);
    }

    DelFalseNode(pQuadTree->root);
}

void SearchQuadTree(QuadNode* node,MapRect &queryRect,vector<int>& ItemSearched)
{
    assert(node);

    //int coreNum = omp_get_num_procs();
    //vector<int> * pResArr = new vector<int>[coreNum];

    if (NULL != node)
    {
        for (int i = 0; i < node->nShpCount; i ++)
        {
            if (queryRect.Contains(node->pShapeObj[i].Box)
                || queryRect.Intersects(node->pShapeObj[i].Box))
            {
                ItemSearched.push_back(node->pShapeObj[i].nID);
            }
        }

        //并行搜索四个孩子节点
        /*#pragma omp parallel sections
        {
            #pragma omp section
            if ((node->children[0] != NULL) &&
                (node->children[0]->Box.Contains(queryRect)
                || node->children[0]->Box.Intersects(queryRect)))
            {
                int tid = omp_get_thread_num();
                SearchQuadTree(node->children[0],queryRect,pResArr[tid]);
            }

            #pragma omp section
            if ((node->children[1] != NULL) &&
                (node->children[1]->Box.Contains(queryRect)
                || node->children[1]->Box.Intersects(queryRect)))
            {
                int tid = omp_get_thread_num();
                SearchQuadTree(node->children[1],queryRect,pResArr[tid]);
            }

            #pragma omp section
            if ((node->children[2] != NULL) &&
                (node->children[2]->Box.Contains(queryRect)
                || node->children[2]->Box.Intersects(queryRect)))
            {
                int tid = omp_get_thread_num();
                SearchQuadTree(node->children[2],queryRect,pResArr[tid]);
            }

            #pragma omp section
            if ((node->children[3] != NULL) &&
                (node->children[3]->Box.Contains(queryRect)
                || node->children[3]->Box.Intersects(queryRect)))
            {
                int tid = omp_get_thread_num();
                SearchQuadTree(node->children[3],queryRect,pResArr[tid]);
            }
        }*/
        for (int i = 0; i < 4; i ++)
        {
            if ((node->children[i] != NULL) &&
                (node->children[i]->Box.Contains(queryRect)
                || node->children[i]->Box.Intersects(queryRect)))
            {
                SearchQuadTree(node->children[i],queryRect,ItemSearched);
                //node = node->children[i];    //非递归
            }
        }
    }

    /*for (int i = 0 ; i < coreNum; i ++)
    {
        ItemSearched.insert(ItemSearched.end(),pResArr[i].begin(),pResArr[i].end());
    }*/

}

void SearchQuadTreePara(vector<QuadNode*> resNodes,MapRect &queryRect,vector<int>& ItemSearched)
{
    int coreNum = omp_get_num_procs();
    omp_set_num_threads(coreNum);
    vector<int>* searchArrs = new vector<int>[coreNum];
    for (int i = 0; i < coreNum; i ++)
    {
        searchArrs[i].clear();
    }

    #pragma omp parallel for
    for (int i = 0; i < resNodes.size(); i ++)
    {
        int tid = omp_get_thread_num();
        for (int j = 0; j < resNodes[i]->nShpCount; j ++)
        {
            if (queryRect.Contains(resNodes[i]->pShapeObj[j].Box)
                || queryRect.Intersects(resNodes[i]->pShapeObj[j].Box))
            {
                searchArrs[tid].push_back(resNodes[i]->pShapeObj[j].nID);
            }
        }
    }

    for (int i = 0; i < coreNum; i ++)
    {
        ItemSearched.insert(ItemSearched.end(),
            searchArrs[i].begin(),searchArrs[i].end());
    }

    delete [] searchArrs;
    searchArrs = NULL;
}

void PtSearchQTree(QuadNode* node,double cx,double cy,vector<int>& ItemSearched)
{
    assert(node);
    if (node->nShpCount >0)        //节点
    {
        for (int i = 0; i < node->nShpCount; i ++)
        {
            if (node->pShapeObj[i].Box.IsPointInRect(cx,cy))
            {
                ItemSearched.push_back(node->pShapeObj[i].nID);
            }
        }
    }

    else if (node->nChildCount >0)                //节点
    {
        for (int i = 0; i < 4; i ++)
        {
            if (node->children[i]->Box.IsPointInRect(cx,cy))
            {
                PtSearchQTree(node->children[i],cx,cy,ItemSearched);
            }
        }
    }

    //找出重复元素的位置
    sort(ItemSearched.begin(),ItemSearched.end());    //先排序,默认升序
    vector<int>::iterator unique_iter =
        unique(ItemSearched.begin(),ItemSearched.end());
    ItemSearched.erase(unique_iter,ItemSearched.end());
}

void Insert(long key, MapRect &itemRect,QuadNode* pNode)
{
    QuadNode *node = pNode;        //保留根节点副本
    SHPMBRInfo pShpInfo;

    //节点有孩子
    if (0 < node->nChildCount)
    {
        for (int i = 0; i < 4; i ++)
        {
            //如果包含或相交,则将节点插入到此节点
            if (node->children[i]->Box.Contains(itemRect)
                || node->children[i]->Box.Intersects(itemRect))
            {
                //node = node->children[i];
                Insert(key,itemRect,node->children[i]);
            }
        }
    }

    //如果当前节点存在一个子节点时
    else if (1 == node->nShpCount)
    {
        MapRect boxs[4];
        node->Box.Split(boxs,boxs+1,boxs+2,boxs+3);

        //创建四个节点并插入相应的MBR
        node->children[UR] = InitQuadNode();
        node->children[UL] = InitQuadNode();
        node->children[LL] = InitQuadNode();
        node->children[LR] = InitQuadNode();

        node->children[UR]->Box = boxs[0];
        node->children[UL]->Box = boxs[1];
        node->children[LL]->Box = boxs[2];
        node->children[LR]->Box = boxs[3];
        node->nChildCount = 4;

        for (int i = 0; i < 4; i ++)
        {
            //将当前节点中的要素移动到相应的子节点中
            for (int j = 0; j < node->nShpCount; j ++)
            {
                if (node->children[i]->Box.Contains(node->pShapeObj[j].Box)
                    || node->children[i]->Box.Intersects(node->pShapeObj[j].Box))
                {
                    node->children[i]->nShpCount += 1;
                    node->children[i]->pShapeObj =
                        (SHPMBRInfo*)malloc(node->children[i]->nShpCount*sizeof(SHPMBRInfo));

                    memcpy(node->children[i]->pShapeObj,&(node->pShapeObj[j]),sizeof(SHPMBRInfo));

                    free(node->pShapeObj);
                    node->pShapeObj = NULL;
                    node->nShpCount = 0;
                }
            }
        }

        for (int i = 0; i < 4; i ++)
        {
            //如果包含或相交,则将节点插入到此节点
            if (node->children[i]->Box.Contains(itemRect)
                || node->children[i]->Box.Intersects(itemRect))
            {
                if (node->children[i]->nShpCount == 0)     //如果之前没有节点
                {
                    node->children[i]->nShpCount += 1;
                    node->pShapeObj =
                        (SHPMBRInfo*)malloc(sizeof(SHPMBRInfo)*node->children[i]->nShpCount);
                }
                else if    (node->children[i]->nShpCount > 0)
                {
                    node->children[i]->nShpCount += 1;
                    node->children[i]->pShapeObj =
                        (SHPMBRInfo *)realloc(node->children[i]->pShapeObj,
                        sizeof(SHPMBRInfo)*node->children[i]->nShpCount);
                }

                pShpInfo.Box = itemRect;
                pShpInfo.nID = key;
                memcpy(node->children[i]->pShapeObj,
                    &pShpInfo,sizeof(SHPMBRInfo));
            }
        }
    }

    //当前节点没有空间对象
    else if (0 == node->nShpCount)
    {
        node->nShpCount += 1;
        node->pShapeObj =
            (SHPMBRInfo*)malloc(sizeof(SHPMBRInfo)*node->nShpCount);

        pShpInfo.Box = itemRect;
        pShpInfo.nID = key;
        memcpy(node->pShapeObj,&pShpInfo,sizeof(SHPMBRInfo));
    }
}

void InsertQuad(long key,MapRect &itemRect,QuadNode* pNode)
{
    assert(pNode != NULL);

    if (!IsQuadLeaf(pNode))       //非叶子节点
    {
        int nCorver = 0;        //跨越的子节点个数
        int iIndex = -1;        //被哪个子节点完全包含的索引号
        for (int i = 0; i < 4; i ++)
        {
            if (pNode->children[i]->Box.Contains(itemRect)
                && pNode->Box.Contains(itemRect))
            {
                nCorver += 1;
                iIndex = i;
            }
        }

        //如果被某一个子节点包含,则进入该子节点
        if (/*pNode->Box.Contains(itemRect) ||
            pNode->Box.Intersects(itemRect)*/1 <= nCorver)
        {
            InsertQuad(key,itemRect,pNode->children[iIndex]);
        }

        //如果跨越了多个子节点,直接放在这个节点中
        else if (nCorver == 0)
        {
            if (pNode->nShpCount == 0)     //如果之前没有节点
            {
                pNode->nShpCount += 1;
                pNode->pShapeObj =
                    (SHPMBRInfo*)malloc(sizeof(SHPMBRInfo)*pNode->nShpCount);
            }
            else
            {
                pNode->nShpCount += 1;
                pNode->pShapeObj =
                    (SHPMBRInfo *)realloc(pNode->pShapeObj,sizeof(SHPMBRInfo)*pNode->nShpCount);
            }

            SHPMBRInfo pShpInfo;
            pShpInfo.Box = itemRect;
            pShpInfo.nID = key;
            memcpy(pNode->pShapeObj+pNode->nShpCount-1,&pShpInfo,sizeof(SHPMBRInfo));
        }
    }

    //如果是叶子节点,直接放进去
    else if (IsQuadLeaf(pNode))
    {
        if (pNode->nShpCount == 0)     //如果之前没有节点
        {
            pNode->nShpCount += 1;
            pNode->pShapeObj =
                (SHPMBRInfo*)malloc(sizeof(SHPMBRInfo)*pNode->nShpCount);
        }
        else
        {
            pNode->nShpCount += 1;
            pNode->pShapeObj =
                (SHPMBRInfo *)realloc(pNode->pShapeObj,sizeof(SHPMBRInfo)*pNode->nShpCount);
        }

        SHPMBRInfo pShpInfo;
        pShpInfo.Box = itemRect;
        pShpInfo.nID = key;
        memcpy(pNode->pShapeObj+pNode->nShpCount-1,&pShpInfo,sizeof(SHPMBRInfo));
    }
}

void InsertQuad2(long key,MapRect &itemRect,QuadNode* pNode)
{
    QuadNode *node = pNode;        //保留根节点副本
    SHPMBRInfo pShpInfo;

    //节点有孩子
    if (0 < node->nChildCount)
    {
        for (int i = 0; i < 4; i ++)
        {
            //如果包含或相交,则将节点插入到此节点
            if (node->children[i]->Box.Contains(itemRect)
                || node->children[i]->Box.Intersects(itemRect))
            {
                //node = node->children[i];
                Insert(key,itemRect,node->children[i]);
            }
        }
    }

    //如果当前节点存在一个子节点时
    else if (0 == node->nChildCount)
    {
        MapRect boxs[4];
        node->Box.Split(boxs,boxs+1,boxs+2,boxs+3);

        int cnt = -1;
        for (int i = 0; i < 4; i ++)
        {
            //如果包含或相交,则将节点插入到此节点
            if (boxs[i].Contains(itemRect))
            {
                cnt = i;
            }
        }

        //如果有一个矩形包含此对象,则创建四个孩子节点
        if (cnt > -1)
        {
            for (int i = 0; i < 4; i ++)
            {
                //创建四个节点并插入相应的MBR
                node->children[i] = InitQuadNode();
                node->children[i]->Box = boxs[i];
            }
            node->nChildCount = 4;
            InsertQuad2(key,itemRect,node->children[cnt]);    //递归
        }

        //如果都不包含,则直接将对象插入此节点
        if (cnt == -1)
        {
            if (node->nShpCount == 0)     //如果之前没有节点
            {
                node->nShpCount += 1;
                node->pShapeObj =
                    (SHPMBRInfo*)malloc(sizeof(SHPMBRInfo)*node->nShpCount);
            }
            else if    (node->nShpCount > 0)
            {
                node->nShpCount += 1;
                node->pShapeObj =
                    (SHPMBRInfo *)realloc(node->pShapeObj,
                    sizeof(SHPMBRInfo)*node->nShpCount);
            }

            pShpInfo.Box = itemRect;
            pShpInfo.nID = key;
            memcpy(node->pShapeObj,
                &pShpInfo,sizeof(SHPMBRInfo));
        }
    }

    //当前节点没有空间对象
    /*else if (0 == node->nShpCount)
    {
        node->nShpCount += 1;
        node->pShapeObj =
            (SHPMBRInfo*)malloc(sizeof(SHPMBRInfo)*node->nShpCount);

        pShpInfo.Box = itemRect;
        pShpInfo.nID = key;
        memcpy(node->pShapeObj,&pShpInfo,sizeof(SHPMBRInfo));
    }*/
}

bool IsQuadLeaf(QuadNode* node)
{
    if (NULL == node)
    {
        return 1;
    }
    for (int i = 0; i < 4; i ++)
    {
        if (node->children[i] != NULL)
        {
            return 0;
        }
    }

    return 1;
}

bool DelFalseNode(QuadNode* node)
{
    //如果没有子节点且没有要素
    if (node->nChildCount ==0 && node->nShpCount == 0)
    {
        ReleaseQuadTree(&node);
    }

    //如果有子节点
    else if (node->nChildCount > 0)
    {
        for (int i = 0; i < 4; i ++)
        {
            DelFalseNode(node->children[i]);
        }
    }

    return 1;
}

void TraversalQuadTree(QuadNode* quadTree,vector<int>& resVec)
{
    QuadNode *node = quadTree;
    int i = 0;
    if (NULL != node)
    {
        //将本节点中的空间对象存储数组中
        for (i = 0; i < node->nShpCount; i ++)
        {
            resVec.push_back((node->pShapeObj+i)->nID);
        }

        //遍历孩子节点
        for (i = 0; i < node->nChildCount; i ++)
        {
            if (node->children[i] != NULL)
            {
                TraversalQuadTree(node->children[i],resVec);
            }
        }
    }

}

void TraversalQuadTree(QuadNode* quadTree,vector<QuadNode*>& arrNode)
{
    deque<QuadNode*> nodeQueue;
    if (quadTree != NULL)
    {
        nodeQueue.push_back(quadTree);
        while (!nodeQueue.empty())
        {
            QuadNode* queueHead = nodeQueue.at(0);    //取队列头结点
            arrNode.push_back(queueHead);
            nodeQueue.pop_front();
            for (int i = 0; i < 4; i ++)
            {
                if (queueHead->children[i] != NULL)
                {
                    nodeQueue.push_back(queueHead->children[i]);
                }
            }
        }
    }
}

void ReleaseQuadTree(QuadNode** quadTree)
{
    int i = 0;
    QuadNode* node = *quadTree;
    if (NULL == node)
    {
        return;
    }

    else
    {
        for (i = 0; i < 4; i ++)
        {
            ReleaseQuadTree(&node->children[i]);
        }
        free(node);
        node = NULL;
    }

    node = NULL;
}

long CalByteQuadTree(QuadNode* quadTree,long& nSize)
{
    if (quadTree != NULL)
    {
        nSize += sizeof(QuadNode)+quadTree->nChildCount*sizeof(SHPMBRInfo);
        for (int i = 0; i < 4; i ++)
        {
            if (quadTree->children[i] != NULL)
            {
                nSize += CalByteQuadTree(quadTree->children[i],nSize);
            }
        }
    }

    return 1;
}

代码有点长,有需要的朋友可以借鉴并自己优化。

原文链接:四叉树空间索引原理及其实现

时间: 2025-01-23 21:00:56

四叉树空间索引原理及其实现的相关文章

四叉树算法原理与实现

一.原理 四叉树编码的基本思想是:首先将把一副图像或栅格地图( ,k>1,不足则补网)等分成四个一级字块,顺序为左上,右上,左下,右下:然后逐块检查其中所有格网属性值(或灰度值),若相同,则该字块不再分:若不同,则将该子块进一步分成四个二级子块:如此递归地分割,直到每个子块的属性或灰度均相等为止. 二.算法实现 1 //实现四叉树编码 2 3 #include"stdio.h" 4 void Qutree(int arysize,int level,float curary[]

基于空间误差同质区的矢量电子地图快速纠偏算法 Fast Map Rectification Algorithm Based on Spatial Error Homogeneous Region

作 者:蔡文婷刘正坤CAI Wen-tingLIU Zheng-kun(Dingxin Information Technology Co.Ltd,Guangzhou 510623Guangdong Electric Power Design Institute Co.Ltd of China Energy Engineering Group,Guangzhou 510663,China) 作者机构:[1]鼎信信息科技有限责任公司,广东广州510623;[2]中国能源建设集团广东省电力设计研究院

[地图开发][算法及数据结构]四叉树原理

参考:http://blog.csdn.net/zhouxuguang236/article/details/12312099 原博客地址还有c++源码... 四叉树索引的基本思想是将地理空间递归划分为不同层次的树结构.它将已知范围的空间等分成四个相等的子空间,如此递归下去,直至树的层次达到一定深度或者满足某种要求后停止分割.四叉树的结构比较简单,并且当空间数据对象分布比较均匀时,具有比较高的空间数据插入和查询效率,因此四叉树是GIS中常用的空间索引之一.常规四叉树的结构如图所示,地理空间对象都

空间索引 - GeoHash算法及其实现优化

h1,h2,h3,h4,h5,h6,p,blockquote { margin: 0; padding: 0 } body { font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif; font-size: 13px; line-height: 18px; color: #737373; background-color: white; margin: 10px

空间索引 - 各数据库空间索引使用报告

h1,h2,h3,h4,h5,h6,p,blockquote { margin: 0; padding: 0 } body { font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif; font-size: 13px; line-height: 18px; color: #737373; background-color: white; margin: 10px

深入浅出空间索引:2

http://www.cnblogs.com/LBSer/p/3403933.html 深入浅出空间索引2 第一篇讲到了传统的索引如B树不能很好的支持空间数据,比如点(POI等).线(道路.河流等).面(行政边界.住宅区等).本篇将对空间索引进行简单分类,然后介绍网格索引.(深入浅出空间索引1:http://www.cnblogs.com/LBSer/p/3392491.html) 一.空间索引有哪几种? 传统索引使用哈希和树这两类最基本的数据结构.空间索引虽然更为复杂,但仍然发展于这两种数据结

GeoHash原理和可视化显示

最近在做附近定位功能的产品,geohash是一个非常不错的实现方式.查询资料,发现阿里的这篇文章讲解的很好.但文中并没有给出geohash显示的工具.无奈,也没有查到类似的.只好自己简单显示一下,方便自己理解. 项目地址:  https://github.com/Ryan-Miao/geohash-visualization geohash可视化显示 经纬度获取9宫格覆盖: https://ryan-miao.github.io/geohash-visualization/index.html

mysql之索引原理与慢查询优化

一.介绍 1.什么是索引? 一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,在生产环境中,我们遇到最多的,也是最容易出问题的,还是一些复杂的查询操作,因此对查询语句的优化显然是重中之重.说起加速查询,就不得不提到索引了. 2.为什么要有索引呢? 索引在MySQL中也叫做"键",是存储引擎用于快速找到记录的一种数据结构.索引对于良好的性能非常关键,尤其是当表中的数据量越来越大时,索引对于性能的影响愈发重要.索引优化应该是对查询性能优化最有效的手段了.

BNUOJ 4049 四叉树

四叉树 Time Limit: 1000ms Memory Limit: 65536KB 64-bit integer IO format: %lld      Java class name: Main 四叉树是一种常用的数据结构,广泛应用于栅格数据(如地图数据.遥感图像)的压缩编码中.将四叉树扩展到三维就形成了八叉树,可实现三维信息的压缩存储.下面是它的实现原理: 如图是一个8*8图象,如果该图像所有元素都一样(都是0或都是1),就编码为0,再加上公共一样的元素(如01或00).如果不一样,