【Mark】四叉树与八叉树

写在前面,四叉树和八叉树就是2D和3D的“二分法”,搜索过程与二叉树搜索也类似,二叉树中是将数组sort后存入二叉树中,从而在查找中实现时间复杂度为log2;四叉树/八叉树是按平面/空间范围划分有序node,将所有points(坐标已知)放入所属node中,实现所有points的sort,进而在搜索时,实现时间复杂度为log4/log8    ----WellP.C

转载自: http://blog.csdn.net/zhanxinhang/article/details/6706217

前序

四叉树或四元树也被称为Q树(Q-Tree)。四叉树广泛应用于图像处理、空间数据索引、2D中的快速碰撞检测、存储稀疏数据等,而八叉树(Octree)主要应用于3D图形处理。对游戏编程,这会很有用。本文着重于对四叉树与八叉树的原理与结构的介绍,帮助您在脑海中建立四叉树与八叉树的基本思想。本文并不对这两种数据结构同时进行详解,而只对四叉树进行详解,因为八叉树的建立可由四叉树的建立推得。若有不足之处,望能不吝指出,以改进之。^_^  欢迎Email:[email protected]

四叉树与八叉树的结构与原理

四叉树(Q-Tree)是一种树形数据结构。四叉树的定义是:它的每个节点下至多可以有四个子节点,通常把一部分二维空间细分为四个象限或区域并把该区域里的相关信息存入到四叉树节点中。这个区域可以是正方形、矩形或是任意形状。以下为四叉树的二维空间结构(左)和存储结构(右)示意图(注意节点颜色与网格边框颜色):

四叉树的每一个节点代表一个矩形区域(如上图黑色的根节点代表最外围黑色边框的矩形区域),每一个矩形区域又可划分为四个小矩形区域,这四个小矩形区域作为四个子节点所代表的矩形区域。

较之四叉树,八叉树将场景从二维空间延伸到了三维空间。八叉树(Octree)的定义是:若不为空树的话,树中任一节点的子节点恰好只会有八个,或零个,也就是子节点不会有0与8以外的数目。那么,这要用来做什么?想象一个立方体,我们最少可以切成多少个相同等分的小立方体?答案就是8个。如下八叉树的结构示意图所示:

四叉树存储结构的c语言描述:

 1 /* 一个矩形区域的象限划分::
 2
 3        UL(1)   |    UR(0)
 4      ----------|-----------
 5        LL(2)   |    LR(3)
 6 以下对该象限类型的枚举
 7 */
 8 typedef enum
 9 {
10     UR = 0,
11     UL = 1,
12     LL = 2,
13     LR = 3
14 }QuadrantEnum;
15
16 /* 矩形结构 */
17 typedef struct quadrect_t
18 {
19     double  left,
20             top,
21             right,
22             bottom;
23 }quadrect_t;
24
25 /* 四叉树节点类型结构 */
26 typedef struct quadnode_t
27 {
28     quadrect_t    rect;          //节点所代表的矩形区域
29     list_t        *lst_object;   //节点数据, 节点类型一般为链表,可存储多个对象
30     struct  quadnode_t  *sub[4]; //指向节点的四个孩子
31 }quadnode_t;
32
33 /* 四叉树类型结构 */
34 typedef struct quadtree_t
35 {
36     quadnode_t  *root;
37     int         depth;           // 四叉树的深度
38 }quadtree_t;

四叉树的建立

1、利用四叉树分网格,如本文的第一张图<四层完全四叉树结构示意图>,根据左图的网格图形建立如右图所示的完全四叉树。

伪码:

 1 Funtion QuadTreeBuild ( depth, rect )
 2 {
 3     QuadTree->depth = depth;
 4     /*创建分支,root树的根,depth深度,rect根节点代表的矩形区域*/
 5     QuadCreateBranch (  root, depth, rect );
 6 }
 7 Funtion QuadCreateBranch ( n, depth,rect )
 8 {
 9     if ( depth!=0 )
10    {
11         n = new node;    //开辟新节点
12         n ->rect = rect; //将该节点所代表的矩形区域存储到该节点中
13         将rect划成四份 rect[UR], rect[UL], rect[LL], rect[LR];
14         /*创建各孩子分支*/
15         QuadCreateBranch ( n->sub[UR], depth-1, rect [UR] );
16         QuadCreateBranch ( n->sub[UL], depth-1, rect [UL] );
17         QuadCreateBranch ( n->sub[LL], depth-1, rect [LL] );
18         QuadCreateBranch ( n->sub[LR], depth-1, rect [LR] );
19     }
20 }        

