收藏 分享(赏)

第6章 树型结构.ppt

上传人:scg750829 文档编号:8271133 上传时间:2019-06-17 格式:PPT 页数:131 大小:1.50MB
下载 相关 举报
第6章 树型结构.ppt_第1页
第1页 / 共131页
第6章 树型结构.ppt_第2页
第2页 / 共131页
第6章 树型结构.ppt_第3页
第3页 / 共131页
第6章 树型结构.ppt_第4页
第4页 / 共131页
第6章 树型结构.ppt_第5页
第5页 / 共131页
点击查看更多>>
资源描述

1、第6章 树,数据结构(C描述),6.9 二叉树的应用哈夫曼树,6.8 树和森林,6.7 线索二叉树,6.4 遍历二叉树,6.3 二叉树的定义及存储结构,6.1 树的基本概念,目录,6.2 树的存储结构,6.5 二叉排序树,6.6 平衡二叉树,在许多领域许多问题不能或难用线性结构表示(哈夫曼编码、判定问题),故研究非线性的数据结构。树是一种应用十分广泛的非线性数据结构。,6.1 树的基本概念,6.1.1 树的定义,树的定义,树是由n(n0)个结点组成的有限集合。若n=0,称为空树;若n0,则称为非空树,在任一棵非空树中: (1)有一个特定的称为根(root)的结点。它只有直接后继,但没有直接前驱

2、; (2)除根结点以外的其它结点可以划分为m(m0)个互不相交的有限集合T0,T1,Tm-1,且每个集合Ti(i=0,1,m-1)本身又是一棵树,称为根的子树。由此可知,树的定义是一个递归的定义,即树的定义中又用到了树的概念。,从定义中看出树结构具有以下特点:,(1)有且仅有一个结点没有直接前驱,即根结点。 (2)除根结点之外,其余所有结点有且仅有一个直接前趋结点。 (3)包括根结点在内,每个结点可以有多个直接后继结点。 从此可见,树型结构的特点是,数据元素之间存在着一对多的关系。树的结构参见图6-1。,在图6-1(c)中,树的根结点为A,该树还可以分为三个互不相交子集T0,T1,T2,具体请

3、参见图6-2,其中 T0=B,E,F,J,K,L,T1=C,G,T2=D,H,I,M,而T0,T1,T2又可以分解成若干棵不相交子树。如:T0可以分解成T00,T01两个不相交子集,T00=E,J,K,L,T01=F,而T00又可以分为三个不相交子集T000,T001,T002,其中,T000=J,T001=K,T002=L。,6.1.2 基本术语,1.树的结点 指树中的一个数据元素,一般用一个字母表示。,2.结点的度 一个结点包含子树的数目,称为该结点的度。,3.树叶(叶子)度为0的结点,称为叶子结点或树叶,也叫终端结点。,4.分支结点(非终端结点) 除叶子结点外的所有结点,为分支结点。通常

4、又将除根结点之外的分支结点称为内部结点。,6.双亲结点 若结点X有子女Y,则X为Y的双亲结点。,7.祖先结点,8.子孙结点 某一结点的子女的子女为该结点子孙。,5.孩子结点 若结点X有子树,则子树的根结点为X的孩子结点,也称为孩子。如图6-1(c)中A的孩子为B,C,D。,10结点的层次 从根结点开始定义,根为第一层,根的孩子为第二层,依次类推。,11. 树的高度(深度) 树中结点所处的最大层数称为树的高度,如空树的高度为0,只有一个根结点的树高度为1。,12.树的度 树中结点度的最大值称为树的度。,9.兄弟结点 具有同一个双亲的结点,称为兄弟结点。,13. 有序树 若一棵树中所有子树从左到右

