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

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

四叉树索引的基本思想是将地理空间递归划分为不同层次的树结构。它将已知范围的空间等分成四个相等的子空间,如此递归下去,直至树的层次达到一定深度或者满足某种要求后停止分割。四叉树的结构比较简单,并且当空间数据对象分布比较均匀时,具有比较高的空间数据插入和查询效率,因此四叉树是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语言实现版本代码。

头文件如下:

 

 

[cpp] view plain copy
 
  1. #ifndef __QUADTREE_H_59CAE94A_E937_42AD_AA27_794E467715BB__  
  2. #define __QUADTREE_H_59CAE94A_E937_42AD_AA27_794E467715BB__  
  3.   
  4.   
  5.   
  6.   
  7. /* 一个矩形区域的象限划分:: 
  8.  
  9. UL(1)   |    UR(0) 
  10. ----------|----------- 
  11. LL(2)   |    LR(3) 
  12. 以下对该象限类型的枚举 
  13. */  
  14. typedef enum  
  15. {  
  16.     UR = 0,  
  17.     UL = 1,  
  18.     LL = 2,  
  19.     LR = 3  
  20. }QuadrantEnum;  
  21.   
  22. /*空间对象MBR信息*/  
  23. typedef struct SHPMBRInfo  
  24. {  
  25.     int nID;        //空间对象ID号  
  26.     MapRect Box;    //空间对象MBR范围坐标  
  27. }SHPMBRInfo;  
  28.   
  29. /* 四叉树节点类型结构 */  
  30. typedef struct QuadNode  
  31. {  
  32.     MapRect     Box;            //节点所代表的矩形区域  
  33.     int         nShpCount;      //节点所包含的所有空间对象个数  
  34.     SHPMBRInfo* pShapeObj;      //空间对象指针数组  
  35.     int     nChildCount;        //子节点个数  
  36.     QuadNode  *children[4];     //指向节点的四个孩子   
  37. }QuadNode;  
  38.   
  39. /* 四叉树类型结构 */  
  40. typedef struct quadtree_t  
  41. {  
  42.     QuadNode  *root;  
  43.     int         depth;           // 四叉树的深度                      
  44. }QuadTree;  
  45.   
  46.   
  47.     //初始化四叉树节点  
  48.     QuadNode *InitQuadNode();  
  49.   
  50.     //层次创建四叉树方法(满四叉树)  
  51.     void CreateQuadTree(int depth,GeoLayer *poLayer,QuadTree* pQuadTree);  
  52.   
  53.     //创建各个分支  
  54.     void CreateQuadBranch(int depth,MapRect &rect,QuadNode** node);  
  55.   
  56.     //构建四叉树空间索引  
  57.     void BuildQuadTree(GeoLayer*poLayer,QuadTree* pQuadTree);  
  58.   
  59.     //四叉树索引查询(矩形查询)  
  60.     void SearchQuadTree(QuadNode* node,MapRect &queryRect,vector<int>& ItemSearched);  
  61.   
  62.     //四叉树索引查询(矩形查询)并行查询  
  63.     void SearchQuadTreePara(vector<QuadNode*> resNodes,MapRect &queryRect,vector<int>& ItemSearched);  
  64.   
  65.     //四叉树的查询(点查询)  
  66.     void PtSearchQTree(QuadNode* node,double cx,double cy,vector<int>& ItemSearched);  
  67.   
  68.     //将指定的空间对象插入到四叉树中  
  69.     void Insert(long key,MapRect &itemRect,QuadNode* pNode);  
  70.   
  71.     //将指定的空间对象插入到四叉树中  
  72.     void InsertQuad(long key,MapRect &itemRect,QuadNode* pNode);  
  73.   
  74.     //将指定的空间对象插入到四叉树中  
  75.     void InsertQuad2(long key,MapRect &itemRect,QuadNode* pNode);  
  76.   
  77.     //判断一个节点是否是叶子节点  
  78.     bool IsQuadLeaf(QuadNode* node);  
  79.   
  80.     //删除多余的节点  
  81.     bool DelFalseNode(QuadNode* node);  
  82.   
  83.     //四叉树遍历(所有要素)  
  84.     void TraversalQuadTree(QuadNode* quadTree,vector<int>& resVec);  
  85.   
  86.     //四叉树遍历(所有节点)  
  87.     void TraversalQuadTree(QuadNode* quadTree,vector<QuadNode*>& arrNode);  
  88.   
  89.     //释放树的内存空间  
  90.     void ReleaseQuadTree(QuadNode** quadTree);  
  91.   
  92.     //计算四叉树所占的字节的大小  
  93.     long CalByteQuadTree(QuadNode* quadTree,long& nSize);  
  94.   
  95.   
  96. #endif  



 

 

from: http://blog.csdn.NET/zhouxuguang236/article/details/12312099

posted @ 2017-06-13 14:30  不会就问咯  阅读(1105)  评论(0编辑  收藏  举报