2、假设在一个矩形区域里有N个对象,如下左图一个黑点代表一个对象,每个对象的坐标位置都是已知的,用四叉树的一个节点存储一个对象,构建成如下右图所示的四叉树。

方法也是采用递归的方法对该矩形进行划分分区块,分完后再往里分,直到每一个子矩形区域里只包含一个对象为止。

伪码:

 1 Funtion QuadtreeBuild()
 2 {
 3      Quadtree = {empty};
 4      For (i = 1;i<n;i++) //遍历所有对象
 5      {
 6         QuadInsert(i, root);//将i对象插入四叉树
 7      }          
 8     剔除多余的节点;//执行完上面循环后,四叉树中可能有数据为空的叶子节点需要剔除
 9 }
10 Funtion QuadInsert(i,n)//该函数插入后四叉树中的每个节点所存储的对象数量不是1就是0
11 {  
12      if(节点n有孩子)
13      {      
14         通过划分区域判断i应该放置于n节点的哪一个孩子节点c;       
15         QuadInsert(i,c);
16      }
17      else if(节点n存储了一个对象)
18      {
19         为n节点创建四个孩子;
20         将n节点中的对象移到它应该放置的孩子节点中;
21         通过划分区域判断i应该放置于n节点的哪一个孩子节点c;
22         QuadInsert(i,c);
23      }
24      else if(n节点数据为空)    
25      {
26         将i存储到节点n中;
27      }
28 }

(以上两种建立方法作为举一反三之用)

用四叉树查找某一对象

1、采用盲目搜索,与二叉树的递归遍历类似,可采用后序遍历或前序遍历或中序遍历对其进行搜索某一对象,时间复杂度为O(n)。

2、根据对象在区域里的位置来搜索,采用分而治之思想,时间复杂度只与四叉树的深度有关。比起盲目搜索,这种搜索在区域里的对象越多时效果越明显

伪码:

 1 Funtion find ( n, pos, )
 2 {
 3       If (n节点所存的对象位置为 pos所指的位置 )
 4           Return n;
 5       If ( pos位于第一象限 )
 6           temp = find ( n->sub[UR], pos );
 7       else if ( pos位于第二象限)
 8           temp = find ( n->sub[UL], pos );
 9       else if ( pos位于第三象限 )
10           temp = find ( n->sub[LL], pos );
11       else  //pos 位于第四象限
12           temp = find ( n->sub[LR], pos );
13       return temp;   
14 } 

结语:

熟话说:结构之法,算法之道。多一种数据结构就多一种解决问题的方法,多一种方法就多一种思维模式。祝君学习愉快!^_^

==============================================

声明:版权所有,转载请注明出处: http://blog.csdn.net/zhanxinhang/article/details/6706217

参考:维基百科、百度百科

参考:CS267: Lecture 24, Apr 11 1996 Fast Hierarchical Methods for the N-body Problem, Part 1

原文地址:https://www.cnblogs.com/wellp/p/8536745.html

时间: 2024-10-17 01:53:05

【Mark】四叉树与八叉树的相关文章

游戏编程精粹系列书籍目录一览

游戏编程精粹1 第1章 通用编程技术 1.0 神奇的数据驱动设计(Steve Rabin) 3 1.0.1 点子1--基础 3 1.0.2 点子2--最低标准 3 1.0.3 点子3--杜绝硬编码 3 1.0.4 点子4--将控制流写成脚本 4 1.0.5 点子5--什么时候不适合使用脚本? 5 1.0.6 点子6--避免重复数据 5 1.0.7 点子7--开发工具来生成数据 6 1.0.8 结论 6 1.1 面向对象的编程与设计技术(James Boer) 7 1.1.1 代码风格 7 1.1

从B树、B+树、B*树谈到R 树

第一节.B树.B+树.B*树 1.前言: 动态查找树主要有:二叉查找树(Binary Search Tree),平衡二叉查找树(Balanced Binary Search Tree),红黑树(Red-Black Tree ),B-tree/B+-tree/ B*-tree(B~Tree).前三者是典型的二叉查找树结构,其查找的时间复杂度O(log2N)与树的深度相关,那么降低树的深度自然会提高查找效率. 但是咱们有面对这样一个实际问题:就是大规模数据存储中,实现索引查询这样一个实际背景下,树节