5、的排序是有顺序的,不能颠倒次序。称该树为有序树。,14. 无序树若一棵树中所有子树的次序无关紧要,则称为无序树。,15森林(树林)若干棵互不相交的树组成的集合为森林。一棵树可以看成是一个特殊的森林。 树与森林的关系,6.1.3 树的表示,1树形结构表示法 (掌握) 具体参 见图6-1 。,2. 凹入法表示法 具体参见图6-3,3. 嵌套集合表示法 具体参 见图6-4 。,4.广义表表示法对图7-1(c)的树结构,广义表表示法可表示为: A(B(E(J,K,L),F),C(G),D(H(M),I),6.2 树的存储结构仅考虑链式存储结构,有两种:多重链表表示法、二重链表表示法 6.2.1 多重链

6、表表示法每个结点由一个数据域和若干个指针域组成,其中,每个指针域指向该结点的一个孩子。一棵树中不同结点的度数可能不同,每个结点设置的指针域的数目可能就有所不同。通常有下面的两种方案: 1、定长结点的多重链表表示法,取树的度数作为每个结点的指针域的个数。 缺点:,由于树中多数结点的度可能小于树的度,因而这种方法将会导致许多结点的部分指针域为空,造成空间的浪费。,2、不定长结点的多重链表示法树中每个结点都取自己的度数作为指针域的个数,显然,对于叶结点就不必设指针域。另外,每个结点除了数据域、指针域外,还应设一个度数域用来指出该结点的度数,即指出该结点中指针域的个数。 6.2.2 二重链表表示法这种

7、方法是对树中的每个结点设三个域:数据域和2个指针域,第一个指针域给出该结点的第一个孩子(即最左边子树的根结点,长子)的地址,第二个指针域给出该结点的右边第一个兄弟结点(次弟)的地址。树的三重链表表示,增加了一个指针域即给出该结点的双亲结点的地址。,6.3 二叉树 在树型结构中,有一类简单而又重要的树,它的每个结点最多只有2棵子树,这种树被称为二叉树。,6.3.1 二叉树的定义,1二叉树的定义和树结构定义类似,二叉树的定义也可以递归形式给出: 二叉树是n(n0)个结点的有限集,它或者是空集(n=0),或者由一个根结点及两棵不相交的左子树和右子树组成。,二叉树的特点:每个结点最多有两个孩子,或者说

8、,在二叉树中,不存在度大于2的结点二叉树是有序树(树为无序树),其子树的顺序不能颠倒。因此,二叉树有五种不同的形态,参见下图。,6.3.2 二叉树的性质,性质1 若二叉树的层数从1开始,则二叉树的第k层结点数,最多为个 (k0)。 可以用数学归纳法证明之。,性质2 深度(高度)为k的二叉树最大结点数为 (k0),证明: 深度为k的二叉树,若要求结点数最多,则必须每一层的结点数都为最多,由性质1可知,最大结点数应为每一层最大结点数之和。即为: 20+21+2k-1=2k-1。,2k-1,2k-1,性质3 对任意一棵二叉树,如果叶子结点个数为n0,度为2的结点个数为n2,则有n0=n2+1。,证明

9、:设二叉树中度为1的结点个数为n1,根据二叉树的定义(二叉树中所有结点的度均小于或等于2)可知,该二叉树的结点总数 n=n0+n1+n2 (1)。再看二叉树中的分支数。除了根结点外,其余结点都有一个分支进入。设B为分支总数,则 n=B+1 由于这些分支是由度为1或2的结点射出的,所以又有B=n1+2*n2 于是得:n=n1+2n2+1 (2) 由(1)和(2)得:n0=n2+1,下面讨论两种特殊的二叉树:满二叉树和完全二叉树。,满二叉树 深度为k具有2k-1个结点的二叉树,称为满二叉树。或者说:如果一棵二叉树中任何结点,或者是叶结点,或者是有两棵非空子树,且叶子结点都集中在二叉树的最下一层,这

10、样的二叉树称为满二叉树。从定义可知:必须是二叉树的每一层上的结点数都达到最大,否则就不是满二叉树。,例:深(高)度为4的满二叉树如图(15个结点),可以对满二叉树的结点进行编号,约定编号从根结点起,自上而下,自左而右,由此引出完全二叉树的定义。,完全二叉树 如果一棵具有n个结点的深度为k的二叉树,它的每一个结点都与深度为k的满二叉树中编号为1 n的结点一一对应,则称这棵二叉树为完全二叉树。(例:k=3,n=4,5,6),从满二叉树及完全二叉树定义可以得出如下结论:满二叉树一定是一棵完全二叉树反之完全二叉树不一定是一棵满二叉树。满二叉树的叶子结点全部在最底层,而完全二叉树的叶子结点可以分布在最下

11、面两层。深度为4的满二叉树和完全二叉树(8个结点)如图6-6所示。,性质4 具有n个结点的完全二叉树高度为log2(n)+1 或 log2(n+1) 。 (注意x表示取不大于x(即)的最大整数,也叫做对x下取整,x表示取不小于x(即)的最小整数,也叫做对x上取整。),1、二叉树中度为0的结点数为50,度为1的结点数为30,总结点数为_。,湖南大学考研题,性质3:n0=n2+1,2、树最合适用来表示_。 A 有序数据元素 B 无序数据元素 C 元素之间无联系的数据 D元素之间分支层次关系的数据,3、对于有n 个结点的二叉树, 其高度为( )【武汉交通科技大学 一、5 (4分)】Anlog2n B

12、log2n Clog2n+1 D不确定 4、深度为h的满m叉树的第k层有( )个结点。 (1 k h)【北京航空航天大学 一、4(2分)】Amk-1 Bmk-1 Cmh-1 Dmh-1 5、在一棵高度为k的满二叉树中,结点总数为( )【北京工商大学 一、3 (3分)】A2k-1 B2k C2k-1 Dlog2k+1 6、高度为 K的二叉树最大的结点数为( )。【山东大学 二、3 (1分)】 A2k B2k-1 C2k -1 D2k-1-1,7、若一棵二叉树具有10个度为2的结点,5个度为1的结点,则度为0的结点个数是( ) A9 B11 C15 D不确定 【北京工商大学一.7(3分)】,性质3

13、 对任意一棵二叉树,如果叶子结点个数为n0,度为2的结点个数为n2,则有n0=n2+1。,6.3.3 二叉树的存贮结构,1顺序存贮结构,即用一维数组TM来存储二叉树的数据元素,按照二叉树的结点层次编号依次来存放。 如:见图 这种结构适合于存储完全二叉树和满二叉树,若是一般二叉树应如何处理?,必须按完全二叉树的形式来存贮树中的结点,这就要虚设很多空结点才能使它成为一棵完全二叉树。如图可见这将造成空间的浪费。,例:k=3的一般二叉树,对于一棵二叉树,若采用顺序存贮时,当它为完全二叉树(或满二叉树)时,比较方便,若为非完全二叉树,将会浪费大量存贮存贮单元。最坏情况的非完全二叉树是全部只有右分支,设高

14、度为K,则需占用个 存贮单元,而实际只有k个元素,实际只需k个存储单元。因此,对于非完全二叉树,宜采用下面的链式存储结构。,2K-1,2二叉链表存贮结构,(1)二叉链表表示 将一个结点分成三部分,一部分存放结点本身信息,另外两部分为指针,分别存放左、右孩子的地址。,二叉链表中一个结点可描述为:,对于图6-7所示二叉树,用二叉链表形式描述见图6-8。,(2)二叉链表的类型说明 二叉链表的数据类型描述如下: typedef struct btnode int data ; /结点数据类型 struct btnode *lchild, *rchild; /定义左、右孩子为指 针型 bitree; 有

15、时,为了便于找到结点中的双亲,还可在结点结构中增加一个指向双亲的指针域,这种存贮结构称为三叉链表。,6.4 遍历二叉树 (二叉树的运算),所谓遍历二叉树,就是遵从某种次序,访问二叉树中的所有结点,使得每个结点仅被访问一次。这里提到的“访问”是指对结点施行某种操作,操作可以是输出结点信息,修改结点的数据值等,但要求这种访问不破坏它原来的数据结构。在本书中,我们规定访问是输出结点信息data,且以二叉链表作为二叉树的存贮结构。遍历对线性结构而言非常简单,只需顺序扫描每个数据元素即可。但对非线性结构,要找到一种规律,以便二叉树上各结点能排列成一个线性序列。,二叉树由三部分组成:根结点(D),左子树(

16、L),右子树(R)。要遍历这三个基本部分,可有六种可能的顺序:DLR(先序或前序)DRL(逆先序遍历)LDR(中序)RDL(逆中序)LRD (后序) RLD(逆后序) 规定:二叉树中必须先左后右(左右顺序不能颠倒),则只有DLR、LDR、LRD三种遍历规则。 DLR称为前根遍历(或前序遍历、先序遍历、先根遍历),LDR称为中根遍历(或中序遍历),LRD称为后根遍历(或后序遍历)。,6.4.1先序遍历 所谓先序遍历,就是根结点最先遍历,其次左子树,最后右子树。,递归遍历,先序遍历二叉树的递归遍历算法描述为: 若二叉树为空,则算法结束;否则 (1)输出(访问)根结点; (2)再按先序遍历方式遍历根

17、结点的左子树; (3)最后按先序遍历方式遍历根结点的右子树;,递归算法如下: void preorder(bitree *root) if(root!=NULL) printf(“%d”,root-data);preorder(root-lchild);preorder (root-rchild); ,6.4.2中序遍历 所谓中序遍历,就是根在中间,先左子树,然后根结点,最后右子树。,递归遍历,中序遍历二叉树的递归遍历算法描述为: 若二叉树为空,则算法结束;否则 中序遍历左子树; 输出根结点; 中序遍历右子树。,算法如下: void inorder(biteee *root) if (root

18、!=NULL) inorder(root-lchild);printf(“%d”,root-data);inorder(root-rchild); ,6.4.3 后序遍历 所谓后序遍历,就是根在最后,即先左子树,然后右子树,最后根结点。,递归遍历,后序遍历二叉树的递归遍历算法描述为: 若二叉树为空,则算法结束;否则 (1)后序遍历左子树: (2)后序遍历右子树; (3)访问根结点。,算法如下: void postorder( bitree *root) if (root!=NULL) postorder (root-lchild);postorder (root-rchild);printf(

19、“%d”,root-data); ,例如,可以利用上面介绍的遍历算法,写出如下图所示二叉树的三种遍历序列为:,先序遍历序列:ABDGCEFH 中序遍历序列: BGDAECFH 后序遍历序列: GDBEHFCA例题,另外,在编译原理中,有用二叉树来表示一个算术表达式的情形。在一棵二叉树中,若用操作数代表树叶,运算符代表非叶子结点,则这样的树可以代表一个算术表达式。若按前序、中序、后序对该二叉树进行遍历,则得到的遍历序列分别称为前缀表达式(或称波兰式)、中缀表达式、后缀表达式(逆波兰式)。具体参见图6-12。,右图所对应的前缀表达式: -*abc。 右图所对应的中缀表达式:a*b-c。 右图所对应

20、的后缀表达式:ab*c-。,6.4.4 遍历二叉树的非递归算法,递归算法:简明,但效率较低,且有的程序设计语言不允许函数递归调用。 故要讨论遍历二叉树的非递归算法。 均用栈保存遍历过程中经历的结点的左右孩子(指向孩子的指针),用一维数组SM作为栈存放元素,top为栈顶指针。,1、先序遍历二叉树的非递归算法 利用一个一维数组作为栈,来存储二叉链表中结点,,算法思想为:从二叉树根结点开始,先输出结点信息,沿左子树一直走到末端(左孩子为空)为止,在走的过程中,遇到结点有右孩子的,则把指向结点右孩子的指针进栈,当左子树为空时,从栈顶退出一个指针信息(即退出某结点的右孩子)。如此重复,直到栈为空。,vo

21、id preorder(bitree *root) bitree *p,*s100;int top=0; /top为栈顶指针p=root; do while(p!=NULL) printf(“%d”,p-data);if(p-rchild!=NULL)stop+=p-rchild; p=p-lchild; if(top=0)p=s-top; while(top=0);,2中序遍历二叉树的非递归算法,同样利用一个一维数组作栈,来存贮二叉链表中结点,算法思想为: 从二叉树根结点开始,沿左子树一直走到末端(左孩子为空)为止,在走的过程中,把依次遇到的结点进栈,待左子树为空时,从栈中退出结点并访问,然

22、后再转向它的右子树。如此重复,直到栈空或指针为空止。,算法如下: void inorder ( bitree *root) bitree *p,*s100; /s为一个栈,top为栈顶指针int top=0;p=root; dowhile(p!=NULL)stop +=p;p=p-lchild;if(top=0)p=s-top; printf(“%d”,p-data);p=p-rchild;while(top=0);,6.4.5 遍历算法应用举例,例1 由二叉树的前序序列和中序序列建立该二叉树,分析:若二叉树的任意两个结点的值都不相同,则二叉树的前序序列和中序序列能唯一确定一棵二叉树。 另外,

23、由前序序列和中序序列的定义可知,前序序列中第一个结点必为根结点,而在中序序列中,根结点刚好是左、右子树的分界点,因此,可按如下方法建立二叉树:,1.用前序序列的第一个结点作为根结点;,2.在中序序列中查找根结点的位置,并以此为界将中序序列划分为左、右两个序列(左、右子树);,3.根据左、右子树的中序序列中的结点个数,将前序序列去掉根结点后的序列划分为左、右两个序列,它们分别是左、右子树的前序序列;,4.对左、右子树的前序序列和中序序列递归地实施同样方法,直到所得左、右子树为空。,假设前序序列为ABDGHCEFI,,中序序列为GDHBAECIF,,则得到的二叉树如下页所示,1。A为根结点,A B

24、DGH CEFI,GDHB A ECIF,2. B为左子树的根结点,B DGH,GDH B,3. D为左子树的左子树的根结点,4。C为右子树的根结点,5。F为右子树的右子树的根结点,C E FI,E C IF,思考:能否根据中序、后序求前序?能否根据前序、后序求中序?,例2 按层次遍历一棵二叉树,对于一棵二叉树,若规定遍历顺序为从上到下(上层遍历完才进入下层),从左到右(同一层从左到右进行,这样的遍历称为按层次遍历:例1的树的层次遍历序列为:ABCDEFGHI。下面用一个一维数组来模拟队列,实现二叉树的层次遍历。,Void lorder (bitree * t) bitree *qmaxsiz

25、e,*p; / maxsize为最大容量 int f,r; / f,r类似于头尾指针 q0=t; f=r=0;while (fdata);if(p -lchild!=NULL) r+; qr=p-1child; /入队if (p-rchild!=NULL) r+; qr=p-rchild; /入队 ,作业: 1、一棵度为2的树与一棵二叉树有何区别? 2、用一维数组存放的一棵完全二叉树:ABCDEFGHIJKL,写出该二叉树的前序、中序、后序遍历序列。 3、假设一棵二叉树的前序序列为EBADCFHGIKJ和中序序列为ABCDEFGHIJK,请写出二叉树的后序遍历序列。 4、假设一棵二叉树的中序序

26、列为DCBGEAHFIJK和后序序列为DCEGBFHKJIA。请写出二叉树前序遍历序列。,6.5 二叉排序树(二叉搜索树,二叉查找树) 1什么是二叉排序树,二叉排序树(Binary Sorting Tree),它或者是一棵空树,或者是一棵具有如下特征的非空二叉树: (1)若它的左子树非空,则左子树上所有结点的关键字均小于根结点的关键字; (2)若它的右子树非空,则右子树上所有结点的关键字均大于等于根结点的关键字; (3)左、右子树本身又都是一棵二叉排序树。 下图各例是否为二叉排序树?(为了讨论问题的方便,假设树中每个结点的值是一个十进制整数),2、下面给出构造二叉排序树的算法: 将一个给定的数

27、据元素构造为相应的二叉排序树,通常采用逐步插入结点的方法来构造二叉排序树。 设k=k1,k2,.,kn为数据元素序列,从k1开始依次取序列中的元素,每取出一个元素ki,按下列原则建立二叉排序树的一个新结点: (1)若二叉排序树为空,则新的数据元素就是二叉排序树的根结点。 (2)若二叉排序树非空,则将新的数据元素与该二叉树的根结点的值进行比较,若小于根结点的值,则将新的数据元素插入到根结点的左子树中;否则,插入到右子树中。 这个过程是一个递归的过程,因为数据元素插入到左子树或右子树也同样是按这个原则递归进行的。(例),例如,结定关键字序列79,62,68,90,88,89,17,5,100,12

28、0,生成二叉排序树过程如下图所示。,(注:排列顺序不一样,得到的二叉排序树也不一样),二叉排序树与关键字排列顺序有关吗?,a、递归算法 bitree *Inserttree(bitree *t, int x) if(t=NULL)t=( bitree *)malloc(sizeof(bitree);t-data=x;t-lchild=NULL; t-rchild=NULL;else,若二叉排序树为空,则新的数据元素就是二叉排序树的根结点。,if(xdata)t-lchild=Inserttree(t-lchild,x);elset-rchild=Inserttree(t-rchild,x);r

29、eturn(t); b、生成二叉排序树的非递归算法:bitree *creat(bitree *t) bitree *s,*p,*q;int x;,若二叉排序树非空,则将新的数据元素与该二叉树的根结点的值进行比较,若小于根结点的值,则将新的数据元素插入到根结点的左子树中;否则,插入到右子树中。,scanf(“%d”,while(p) q=p;if(s-datadata) p=p-lchild;else p=p-rchild; if(s-datadata)q-lchild=s; elseq-rchild=s; /插入结点算法,scanf(“%d”, ,3、二叉排序 树上的查找(检索算法),(1)

30、二叉排序 树的查找思想 若二叉排树为空,则查找 失败,否则,先拿根结点值与待查值进行比较,若相等,则查找成功,若根结点值大于待查值,则进入左子树重复此步骤,否则,进入右子树重复此步骤,若在查找过程中遇到二叉排序树的叶子结点时,还没有找到待找结点,则查找不成功。 (2)二叉排序树查找的算法实现,a、递归算法:,bitree *bstsrch(bitree *t,int k) if(t=NULL)|(t-data=k)return(t);else if(t-data rchild,k);elsereturn(bstsrch(t-lchild,k);,b、非递归算法,bitree *search(b

31、itree *t,int k) while(t!=NULL) if(t-data=k)return(t);else if(t-datarchild;elset=t-lchild;return(NULL); ,4、删除运算 在二叉排序树上删除一个结点需注意:要保证删除后所得的二叉树仍是一棵二叉检索树。考虑下面三种情况: 1)若要删除的是叶子结点最简单的一种,只要将其双亲结点与它之间的链接的指针置空即可。如图2)若要删除的结点只有左子树或只有右子树,即单支结点。 a、若被删除的结点没有左子树,则可用其右子树的根结点取代被删除结点的位置。 b、若被删除结点没有右子树,则可用其左子树的根结点取代被删除

32、结点的位置。,3)若删除的结点具有左、右子树。,方法:首先将该结点的中序前趋结点的值赋给该结点的值,然后再删除它的中序前趋结点。由于此时,它的中序前趋结点的右指针为空,只要将中序前趋结点的左指针链接到中序前趋结点所在的链接位置即可。,5二叉排序树查找的性能分析,在二叉排序树查找中,成功的查找次数不会超过二叉树的深度,而具有n个结点的二叉排序树的深度,最好为 log2(n+1) ,最坏为n。因此,二叉排序树查找的最好时间复杂度为O(log2n),最坏的时间复杂度为O(n),一般情形下,其时间复杂度大致可看成O(log2n),比顺序查找效率要好,但比二分查找要差。即使关键字相同的一组数据,若先后插

33、入的次序不同,所生成的二叉排序树也不同,则查找的时间性能也不同,当要求查找的性能较高时,要对构成二叉排序树的过程进行“平衡化”处理,形成二叉平衡树。,6.6 平衡二叉树 1平衡二叉树的概念,平衡二叉树(balanced binary tree)是由阿德尔森一维尔斯和兰迪斯(Adelson-Velskii and Landis)于1962年首先提出的,所以又称为AVL树。,平衡二叉树:若一棵二叉树中每个结点的左、右子树的深度之差的绝对值不超过1,则称这样的二叉树为平衡二叉树。 平衡因子:将该结点的左子树深度减去右子树深度的值,称为该结点的平衡因子(balance factor)。 也就是说,一棵

34、二叉排序树中,所有结点的平衡因子只能为0、1、-1时,则该二叉排序树就是一棵平衡二叉树,,2. 非平衡二叉树的平衡处理,若一棵二叉排序树是平衡二叉树,扦入某个结点后,可能会变成非平衡二叉树,这时,就可以对该二叉树进行平衡处理,使其变成一棵平衡二叉树。 处理的原则应该是处理与扦入点最近的、而平衡因子又比1大或比-1小的结点。下面将分四种情况讨论平衡处理。,(1)LL型 的处理(左左型) 如图7-10所示,在C的左孩子B上扦入一个左孩子结点A,使C的平衡因子由1变成了2,成为不平衡的二叉树序树。这时的平衡处理为:将C顺时针旋转,成为B的右子树,而原来B的右子树则变成C的左子树,待扦入结点A作为B的

35、左子树。(注:图中结点旁边的数字表示该 结点的平衡因子),(2)LR型的处理(左右型) 如图7-11所示,在C的左孩子A上扦入一个右孩子B,使的C的平衡因子由1变成了2,成为不平衡的二叉排序树。这是的平衡处理为:将B变到A与C 之间,使之成为LL型,然后按第(1)种情形LL型处理。,(3)RR型的处理(右右型) 如图7-12所示,在A的右孩子B上扦入一个右孩子C,使A的平衡因子由-1变成-2,成为不平衡的二叉排序树。这时的平衡处理为:将A逆时针旋转,成为B的左子树,而原来B的左子树则变成A的右子树,待扦入结点C成为B的右子树。,(4)RL型的处理(右左型) 如图7-13所示,在A的右孩子C上扦

36、入一个左孩子B,使A的平衡因子由-1变成-2,成为不平衡的二叉排序树。这时的平衡处理为:将B变到A与C之间,使之成为RR型,然后按第(3) 种情形RR型处理。,例1,给定一个关键字序列4,5,7,2,1,3,6,试生成一棵平衡二叉树。 分析:平衡二叉树实际上也是一棵二叉排序树,故可以按建立二叉排序树的思想建立,在建立的过程中,若遇到不平衡,则进行相应平衡处理,最后就可以建成一棵平衡二叉树。具体生成过程见图7-14。,例2:给定一个关键字序列13,24,37,90,53,试生成一棵平衡二叉树。 作业:将一组关键字(47,16,21,36,29,59,19,54)生成一二叉平衡树。,3平衡二叉树的

37、查找及性能分析 平衡二叉树本身就是一棵二叉排序树,故它的查找与二叉排序树完全相同。但它的查找 性能优于二叉排序树,不像二叉排序树一样,会出现最坏的时间复杂度O(n),它的时间复杂度与二叉排序树的最好时间复杂相同,都为O(log2n)。 一般二叉平衡树主要应用于查找。,例3,对例1给定的关键字序列4,5,7,2,1,3,6,试用二叉排序树和平衡二叉树两种方法查找,给出查找6的次数及成功的平均查找长度。 分析:由于关键字序列的顺序己经确定,故得到的二叉排序树和平衡二叉树都是唯一的。得到的平衡二叉树见图7-14,得到的二叉排序树见图7-15。,从图7-15的二叉排序树可知,查找6需4次,假设7个记录

38、的查找概率相等,为1/7,则该二叉排序树的平均查找长度为ASL=(1+2+2+3+3+3+4)/7=18/72.57。 从图7-16的平衡二叉树可知,查找6需2次,平均查找长度 ASL=(1+2+2+3+3+3+3)/7=17/72.43。,从结果可知,平衡二叉树的查找性能优于二叉排序树。,#include“h1.h“ #include #include bitree *creat(bitree *t) bitree *s,*p,*q;int x;printf(“input the nodes value:0-ENDn“);scanf(“%d“,if(s-datadata)q-lchild=s

39、;elseq-rchild=s; printf(“input the nodes value:n“);scanf(“%d“, ,湖南大学01-03,1、树最合适用来表示_。 A 有序数据元素 B 无序数据元素 C 元素之间无联系的数据 D元素之间分支层次关系的数据 2、中序遍历二叉排序树就可以得到排好序的结点序列。( )(判断正误),一维数组存放一棵完全二叉树: ABCDEFGHIJK,请给出该二叉树的后序遍历序列。算法设计题略,1、在二叉排序树上成功地找到一个结点,在平均情况下的时间复杂性是 , 在最坏情况下的时间复杂性是 。设结点个数为 n,以大O形式给出时间复杂性。2、已知一棵二叉树是以

40、二叉链表的形式存储的,其结点结构说明如下:(本题10 分。) struct node int data; / 结点的数据场。 struct node *left; / 给出结点的左儿子的地址。 struct node * right; / 给出结点的右儿子的地址。 ; 请在1、2二题的 处进行填空,完成题目要求的功能。注意,每空只能填一个语句,多填为 0 分。(1) 求出以T 为根的二叉树或子树的结点个数。 int size (struct node * T ) if ( ) return 0; else ; ( 2) 求出以T为根的二叉树或子树的高度。注:高度定义为树的总的层次数。 int

41、height(struct node * T ) if ( T = NULL ) ; else ; ,上海交通大学2004年数据结构考研试题,提示: 用递归形式,O(log2n) O(n) T = NULL return ( 1 +size(T-left) + size(T-right) )return 0 return 1 +( ( height(T-left) height(T-right)? height(T-left): height(T-right) ),6.7线索二叉树 6.7.1 线索的概念,遍历二叉树:就是将树中所有结点排成一个线性序列。好处:在这样的线性序列中,很容易求得某个

42、结点在某种遍历下的直接前驱和后继。,带来麻烦,希望不进行遍历就能快速找到某个结点在某种遍历下的直接前驱和后继,这样,就应该把每个结点的直接前驱和直接后继记录下来。为了做到这一点,可以在原来的二叉链表结点中,再增加两个指针域,一个指向前驱,一个指向后继,但这样做将会浪费大量存贮单元,存贮空间的利用率相当低(一个结点中有4个指针,1个指左孩子,1个指右孩子,1个指前驱,1个指后继),而原来的左、右孩子域有许多空指针又没有利用起来。,为了不浪费存贮空间,我们利用原有的孩子指针为空时来存放直接前驱和后继,这样的指针称为“线索”(thread),加线索的过程称为线索化,加了线索的二叉树,称为线索二叉树,

43、对应的二叉链表称为线索二叉链表(简称为线索链表)。在线索二叉树中,由于有了线索,无需遍历二叉树就可以得到任一结点在某种遍历下的直接前驱和后继。但是,我们怎样来区分孩子指针域中存放的是左、右孩子信息还是直接前驱或直接后继信息呢?为此,在二叉链表结点中,还必须增加两个标志域ltag、rtag。,ltag和rtag定义如下:,0 lchild域指向结点的左孩子 ltag= 1 lchild域指向结点在某种遍历下的直 接前驱,0 rchild域指向结点的右孩子 rtag= 1 rchild域指向结点在某种遍历下的直接后继,这样,二叉链表中每个结点还是有5个域,但其中只有2个指针,较原来的4个指针要方便

44、。增加线索后的二叉链表结点结构可描述如下:,2线索的分类,另外,根据遍历的不同要求,线索二叉树可以分为: (1)前序前驱线索二叉树(只需画出前驱) (2)前序后继线索二叉树(只需画出后继),(3)前序线索二叉树(前驱和后继都要标出) (4)中序前驱线索二叉树(只需画出前驱) (5)中序后继线索二叉树(只需画出中序后继) (6)中序线索二叉树(中序前驱和后继都要标出) (8)后序前驱线索二叉树(只需画出后序前驱) (8)后序后继线索二叉树(中需画出后序后驱) (9)后序线索二叉树(前驱和后继都要标出),6.7.2线索的描述,1结点数据类型描述,typedef struct bithrnode i

45、nt data;int ltag ,rtag; /左、右标志域struct bithrnode *lchild, *rchild;binode ;,2线索的画法,在二叉树或二叉链表中,若左孩子为空,则画出它的直接前驱,右孩子为空时,则画出它的直接后继,左右孩子不为空时,不需画前驱和后继。这样就得到了线索二叉树或线索二叉链表。,前序序列为:ABCD,中序序列为:BADC,后序序列为:BDCA,仿线性表的存储结构,在二叉树的线索链表上添加一个头结点,其中lchild指向根结点,rchild指向自己,并且原先指向空的线索均指向该头结点。如此处理,使得在线索二叉树中查找某结点的前趋、后继结点的算法中不

46、必再判断线索是否为空的情况。,6.8 树和森林 6.8.1 树、森林和二叉树的转换 1树转换成二叉树,可以分为三步: (1) 连线 指相邻兄弟之间连线,加一虚线。,(2) 抹线 指抹掉双亲与除最左孩子外其它孩子之间的连线。,(3) 旋转 只需将树作适当的旋转,具体:将图形上原有的实线均向左斜,加上的虚线均向右斜,且变成实线,调整成二叉树的树型结构。,具体实现过程见图7-20。,由转换可知:在二叉树中,左分支上的各结点在原来的树中是父子关系,而右分支上的各结点在原来的树中是兄弟关系。,由于根结点没有兄弟,所以变换后的二叉树的根结点的右孩子必为空,2森林转换成二叉树,(1) 将森林中每一棵树分别转

47、换成二叉树 这在刚才的树转换成二叉树中已经介绍过。,(2)合并 使第n棵树接入到第n-1棵的右边并成为它的右子树,第 n-1 棵二叉树接入到第n-2 棵的右边并成为它的右子树,第2棵二叉树接入到第1棵的右边并成为它的右子树,直到最后剩下一棵二叉树为止。,3二叉树还原成树,与树转换成二叉树的步骤刚好相反: a. 加线:若某节点I是双亲节点的左孩子,则将该节点的右孩子及沿着此右孩子的右链不断搜索到的所有右孩子,都分别与节点I的双亲节点用虚线连接起来。 b. 抹线:抹掉原二叉树中所有双亲节点与右孩子的连线。 c. 旋转:将树中虚线均变为实线,并按层次排好。,A,B,E,C,D,F,A,B,C,D,E

48、,F,调整后,A,B,C,D,E,F,4. 二叉树还原成森林,(1) 右链断开(即抹线) 将二叉树的根结点的右链及右链的右链等全部断开,得到若干棵无右子树的二叉树。 具体操作见图7-21(b)。 (2) 二叉树还原成树,具体操作步骤见图7-21(c)。,6.8.2 树和森林的遍历,在树和森林中,一个结点可能有两棵以上的子树,因而不便讨论它们的中序遍历。故树和森林的遍历通常有两种方式,先序遍历和后序遍历。 下面分别讨论:,(1)树的先序遍历 若树非空,则先访问根结点,然后按照从左到右的顺序先序遍历各子树。 例: (2)树的后序遍历 若树非空,则依次后序遍历各子树,最后访问根结点。 例: 树的先序遍历与其转换的相应的二叉树的先序遍历的结果序列相同;后序遍历与相应二叉树的中序序列相同。,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报