四叉树空间索引原理及其实现
今天依然在放假中,在此将以前在学校写的四叉树的东西拿出来和大家分享。
四叉树索引的基本思想是将地理空间递归划分为不同层次的树结构。它将已知范围的空间等分成四个相等的子空间,如此递归下去,直至树的层次达到一定深度或者满足某种要求后停止分割。四叉树的结构比较简单,并且当空间数据对象分布比较均匀时,具有比较高的空间数据插入和查询效率,因此四叉树是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. typedefenum
15. {
16. UR = 0,
17. UL = 1,
18. LL = 2,
19. LR = 3
20. }QuadrantEnum;
21.
22. /*空间对象MBR信息*/
23. typedefstruct
24. {
25. int//空间对象ID号
26. //空间对象MBR范围坐标
27. }SHPMBRInfo;
28.
29. /* 四叉树节点类型结构 */
30. typedefstruct
31. {
32. //节点所代表的矩形区域
33. int//节点所包含的所有空间对象个数
34. //空间对象指针数组
35. int//子节点个数
36. //指向节点的四个孩子
37. }QuadNode;
38.
39. /* 四叉树类型结构 */
40. typedefstruct
41. {
42. QuadNode *root;
43. int// 四叉树的深度
44. }QuadTree;
45.
46.
47. //初始化四叉树节点
48. QuadNode *InitQuadNode();
49.
50. //层次创建四叉树方法(满四叉树)
51. voidint
52.
53. //创建各个分支
54. voidint
55.
56. //构建四叉树空间索引
57. void
58.
59. //四叉树索引查询(矩形查询)
60. voidint>& ItemSearched);
61.
62. //四叉树索引查询(矩形查询)并行查询
63. voidint>& ItemSearched);
64.
65. //四叉树的查询(点查询)
66. voiddouble cx,double cy,vector<int>& ItemSearched);
67.
68. //将指定的空间对象插入到四叉树中
69. voidlong
70.
71. //将指定的空间对象插入到四叉树中
72. voidlong
73.
74. //将指定的空间对象插入到四叉树中
75. voidlong
76.
77. //判断一个节点是否是叶子节点
78. bool
79.
80. //删除多余的节点
81. bool
82.
83. //四叉树遍历(所有要素)
84. voidint>& resVec);
85.
86. //四叉树遍历(所有节点)
87. void
88.
89. //释放树的内存空间
90. void
91.
92. //计算四叉树所占的字节的大小
93. longlong& nSize);
94.
95.
96. #endif
源文件如下:
[cpp] view plain copy
1. #include "QuadTree.h"
2.
3.
4. QuadNode *InitQuadNode()
5. {
6. new
7. node->Box.maxX = 0;
8. node->Box.maxY = 0;
9. node->Box.minX = 0;
10. node->Box.minY = 0;
11.
12. forint
13. {
14. node->children[i] = NULL;
15. }
16. node->nChildCount = 0;
17. node->nShpCount = 0;
18. node->pShapeObj = NULL;
19.
20. return
21. }
22.
23. voidint
24. {
25. pQuadTree->depth = depth;
26.
27. //整个图层的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
40. new
41. forint
42. {
43. pFeatureClass[i] = poLayer->GetFeature(i);
44. }
45.
46. //插入各个要素
47. //空间对象的MBR
48. //#pragma omp parallel for
49. forint
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. voidint
63. {
64. if
65. {
66. //创建树根
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. forint
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
85. {
86. assert(poLayer);
87. //整个图层的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
101.
102. MapRect rect;
103. //空间对象的MBR
104. forint
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. voidint>& ItemSearched)
118. {
119. assert(node);
120.
121. //int coreNum = omp_get_num_procs();
122. //vector<int> * pResArr = new vector<int>[coreNum];
123.
124. if
125. {
126. forint
127. {
128. if
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. forint
175. {
176. if
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. voidint>& ItemSearched)
194. {
195. int
196. omp_set_num_threads(coreNum);
197. int>* searchArrs = new vector<int>[coreNum];
198. forint
199. {
200. searchArrs[i].clear();
201. }
202.
203. #pragma omp parallel for
204. forint
205. {
206. int
207. forint
208. {
209. if
210. || queryRect.Intersects(resNodes[i]->pShapeObj[j].Box))
211. {
212. searchArrs[tid].push_back(resNodes[i]->pShapeObj[j].nID);
213. }
214. }
215. }
216.
217. forint
218. {
219. ItemSearched.insert(ItemSearched.end(),
220. searchArrs[i].begin(),searchArrs[i].end());
221. }
222.
223. delete
224. searchArrs = NULL;
225. }
226.
227. voiddouble cx,double cy,vector<int>& ItemSearched)
228. {
229. assert(node);
230. if//节点
231. {
232. forint
233. {
234. if
235. {
236. ItemSearched.push_back(node->pShapeObj[i].nID);
237. }
238. }
239. }
240.
241. elseif (node->nChildCount >0) //节点
242. {
243. forint
244. {
245. if
246. {
247. PtSearchQTree(node->children[i],cx,cy,ItemSearched);
248. }
249. }
250. }
251.
252. //找出重复元素的位置
253. //先排序,默认升序
254. int>::iterator unique_iter =
255. unique(ItemSearched.begin(),ItemSearched.end());
256. ItemSearched.erase(unique_iter,ItemSearched.end());
257. }
258.
259. voidlong
260. {
261. //保留根节点副本
262. SHPMBRInfo pShpInfo;
263.
264. //节点有孩子
265. if
266. {
267. forint
268. {
269. //如果包含或相交,则将节点插入到此节点
270. if
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. elseif
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. forint
298. {
299. //将当前节点中的要素移动到相应的子节点中
300. forint
301. {
302. if
303. || node->children[i]->Box.Intersects(node->pShapeObj[j].Box))
304. {
305. node->children[i]->nShpCount += 1;
306. node->children[i]->pShapeObj =
307. sizeof(SHPMBRInfo));
308.
309. sizeof(SHPMBRInfo));
310.
311. free(node->pShapeObj);
312. node->pShapeObj = NULL;
313. node->nShpCount = 0;
314. }
315. }
316. }
317.
318. forint
319. {
320. //如果包含或相交,则将节点插入到此节点
321. if
322. || node->children[i]->Box.Intersects(itemRect))
323. {
324. if//如果之前没有节点
325. {
326. node->children[i]->nShpCount += 1;
327. node->pShapeObj =
328. sizeof(SHPMBRInfo)*node->children[i]->nShpCount);
329. }
330. elseif
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. sizeof(SHPMBRInfo));
342. }
343. }
344. }
345.
346. //当前节点没有空间对象
347. elseif
348. {
349. node->nShpCount += 1;
350. node->pShapeObj =
351. sizeof(SHPMBRInfo)*node->nShpCount);
352.
353. pShpInfo.Box = itemRect;
354. pShpInfo.nID = key;
355. sizeof(SHPMBRInfo));
356. }
357. }
358.
359. voidlong
360. {
361. assert(pNode != NULL);
362.
363. if//非叶子节点
364. {
365. int//跨越的子节点个数
366. int//被哪个子节点完全包含的索引号
367. forint
368. {
369. if
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. elseif
386. {
387. if//如果之前没有节点
388. {
389. pNode->nShpCount += 1;
390. pNode->pShapeObj =
391. sizeof(SHPMBRInfo)*pNode->nShpCount);
392. }
393. else
394. {
395. pNode->nShpCount += 1;
396. pNode->pShapeObj =
397. sizeof(SHPMBRInfo)*pNode->nShpCount);
398. }
399.
400. SHPMBRInfo pShpInfo;
401. pShpInfo.Box = itemRect;
402. pShpInfo.nID = key;
403. sizeof(SHPMBRInfo));
404. }
405. }
406.
407. //如果是叶子节点,直接放进去
408. elseif
409. {
410. if//如果之前没有节点
411. {
412. pNode->nShpCount += 1;
413. pNode->pShapeObj =
414. sizeof(SHPMBRInfo)*pNode->nShpCount);
415. }
416. else
417. {
418. pNode->nShpCount += 1;
419. pNode->pShapeObj =
420. sizeof(SHPMBRInfo)*pNode->nShpCount);
421. }
422.
423. SHPMBRInfo pShpInfo;
424. pShpInfo.Box = itemRect;
425. pShpInfo.nID = key;
426. sizeof(SHPMBRInfo));
427. }
428. }
429.
430. voidlong
431. {
432. //保留根节点副本
433. SHPMBRInfo pShpInfo;
434.
435. //节点有孩子
436. if
437. {
438. forint
439. {
440. //如果包含或相交,则将节点插入到此节点
441. if
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. elseif
452. {
453. MapRect boxs[4];
454. node->Box.Split(boxs,boxs+1,boxs+2,boxs+3);
455.
456. int
457. forint
458. {
459. //如果包含或相交,则将节点插入到此节点
460. if
461. {
462. cnt = i;
463. }
464. }
465.
466. //如果有一个矩形包含此对象,则创建四个孩子节点
467. if
468. {
469. forint
470. {
471. //创建四个节点并插入相应的MBR
472. node->children[i] = InitQuadNode();
473. node->children[i]->Box = boxs[i];
474. }
475. node->nChildCount = 4;
476. //递归
477. }
478.
479. //如果都不包含,则直接将对象插入此节点
480. if
481. {
482. if//如果之前没有节点
483. {
484. node->nShpCount += 1;
485. node->pShapeObj =
486. sizeof(SHPMBRInfo)*node->nShpCount);
487. }
488. elseif
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. 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
517. {
518. if
519. {
520. return
521. }
522. forint
523. {
524. if
525. {
526. return
527. }
528. }
529.
530. return
531. }
532.
533. bool
534. {
535. //如果没有子节点且没有要素
536. if
537. {
538. ReleaseQuadTree(&node);
539. }
540.
541. //如果有子节点
542. elseif
543. {
544. forint
545. {
546. DelFalseNode(node->children[i]);
547. }
548. }
549.
550. return
551. }
552.
553. voidint>& resVec)
554. {
555. QuadNode *node = quadTree;
556. int
557. if
558. {
559. //将本节点中的空间对象存储数组中
560. for
561. {
562. resVec.push_back((node->pShapeObj+i)->nID);
563. }
564.
565. //遍历孩子节点
566. for
567. {
568. if
569. {
570. TraversalQuadTree(node->children[i],resVec);
571. }
572. }
573. }
574.
575. }
576.
577. void
578. {
579. deque<QuadNode*> nodeQueue;
580. if
581. {
582. nodeQueue.push_back(quadTree);
583. while
584. {
585. //取队列头结点
586. arrNode.push_back(queueHead);
587. nodeQueue.pop_front();
588. forint
589. {
590. if
591. {
592. nodeQueue.push_back(queueHead->children[i]);
593. }
594. }
595. }
596. }
597. }
598.
599. void
600. {
601. int
602. QuadNode* node = *quadTree;
603. if
604. {
605. return;
606. }
607.
608. else
609. {
610. for
611. {
612. ReleaseQuadTree(&node->children[i]);
613. }
614. free(node);
615. node = NULL;
616. }
617.
618. node = NULL;
619. }
620.
621. longlong& nSize)
622. {
623. if
624. {
625. sizeof(QuadNode)+quadTree->nChildCount*sizeof(SHPMBRInfo);
626. forint
627. {
628. if
629. {
630. nSize += CalByteQuadTree(quadTree->children[i],nSize);
631. }
632. }
633. }
634.
635. return
636. }
代码有点长,有需要的朋友可以借鉴并自己优化
今天依然在放假中,在此将以前在学校写的四叉树的东西拿出来和大家分享。
四叉树索引的基本思想是将地理空间递归划分为不同层次的树结构。它将已知范围的空间等分成四个相等的子空间,如此递归下去,直至树的层次达到一定深度或者满足某种要求后停止分割。四叉树的结构比较简单,并且当空间数据对象分布比较均匀时,具有比较高的空间数据插入和查询效率,因此四叉树是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. typedefenum
15. {
16. UR = 0,
17. UL = 1,
18. LL = 2,
19. LR = 3
20. }QuadrantEnum;
21.
22. /*空间对象MBR信息*/
23. typedefstruct
24. {
25. int//空间对象ID号
26. //空间对象MBR范围坐标
27. }SHPMBRInfo;
28.
29. /* 四叉树节点类型结构 */
30. typedefstruct
31. {
32. //节点所代表的矩形区域
33. int//节点所包含的所有空间对象个数
34. //空间对象指针数组
35. int//子节点个数
36. //指向节点的四个孩子
37. }QuadNode;
38.
39. /* 四叉树类型结构 */
40. typedefstruct
41. {
42. QuadNode *root;
43. int// 四叉树的深度
44. }QuadTree;
45.
46.
47. //初始化四叉树节点
48. QuadNode *InitQuadNode();
49.
50. //层次创建四叉树方法(满四叉树)
51. voidint
52.
53. //创建各个分支
54. voidint
55.
56. //构建四叉树空间索引
57. void
58.
59. //四叉树索引查询(矩形查询)
60. voidint>& ItemSearched);
61.
62. //四叉树索引查询(矩形查询)并行查询
63. voidint>& ItemSearched);
64.
65. //四叉树的查询(点查询)
66. voiddouble cx,double cy,vector<int>& ItemSearched);
67.
68. //将指定的空间对象插入到四叉树中
69. voidlong
70.
71. //将指定的空间对象插入到四叉树中
72. voidlong
73.
74. //将指定的空间对象插入到四叉树中
75. voidlong
76.
77. //判断一个节点是否是叶子节点
78. bool
79.
80. //删除多余的节点
81. bool
82.
83. //四叉树遍历(所有要素)
84. voidint>& resVec);
85.
86. //四叉树遍历(所有节点)
87. void
88.
89. //释放树的内存空间
90. void
91.
92. //计算四叉树所占的字节的大小
93. longlong& nSize);
94.
95.
96. #endif
源文件如下:
[cpp]
view plain
copy
1. #include "QuadTree.h"
2.
3.
4. QuadNode *InitQuadNode()
5. {
6. new
7. node->Box.maxX = 0;
8. node->Box.maxY = 0;
9. node->Box.minX = 0;
10. node->Box.minY = 0;
11.
12. forint
13. {
14. node->children[i] = NULL;
15. }
16. node->nChildCount = 0;
17. node->nShpCount = 0;
18. node->pShapeObj = NULL;
19.
20. return
21. }
22.
23. voidint
24. {
25. pQuadTree->depth = depth;
26.
27. //整个图层的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
40. new
41. forint
42. {
43. pFeatureClass[i] = poLayer->GetFeature(i);
44. }
45.
46. //插入各个要素
47. //空间对象的MBR
48. //#pragma omp parallel for
49. forint
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. voidint
63. {
64. if
65. {
66. //创建树根
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. forint
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
85. {
86. assert(poLayer);
87. //整个图层的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
101.
102. MapRect rect;
103. //空间对象的MBR
104. forint
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. voidint>& ItemSearched)
118. {
119. assert(node);
120.
121. //int coreNum = omp_get_num_procs();
122. //vector<int> * pResArr = new vector<int>[coreNum];
123.
124. if
125. {
126. forint
127. {
128. if
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. forint
175. {
176. if
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. voidint>& ItemSearched)
194. {
195. int
196. omp_set_num_threads(coreNum);
197. int>* searchArrs = new vector<int>[coreNum];
198. forint
199. {
200. searchArrs[i].clear();
201. }
202.
203. #pragma omp parallel for
204. forint
205. {
206. int
207. forint
208. {
209. if
210. || queryRect.Intersects(resNodes[i]->pShapeObj[j].Box))
211. {
212. searchArrs[tid].push_back(resNodes[i]->pShapeObj[j].nID);
213. }
214. }
215. }
216.
217. forint
218. {
219. ItemSearched.insert(ItemSearched.end(),
220. searchArrs[i].begin(),searchArrs[i].end());
221. }
222.
223. delete
224. searchArrs = NULL;
225. }
226.
227. voiddouble cx,double cy,vector<int>& ItemSearched)
228. {
229. assert(node);
230. if//节点
231. {
232. forint
233. {
234. if
235. {
236. ItemSearched.push_back(node->pShapeObj[i].nID);
237. }
238. }
239. }
240.
241. elseif (node->nChildCount >0) //节点
242. {
243. forint
244. {
245. if
246. {
247. PtSearchQTree(node->children[i],cx,cy,ItemSearched);
248. }
249. }
250. }
251.
252. //找出重复元素的位置
253. //先排序,默认升序
254. int>::iterator unique_iter =
255. unique(ItemSearched.begin(),ItemSearched.end());
256. ItemSearched.erase(unique_iter,ItemSearched.end());
257. }
258.
259. voidlong
260. {
261. //保留根节点副本
262. SHPMBRInfo pShpInfo;
263.
264. //节点有孩子
265. if
266. {
267. forint
268. {
269. //如果包含或相交,则将节点插入到此节点
270. if
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. elseif
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. forint
298. {
299. //将当前节点中的要素移动到相应的子节点中
300. forint
301. {
302. if
303. || node->children[i]->Box.Intersects(node->pShapeObj[j].Box))
304. {
305. node->children[i]->nShpCount += 1;
306. node->children[i]->pShapeObj =
307. sizeof(SHPMBRInfo));
308.
309. sizeof(SHPMBRInfo));
310.
311. free(node->pShapeObj);
312. node->pShapeObj = NULL;
313. node->nShpCount = 0;
314. }
315. }
316. }
317.
318. forint
319. {
320. //如果包含或相交,则将节点插入到此节点
321. if
322. || node->children[i]->Box.Intersects(itemRect))
323. {
324. if//如果之前没有节点
325. {
326. node->children[i]->nShpCount += 1;
327. node->pShapeObj =
328. sizeof(SHPMBRInfo)*node->children[i]->nShpCount);
329. }
330. elseif
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. sizeof(SHPMBRInfo));
342. }
343. }
344. }
345.
346. //当前节点没有空间对象
347. elseif
348. {
349. node->nShpCount += 1;
350. node->pShapeObj =
351. sizeof(SHPMBRInfo)*node->nShpCount);
352.
353. pShpInfo.Box = itemRect;
354. pShpInfo.nID = key;
355. sizeof(SHPMBRInfo));
356. }
357. }
358.
359. voidlong
360. {
361. assert(pNode != NULL);
362.
363. if//非叶子节点
364. {
365. int//跨越的子节点个数
366. int//被哪个子节点完全包含的索引号
367. forint
368. {
369. if
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. elseif
386. {
387. if//如果之前没有节点
388. {
389. pNode->nShpCount += 1;
390. pNode->pShapeObj =
391. sizeof(SHPMBRInfo)*pNode->nShpCount);
392. }
393. else
394. {
395. pNode->nShpCount += 1;
396. pNode->pShapeObj =
397. sizeof(SHPMBRInfo)*pNode->nShpCount);
398. }
399.
400. SHPMBRInfo pShpInfo;
401. pShpInfo.Box = itemRect;
402. pShpInfo.nID = key;
403. sizeof(SHPMBRInfo));
404. }
405. }
406.
407. //如果是叶子节点,直接放进去
408. elseif
409. {
410. if//如果之前没有节点
411. {
412. pNode->nShpCount += 1;
413. pNode->pShapeObj =
414. sizeof(SHPMBRInfo)*pNode->nShpCount);
415. }
416. else
417. {
418. pNode->nShpCount += 1;
419. pNode->pShapeObj =
420. sizeof(SHPMBRInfo)*pNode->nShpCount);
421. }
422.
423. SHPMBRInfo pShpInfo;
424. pShpInfo.Box = itemRect;
425. pShpInfo.nID = key;
426. sizeof(SHPMBRInfo));
427. }
428. }
429.
430. voidlong
431. {
432. //保留根节点副本
433. SHPMBRInfo pShpInfo;
434.
435. //节点有孩子
436. if
437. {
438. forint
439. {
440. //如果包含或相交,则将节点插入到此节点
441. if
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. elseif
452. {
453. MapRect boxs[4];
454. node->Box.Split(boxs,boxs+1,boxs+2,boxs+3);
455.
456. int
457. forint
458. {
459. //如果包含或相交,则将节点插入到此节点
460. if
461. {
462. cnt = i;
463. }
464. }
465.
466. //如果有一个矩形包含此对象,则创建四个孩子节点
467. if
468. {
469. forint
470. {
471. //创建四个节点并插入相应的MBR
472. node->children[i] = InitQuadNode();
473. node->children[i]->Box = boxs[i];
474. }
475. node->nChildCount = 4;
476. //递归
477. }
478.
479. //如果都不包含,则直接将对象插入此节点
480. if
481. {
482. if//如果之前没有节点
483. {
484. node->nShpCount += 1;
485. node->pShapeObj =
486. sizeof(SHPMBRInfo)*node->nShpCount);
487. }
488. elseif
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. 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
517. {
518. if
519. {
520. return
521. }
522. forint
523. {
524. if
525. {
526. return
527. }
528. }
529.
530. return
531. }
532.
533. bool
534. {
535. //如果没有子节点且没有要素
536. if
537. {
538. ReleaseQuadTree(&node);
539. }
540.
541. //如果有子节点
542. elseif
543. {
544. forint
545. {
546. DelFalseNode(node->children[i]);
547. }
548. }
549.
550. return
551. }
552.
553. voidint>& resVec)
554. {
555. QuadNode *node = quadTree;
556. int
557. if
558. {
559. //将本节点中的空间对象存储数组中
560. for
561. {
562. resVec.push_back((node->pShapeObj+i)->nID);
563. }
564.
565. //遍历孩子节点
566. for
567. {
568. if
569. {
570. TraversalQuadTree(node->children[i],resVec);
571. }
572. }
573. }
574.
575. }
576.
577. void
578. {
579. deque<QuadNode*> nodeQueue;
580. if
581. {
582. nodeQueue.push_back(quadTree);
583. while
584. {
585. //取队列头结点
586. arrNode.push_back(queueHead);
587. nodeQueue.pop_front();
588. forint
589. {
590. if
591. {
592. nodeQueue.push_back(queueHead->children[i]);
593. }
594. }
595. }
596. }
597. }
598.
599. void
600. {
601. int
602. QuadNode* node = *quadTree;
603. if
604. {
605. return;
606. }
607.
608. else
609. {
610. for
611. {
612. ReleaseQuadTree(&node->children[i]);
613. }
614. free(node);
615. node = NULL;
616. }
617.
618. node = NULL;
619. }
620.
621. longlong& nSize)
622. {
623. if
624. {
625. sizeof(QuadNode)+quadTree->nChildCount*sizeof(SHPMBRInfo);
626. forint
627. {
628. if
629. {
630. nSize += CalByteQuadTree(quadTree->children[i],nSize);
631. }
632. }
633. }
634.
635. return
636. }
代码有点长,有需要的朋友可以借鉴并自己优化