超大地形的处理 (Terrain Visualization)【转自知乎】

转自顾露 [开放世界游戏中的大地图背后有哪些实现技术?] 链接:http://gulu-dev.com/post/2014-11-16-open-world ### 4. 超大地形的处理 (Terrain Visualization) 终于说到对超大地形的处理了.可以说从上世纪九十年代起,超大地形的可视化,一直是3D游戏领域热门的话题.今天我们就借着这个机会,把相关的算法和实现理一理吧. 考虑到篇幅太长的话,俺的手指头招架不住,再一个不少对这个话题感兴趣的同学可能压根就不是程序员,一些实现细节可

我肚子里的墨水——写给3DGIS相关从业人员

序 作为一名程序员,我已经工作了五年,肚子里的墨水虽然不多,但也是积累了一些,今天倒出来整理一下,仅以经验之谈,供长江后浪拍打. 你可能适合阅读: 如果你和我一样,是一名程序员,主要擅长c/c++作为编程语言,从事着三维或者GIS相关的工作,作为一名技术流的探讨者,或者是希望从前辈那里找到点捷径,那么,你可能适合阅读本文. 你还是不要浪费时间了: 如果你是个大牛,或者你不喜欢罗嗦的文章,要不然你是个愤青或者大喷,我劝你还是不要浪费时间了 面象对象编程 Cpp 首先,编程语言只是一门工具,没有高低

浅谈 GPU图形渲染管线

 图形渲染管道被认为是实时图形渲染的核心,简称为管道.管道的主要功能是由给定的虚拟摄像机.三维物体.灯源.光照模型.纹理贴图或其他来产生或渲染一个二维图像.由此可见,渲染管线了实时渲染技术的底层工具.图像中物体的位置及形状是通过它们的几何描述.环境特征.以及该环境中虚拟摄像机的摆放位置来决定的.物体的外观受到了材质属性.灯源.贴图以及渲染模式(sharding modles)的影响.         很多计算机图形学的书籍都把渲染管线分为三个阶段:应用程序阶段.几何阶段.光栅化阶段. 1.  应

章节知识点总结 【转载】

http://blog.sina.com.cn/s/blog_60d6fadc010128mo.html 1.Const与 = 0的理解 const 和 =0 没有关系,要分开理解. 成员函数后面用 const 修饰,通俗的理解就是在这个函数内不能修改类的成员变量,除非那个成员变量是 mutable 的. = 0表示这个成员函数是纯虚函数,也就是它可以没有定义,只有接口,由它的继承类具体定义它的行为,当然,你也可以给它定义缺省的函数体.一个类里如果包含 =0 的纯虚函数,那么这个类就是一个抽象类

图形学复习

交互式计算机图形学(第五版)1-7章课后题答案 计算机图形学基础答案全 计算机图形学考试重点计算题 What is the difference between Gouraud and Phong shading? Gouraud shading (AKA Smooth Shading) is a per-vertex color computation. What this means is that the vertex shader must determine a color for e

《游戏引擎架构》读书心得(二)

一.调试技巧及工具 (1)基础调试 a)   日志及追踪,有些bug难以用VS自带的调试来进行单步调试,最好的解决方案就是printf调试法,打印一组数据,观察情况.之前我的做法是单独生成一个控制台,不过VS自带了一个OutPutDebugString()的方法,可以打印调试信息.不过这个只支持char*内容,我们可以将这个函数加工一下,使其支持不同类型的数据,甚至可以使其接受可变参数个数. b)   冗长级别:我们有时想要打印,有时又不想打印,所以可以设置打印内容的级别,每个信息设置一个级别,

转:场景管理

一.场景管理有很多种方法,如四叉树.八叉树.BSP.模糊K-D树.包围球层次结构等.室内环境主要是BSP为主,从quake3一直延续到现在主流的引擎都是以BSP为基础,BSP使用并不难,关键是数据的生成,这就牵涉到场景编辑器. Quake3.Unreal:BSP,有自己的编辑器. FarCry:场景分为室内和室外两部分,室内场景使用BSP, 室外不清楚但应该跟地形有很大关系,同时为了支持超远距离视距使用了地形Occlusion Culling,另外也可以手动放置OcclusionArea.