四叉树索引的基本思想是将地理空间递归划分为不同层次的树结构。它将已知范围的空间等分成四个相等的子空间,如此递归下去,直至树的层次达到一定深度或者满足某种要求后停止分割。四叉树的结构比较简单,并且当空间数据对象分布比较均匀时,具有比较高的空间数据插入和查询效率,因此四叉树是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
源文件如下:
[cpp] view plain copy
1. #include "QuadTree.h"
2.
3.
4. QuadNode *InitQuadNode()
5. {
6. QuadNode *node = new QuadNode;
7. node->Box.maxX = 0;
8. node->Box.maxY = 0;
9. node->Box.minX = 0;
10. node->Box.minY = 0;
11.
12. for (int i = 0; i < 4; i ++)
13. {
14. node->children[i] = NULL;
15. }
16. node->nChildCount = 0;
17. node->nShpCount = 0;
18. node->pShapeObj = NULL;
19.
20. return node;
21. }
22.
23. void CreateQuadTree(int depth,GeoLayer *poLayer,QuadTree* pQuadTree)
24. {
25. pQuadTree->depth = depth;
26.
27. GeoEnvelope env; //整个图层的MBR
28. poLayer->GetExtent(&env);
29.
30. MapRect rect;
31. rect.minX = env.MinX;
32. rect.minY = env.MinY;
33. rect.maxX = env.MaxX;
34. rect.maxY = env.MaxY;
35.
36. //创建各个分支
37. CreateQuadBranch(depth,rect,&(pQuadTree->root));
38.
39. int nCount = poLayer->GetFeatureCount();
40. GeoFeature **pFeatureClass = new GeoFeature*[nCount];
41. for (int i = 0; i < poLayer->GetFeatureCount(); i ++)
42. {
43. pFeatureClass[i] = poLayer->GetFeature(i);
44. }
45.
46. //插入各个要素
47. GeoEnvelope envObj; //空间对象的MBR
48. //#pragma omp parallel for
49. for (int i = 0; i < nCount; i ++)
50. {
51. pFeatureClass[i]->GetGeometry()->getEnvelope(&envObj);
52. rect.minX = envObj.MinX;
53. rect.minY = envObj.MinY;
54. rect.maxX = envObj.MaxX;
55. rect.maxY = envObj.MaxY;
56. InsertQuad(i,rect,pQuadTree->root);
57. }
58.
59. //DelFalseNode(pQuadTree->root);
60. }
61.
62. void CreateQuadBranch(int depth,MapRect &rect,QuadNode** node)
63. {
64. if (depth != 0)
65. {
66. *node = InitQuadNode(); //创建树根
67. QuadNode *pNode = *node;
68. pNode->Box = rect;
69. pNode->nChildCount = 4;
70.
71. MapRect boxs[4];
72. pNode->Box.Split(boxs,boxs+1,boxs+2,boxs+3);
73. for (int i = 0; i < 4; i ++)
74. {
75. //创建四个节点并插入相应的MBR
76. pNode->children[i] = InitQuadNode();
77. pNode->children[i]->Box = boxs[i];
78.
79. CreateQuadBranch(depth-1,boxs[i],&(pNode->children[i]));
80. }
81. }
82. }
83.
84. void BuildQuadTree(GeoLayer *poLayer,QuadTree* pQuadTree)
85. {
86. assert(poLayer);
87. GeoEnvelope env; //整个图层的MBR
88. poLayer->GetExtent(&env);
89. pQuadTree->root = InitQuadNode();
90.
91. QuadNode* rootNode = pQuadTree->root;
92.
93. rootNode->Box.minX = env.MinX;
94. rootNode->Box.minY = env.MinY;
95. rootNode->Box.maxX = env.MaxX;
96. rootNode->Box.maxY = env.MaxY;
97.
98. //设置树的深度( 根据等比数列的求和公式)
99. //pQuadTree->depth = log(poLayer->GetFeatureCount()*3/8.0+1)/log(4.0);
100. int nCount = poLayer->GetFeatureCount();
101.
102. MapRect rect;
103. GeoEnvelope envObj; //空间对象的MBR
104. for (int i = 0; i < nCount; i ++)
105. {
106. poLayer->GetFeature(i)->GetGeometry()->getEnvelope(&envObj);
107. rect.minX = envObj.MinX;
108. rect.minY = envObj.MinY;
109. rect.maxX = envObj.MaxX;
110. rect.maxY = envObj.MaxY;
111. InsertQuad2(i,rect,rootNode);
112. }
113.
114. DelFalseNode(pQuadTree->root);
115. }
116.
117. void SearchQuadTree(QuadNode* node,MapRect &queryRect,vector<int>& ItemSearched)
118. {
119. assert(node);
120.
121. //int coreNum = omp_get_num_procs();
122. //vector<int> * pResArr = new vector<int>[coreNum];
123.
124. if (NULL != node)
125. {
126. for (int i = 0; i < node->nShpCount; i ++)
127. {
128. if (queryRect.Contains(node->pShapeObj[i].Box)
129. || queryRect.Intersects(node->pShapeObj[i].Box))
130. {
131. ItemSearched.push_back(node->pShapeObj[i].nID);
132. }
133. }
134.
135. //并行搜索四个孩子节点
136. /*#pragma omp parallel sections
137. {
138. #pragma omp section
139. if ((node->children[0] != NULL) &&
140. (node->children[0]->Box.Contains(queryRect)
141. || node->children[0]->Box.Intersects(queryRect)))
142. {
143. int tid = omp_get_thread_num();
144. SearchQuadTree(node->children[0],queryRect,pResArr[tid]);
145. }
146.
147. #pragma omp section
148. if ((node->children[1] != NULL) &&
149. (node->children[1]->Box.Contains(queryRect)
150. || node->children[1]->Box.Intersects(queryRect)))
151. {
152. int tid = omp_get_thread_num();
153. SearchQuadTree(node->children[1],queryRect,pResArr[tid]);
154. }
155.
156. #pragma omp section
157. if ((node->children[2] != NULL) &&
158. (node->children[2]->Box.Contains(queryRect)
159. || node->children[2]->Box.Intersects(queryRect)))
160. {
161. int tid = omp_get_thread_num();
162. SearchQuadTree(node->children[2],queryRect,pResArr[tid]);
163. }
164.
165. #pragma omp section
166. if ((node->children[3] != NULL) &&
167. (node->children[3]->Box.Contains(queryRect)
168. || node->children[3]->Box.Intersects(queryRect)))
169. {
170. int tid = omp_get_thread_num();
171. SearchQuadTree(node->children[3],queryRect,pResArr[tid]);
172. }
173. }*/
174. for (int i = 0; i < 4; i ++)
175. {
176. if ((node->children[i] != NULL) &&
177. (node->children[i]->Box.Contains(queryRect)
178. || node->children[i]->Box.Intersects(queryRect)))
179. {
180. SearchQuadTree(node->children[i],queryRect,ItemSearched);
181. //node = node->children[i]; //非递归
182. }
183. }
184. }
185.
186. /*for (int i = 0 ; i < coreNum; i ++)
187. {
188. ItemSearched.insert(ItemSearched.end(),pResArr[i].begin(),pResArr[i].end());
189. }*/
190.
191. }
192.
193. void SearchQuadTreePara(vector<QuadNode*> resNodes,MapRect &queryRect,vector<int>& ItemSearched)
194. {
195. int coreNum = omp_get_num_procs();
196. omp_set_num_threads(coreNum);
197. vector<int>* searchArrs = new vector<int>[coreNum];
198. for (int i = 0; i < coreNum; i ++)
199. {
200. searchArrs[i].clear();
201. }
202.
203. #pragma omp parallel for
204. for (int i = 0; i < resNodes.size(); i ++)
205. {
206. int tid = omp_get_thread_num();
207. for (int j = 0; j < resNodes[i]->nShpCount; j ++)
208. {
209. if (queryRect.Contains(resNodes[i]->pShapeObj[j].Box)
210. || queryRect.Intersects(resNodes[i]->pShapeObj[j].Box))
211. {
212. searchArrs[tid].push_back(resNodes[i]->pShapeObj[j].nID);
213. }
214. }
215. }
216.
217. for (int i = 0; i < coreNum; i ++)
218. {
219. ItemSearched.insert(ItemSearched.end(),
220. searchArrs[i].begin(),searchArrs[i].end());
221. }
222.
223. delete [] searchArrs;
224. searchArrs = NULL;
225. }
226.
227. void PtSearchQTree(QuadNode* node,double cx,double cy,vector<int>& ItemSearched)
228. {
229. assert(node);
230. if (node->nShpCount >0) //节点
231. {
232. for (int i = 0; i < node->nShpCount; i ++)
233. {
234. if (node->pShapeObj[i].Box.IsPointInRect(cx,cy))
235. {
236. ItemSearched.push_back(node->pShapeObj[i].nID);
237. }
238. }
239. }
240.
241. else if (node->nChildCount >0) //节点
242. {
243. for (int i = 0; i < 4; i ++)
244. {
245. if (node->children[i]->Box.IsPointInRect(cx,cy))
246. {
247. PtSearchQTree(node->children[i],cx,cy,ItemSearched);
248. }
249. }
250. }
251.
252. //找出重复元素的位置
253. sort(ItemSearched.begin(),ItemSearched.end()); //先排序,默认升序
254. vector<int>::iterator unique_iter =
255. unique(ItemSearched.begin(),ItemSearched.end());
256. ItemSearched.erase(unique_iter,ItemSearched.end());
257. }
258.
259. void Insert(long key, MapRect &itemRect,QuadNode* pNode)
260. {
261. QuadNode *node = pNode; //保留根节点副本
262. SHPMBRInfo pShpInfo;
263.
264. //节点有孩子
265. if (0 < node->nChildCount)
266. {
267. for (int i = 0; i < 4; i ++)
268. {
269. //如果包含或相交,则将节点插入到此节点
270. if (node->children[i]->Box.Contains(itemRect)
271. || node->children[i]->Box.Intersects(itemRect))
272. {
273. //node = node->children[i];
274. Insert(key,itemRect,node->children[i]);
275. }
276. }
277. }
278.
279. //如果当前节点存在一个子节点时
280. else if (1 == node->nShpCount)
281. {
282. MapRect boxs[4];
283. node->Box.Split(boxs,boxs+1,boxs+2,boxs+3);
284.
285. //创建四个节点并插入相应的MBR
286. node->children[UR] = InitQuadNode();
287. node->children[UL] = InitQuadNode();
288. node->children[LL] = InitQuadNode();
289. node->children[LR] = InitQuadNode();
290.
291. node->children[UR]->Box = boxs[0];
292. node->children[UL]->Box = boxs[1];
293. node->children[LL]->Box = boxs[2];
294. node->children[LR]->Box = boxs[3];
295. node->nChildCount = 4;
296.
297. for (int i = 0; i < 4; i ++)
298. {
299. //将当前节点中的要素移动到相应的子节点中
300. for (int j = 0; j < node->nShpCount; j ++)
301. {
302. if (node->children[i]->Box.Contains(node->pShapeObj[j].Box)
303. || node->children[i]->Box.Intersects(node->pShapeObj[j].Box))
304. {
305. node->children[i]->nShpCount += 1;
306. node->children[i]->pShapeObj =
307. (SHPMBRInfo*)malloc(node->children[i]->nShpCount*sizeof(SHPMBRInfo));
308.
309. memcpy(node->children[i]->pShapeObj,&(node->pShapeObj[j]),sizeof(SHPMBRInfo));
310.
311. free(node->pShapeObj);
312. node->pShapeObj = NULL;
313. node->nShpCount = 0;
314. }
315. }
316. }
317.
318. for (int i = 0; i < 4; i ++)
319. {
320. //如果包含或相交,则将节点插入到此节点
321. if (node->children[i]->Box.Contains(itemRect)
322. || node->children[i]->Box.Intersects(itemRect))
323. {
324. if (node->children[i]->nShpCount == 0) //如果之前没有节点
325. {
326. node->children[i]->nShpCount += 1;
327. node->pShapeObj =
328. (SHPMBRInfo*)malloc(sizeof(SHPMBRInfo)*node->children[i]->nShpCount);
329. }
330. else if (node->children[i]->nShpCount > 0)
331. {
332. node->children[i]->nShpCount += 1;
333. node->children[i]->pShapeObj =
334. (SHPMBRInfo *)realloc(node->children[i]->pShapeObj,
335. sizeof(SHPMBRInfo)*node->children[i]->nShpCount);
336. }
337.
338. pShpInfo.Box = itemRect;
339. pShpInfo.nID = key;
340. memcpy(node->children[i]->pShapeObj,
341. &pShpInfo,sizeof(SHPMBRInfo));
342. }
343. }
344. }
345.
346. //当前节点没有空间对象
347. else if (0 == node->nShpCount)
348. {
349. node->nShpCount += 1;
350. node->pShapeObj =
351. (SHPMBRInfo*)malloc(sizeof(SHPMBRInfo)*node->nShpCount);
352.
353. pShpInfo.Box = itemRect;
354. pShpInfo.nID = key;
355. memcpy(node->pShapeObj,&pShpInfo,sizeof(SHPMBRInfo));
356. }
357. }
358.
359. void InsertQuad(long key,MapRect &itemRect,QuadNode* pNode)
360. {
361. assert(pNode != NULL);
362.
363. if (!IsQuadLeaf(pNode)) //非叶子节点
364. {
365. int nCorver = 0; //跨越的子节点个数
366. int iIndex = -1; //被哪个子节点完全包含的索引号
367. for (int i = 0; i < 4; i ++)
368. {
369. if (pNode->children[i]->Box.Contains(itemRect)
370. && pNode->Box.Contains(itemRect))
371. {
372. nCorver += 1;
373. iIndex = i;
374. }
375. }
376.
377. //如果被某一个子节点包含,则进入该子节点
378. if (/*pNode->Box.Contains(itemRect) ||
379. pNode->Box.Intersects(itemRect)*/1 <= nCorver)
380. {
381. InsertQuad(key,itemRect,pNode->children[iIndex]);
382. }
383.
384. //如果跨越了多个子节点,直接放在这个节点中
385. else if (nCorver == 0)
386. {
387. if (pNode->nShpCount == 0) //如果之前没有节点
388. {
389. pNode->nShpCount += 1;
390. pNode->pShapeObj =
391. (SHPMBRInfo*)malloc(sizeof(SHPMBRInfo)*pNode->nShpCount);
392. }
393. else
394. {
395. pNode->nShpCount += 1;
396. pNode->pShapeObj =
397. (SHPMBRInfo *)realloc(pNode->pShapeObj,sizeof(SHPMBRInfo)*pNode->nShpCount);
398. }
399.
400. SHPMBRInfo pShpInfo;
401. pShpInfo.Box = itemRect;
402. pShpInfo.nID = key;
403. memcpy(pNode->pShapeObj+pNode->nShpCount-1,&pShpInfo,sizeof(SHPMBRInfo));
404. }
405. }
406.
407. //如果是叶子节点,直接放进去
408. else if (IsQuadLeaf(pNode))
409. {
410. if (pNode->nShpCount == 0) //如果之前没有节点
411. {
412. pNode->nShpCount += 1;
413. pNode->pShapeObj =
414. (SHPMBRInfo*)malloc(sizeof(SHPMBRInfo)*pNode->nShpCount);
415. }
416. else
417. {
418. pNode->nShpCount += 1;
419. pNode->pShapeObj =
420. (SHPMBRInfo *)realloc(pNode->pShapeObj,sizeof(SHPMBRInfo)*pNode->nShpCount);
421. }
422.
423. SHPMBRInfo pShpInfo;
424. pShpInfo.Box = itemRect;
425. pShpInfo.nID = key;
426. memcpy(pNode->pShapeObj+pNode->nShpCount-1,&pShpInfo,sizeof(SHPMBRInfo));
427. }
428. }
429.
430. void InsertQuad2(long key,MapRect &itemRect,QuadNode* pNode)
431. {
432. QuadNode *node = pNode; //保留根节点副本
433. SHPMBRInfo pShpInfo;
434.
435. //节点有孩子
436. if (0 < node->nChildCount)
437. {
438. for (int i = 0; i < 4; i ++)
439. {
440. //如果包含或相交,则将节点插入到此节点
441. if (node->children[i]->Box.Contains(itemRect)
442. || node->children[i]->Box.Intersects(itemRect))
443. {
444. //node = node->children[i];
445. Insert(key,itemRect,node->children[i]);
446. }
447. }
448. }
449.
450. //如果当前节点存在一个子节点时
451. else if (0 == node->nChildCount)
452. {
453. MapRect boxs[4];
454. node->Box.Split(boxs,boxs+1,boxs+2,boxs+3);
455.
456. int cnt = -1;
457. for (int i = 0; i < 4; i ++)
458. {
459. //如果包含或相交,则将节点插入到此节点
460. if (boxs[i].Contains(itemRect))
461. {
462. cnt = i;
463. }
464. }
465.
466. //如果有一个矩形包含此对象,则创建四个孩子节点
467. if (cnt > -1)
468. {
469. for (int i = 0; i < 4; i ++)
470. {
471. //创建四个节点并插入相应的MBR
472. node->children[i] = InitQuadNode();
473. node->children[i]->Box = boxs[i];
474. }
475. node->nChildCount = 4;
476. InsertQuad2(key,itemRect,node->children[cnt]); //递归
477. }
478.
479. //如果都不包含,则直接将对象插入此节点
480. if (cnt == -1)
481. {
482. if (node->nShpCount == 0) //如果之前没有节点
483. {
484. node->nShpCount += 1;
485. node->pShapeObj =
486. (SHPMBRInfo*)malloc(sizeof(SHPMBRInfo)*node->nShpCount);
487. }
488. else if (node->nShpCount > 0)
489. {
490. node->nShpCount += 1;
491. node->pShapeObj =
492. (SHPMBRInfo *)realloc(node->pShapeObj,
493. sizeof(SHPMBRInfo)*node->nShpCount);
494. }
495.
496. pShpInfo.Box = itemRect;
497. pShpInfo.nID = key;
498. memcpy(node->pShapeObj,
499. &pShpInfo,sizeof(SHPMBRInfo));
500. }
501. }
502.
503. //当前节点没有空间对象
504. /*else if (0 == node->nShpCount)
505. {
506. node->nShpCount += 1;
507. node->pShapeObj =
508. (SHPMBRInfo*)malloc(sizeof(SHPMBRInfo)*node->nShpCount);
509.
510. pShpInfo.Box = itemRect;
511. pShpInfo.nID = key;
512. memcpy(node->pShapeObj,&pShpInfo,sizeof(SHPMBRInfo));
513. }*/
514. }
515.
516. bool IsQuadLeaf(QuadNode* node)
517. {
518. if (NULL == node)
519. {
520. return 1;
521. }
522. for (int i = 0; i < 4; i ++)
523. {
524. if (node->children[i] != NULL)
525. {
526. return 0;
527. }
528. }
529.
530. return 1;
531. }
532.
533. bool DelFalseNode(QuadNode* node)
534. {
535. //如果没有子节点且没有要素
536. if (node->nChildCount ==0 && node->nShpCount == 0)
537. {
538. ReleaseQuadTree(&node);
539. }
540.
541. //如果有子节点
542. else if (node->nChildCount > 0)
543. {
544. for (int i = 0; i < 4; i ++)
545. {
546. DelFalseNode(node->children[i]);
547. }
548. }
549.
550. return 1;
551. }
552.
553. void TraversalQuadTree(QuadNode* quadTree,vector<int>& resVec)
554. {
555. QuadNode *node = quadTree;
556. int i = 0;
557. if (NULL != node)
558. {
559. //将本节点中的空间对象存储数组中
560. for (i = 0; i < node->nShpCount; i ++)
561. {
562. resVec.push_back((node->pShapeObj+i)->nID);
563. }
564.
565. //遍历孩子节点
566. for (i = 0; i < node->nChildCount; i ++)
567. {
568. if (node->children[i] != NULL)
569. {
570. TraversalQuadTree(node->children[i],resVec);
571. }
572. }
573. }
574.
575. }
576.
577. void TraversalQuadTree(QuadNode* quadTree,vector<QuadNode*>& arrNode)
578. {
579. deque<QuadNode*> nodeQueue;
580. if (quadTree != NULL)
581. {
582. nodeQueue.push_back(quadTree);
583. while (!nodeQueue.empty())
584. {
585. QuadNode* queueHead = nodeQueue.at(0); //取队列头结点
586. arrNode.push_back(queueHead);
587. nodeQueue.pop_front();
588. for (int i = 0; i < 4; i ++)
589. {
590. if (queueHead->children[i] != NULL)
591. {
592. nodeQueue.push_back(queueHead->children[i]);
593. }
594. }
595. }
596. }
597. }
598.
599. void ReleaseQuadTree(QuadNode** quadTree)
600. {
601. int i = 0;
602. QuadNode* node = *quadTree;
603. if (NULL == node)
604. {
605. return;
606. }
607.
608. else
609. {
610. for (i = 0; i < 4; i ++)
611. {
612. ReleaseQuadTree(&node->children[i]);
613. }
614. free(node);
615. node = NULL;
616. }
617.
618. node = NULL;
619. }
620.
621. long CalByteQuadTree(QuadNode* quadTree,long& nSize)
622. {
623. if (quadTree != NULL)
624. {
625. nSize += sizeof(QuadNode)+quadTree->nChildCount*sizeof(SHPMBRInfo);
626. for (int i = 0; i < 4; i ++)
627. {
628. if (quadTree->children[i] != NULL)
629. {
630. nSize += CalByteQuadTree(quadTree->children[i],nSize);
631. }
632. }
633. }
634.
635. return 1;
636. }
四叉树递归遍历叶节点并输出至数组
原文链接:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define CHILD_NUM 4
typedef int Datatype; // 节点数据类型
typedef struct QuadTree* ChildType; // 指向孩子节点指针
int max_leaf_num = 1; // 最大叶节点个数
static int N = 0; // 对叶节点计数的全局变量
// 四叉树节点结构
struct QuadTree
{
Datatype data; // 数据
ChildType child[CHILD_NUM]; // 存放指向四个子树的指针数组
};
// 判断是否为叶节点,是返回1,不是返回0
int isLeaf( QuadTree* node )
{
int i;
for ( i = 0; i < CHILD_NUM; ++i )
{
if ( node->child[i] != NULL ) // 如果存在子树,则不是叶节点
return 0;
}
return 1;
}
// 将长度为n的数组空间扩大两倍
void expandArr( Datatype** out )
{
int n = max_leaf_num;
Datatype* tmpArr = (Datatype*)malloc( sizeof(Datatype) * n);
memcpy( tmpArr, *out, sizeof(Datatype) * n);
free(*out);
*out = (Datatype*)malloc( sizeof(Datatype) * n * 2);
memcpy( *out, tmpArr, sizeof(Datatype) * n );
free( tmpArr );
max_leaf_num = n * 2;
}
// 遍历四叉树,将叶节点数据存储到out所指的数组中
void __travels( QuadTree* root, Datatype** out )
{
int i;
if ( root == NULL )
return;
if ( isLeaf( root ) )
{
if ( N >= max_leaf_num ) // 如果数组空间不足
{
expandArr( out ); // 将数组空间扩大两倍
}
(*out)[N++] = root->data;
return;
}
for ( i = 0; i < CHILD_NUM; ++i )
__travels( root->child[i], out );
}
// 遍历,返回叶节点数目
int Travels( QuadTree* root, Datatype** out )
{
N = 0; // 全局变量,记录也节点个数
__travels( root, out );
return N;
}
// 初始化
QuadTree* InitTree()
{
int i;
QuadTree* root = (QuadTree*)malloc(sizeof(QuadTree));
for ( i = 0; i < CHILD_NUM; ++i )
{
root->child[i] = NULL;
}
return root;
}
// 释放树空间
void ReleaseTree( QuadTree** root )
{
int i;
QuadTree* node = *root;
if ( node == NULL )
return;
else
{
for ( i = 0; i < CHILD_NUM; ++i )
{
ReleaseTree( &(node->child[i]) );
}
free( node );
}
*root = NULL;
}
// 在root的第n个孩子处插入数据d
void InsertData( QuadTree* root, Datatype d, int n )
{
int i;
QuadTree* tmpNode = NULL;
if ( n < 0 || n >= 4 || root == NULL ) // 如果n不为0,1,2,3或者root为空,这直接结束
return;
if ( root->child[n] != NULL ) // 如果root的第n个孩子节点已经有数据,则用d替换该数据
root->child[n]->data = d;
else // 否则,分配一个新节点,该节点数据为d,让child[n]指向该节点
{
tmpNode = (QuadTree*)malloc(sizeof(QuadTree));
for ( i = 0; i < CHILD_NUM; ++i )
{
tmpNode->child[i] = NULL;
}
tmpNode->data = d;
root->child[n] = tmpNode;
}
}
int main()
{
int i;
QuadTree* root = InitTree();
root->data = 10;
for ( i = 0; i < CHILD_NUM-1; ++i )
{
InsertData( root, i*i, i);
}
for ( i = 0; i < CHILD_NUM; ++i )
{
InsertData( root->child[0], root->data + i+2, i);
}
Datatype* leafData = (Datatype*)malloc( sizeof(Datatype) * max_leaf_num );
int K = Travels( root, &leafData );
for ( int i = 0; i < K; ++i )
{
printf("%d\n", leafData[i] );
}
ReleaseTree( &root );
return 0;
}