1 / 192

第六章 树

第六章 树. 6.1 树 6.2 二叉树 6.3 二叉树的线索化 6.4 二叉树、树、森林 6.5 哈夫曼树 6.6 其他树. 6.1 树. 把图 6.1 的文件树抽象化,给予每个结点一个字母,从根结点开始编号,可以得到图 6.3 的树。. 6.1.1 树的定义. 树是由 n(n≥0) 个结点的有限集。 当 n=0 时,称此树为空树。当 n≠0 时,称此树为非空树。在一棵非空树中: ( 1 )有且仅有一个特定的称为根的结点。

stacey
Download Presentation

第六章 树

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第六章 树 6.1 树 6.2 二叉树 6.3 二叉树的线索化 6.4 二叉树、树、森林 6.5 哈夫曼树 6.6 其他树

  2. 6.1 树 把图6.1的文件树抽象化,给予每个结点一个字母,从根结点开始编号,可以得到图6.3的树。

  3. 6.1.1 树的定义 树是由n(n≥0)个结点的有限集。 当n=0时,称此树为空树。当n≠0时,称此树为非空树。在一棵非空树中: (1)有且仅有一个特定的称为根的结点。 (2)当n>1时,其余的结点可分为m(m>0)个互不相交的有限集T1,T2,…Tm。其中的每个集合本身又是一棵树,并称为根的子树。

  4. 6.1.1 树的定义 例6.1 分析图6.3的树结构。 解:图6.3中的树是一个有16个结点的树,A为根结点,其余的结点分成T1、T2、T3、T4、T5共5棵互不相交的子树。T1={B}、T2={C,G,H,I}、T3={D}、T4={E}、T5={F,J,K,L,M,N,O,P}。。其中T1、T3、T4是只有一个结点的子树;对于T5,F是根结点,其余的结点可以继续划分成T51、T52,T51= {J,L,M,N},T52={ K,O,P },对于T51还可以继续进行类似的划分。由此,发现树的定义是递归的。

  5. 6.1.1 树的定义 树是一种数据结构,具有: Tree=(D,R) 其中:D是具有相同性质的数据元素的集合;R是D上的二元关系r的集合,即R={r}。若D中只有一个元素,则R为空集。 对于图6.3, D={A,B,…… ,P},R={<A,B>,<A,C>,<A,D>……,<K,P>} 从上述定义中看出,树具有非线性结构,结点之间的关系是一对多的关系。由于一对多的关系,引出了许多与线性表不同的数据结构和算法。

  6. 6.1.2 树的常用术语 树是一种具有复杂关系的数据结构,从树的定义中可以引出如下的常用术语,在后续内容中使用这些概念时将以此为准。下面的说明均以图6.3为例。 度(Degree):结点拥有的子树数叫结点的度。树中各个结点的度的最大值定义为树的度。根结点A的度为5,C的度为3,F的度为2,B的度为0。树A的度为5。 叶子(Leaf):度为0的结点叫终端结点,又称为叶子。 分支结点(Branch node):度不为0的结点叫非终端结点,

  7. 6.1.2 树的常用术语 又叫分支结点,度为1的结点叫单分支结点,度为2的结点叫双分支结点,以此类推。如B,D,E,O,P等为叶子结点;F,K为双分支结点;C,J为三分支结点;A为5分支结点。 孩子(Child):结点的子树叫做该结点的孩子;该结点称为此孩子的双亲(Parent);具有相同双亲结点的结点叫兄弟(Sibling);其双亲结点为兄弟的那些结点叫堂兄弟;从根结点开始到达某个结点的所有结点是该结点的祖先(Ancester);某个结点的所有子树上的结点叫该结点的子孙(Descendent)。

  8. 6.1.2 树的常用术语 如F结点是J,K结点的双亲;B,C,D是兄弟;I,J和L,O是堂兄弟;A,F,K是O,P的祖先,B~P结点是A的后代。 层次(Level):从根结点开始定义起,根为第一层,根的孩子为第二层。若某结点在第l层,其子树的根就在第l+1层。如A为第一层,B~F处于第二层;G~K处于第三层;L~P处于第四层。 树深(Depth):树中结点的最大层次叫树的深度,又叫做树的高度。图6.3的树深为4。

  9. 6.1.2 树的常用术语 有序树和无序树:如果把树中各结点的子树按照从左到右的次序标记,不能互换,则称这样的树为有序树,否则叫无序树。 森林:是n (n≥0) 棵互不相交的树集合。

  10. 6.1.3 树的逻辑表示 树的表示有四种形式:树形表示法,文氏图表示法,凹图表示法和广义表表示法。对于图6.3的树,图6.4给出了该树的文氏图(a)、凹图(b)和广义表(c)三种表示法。

  11. 6.1.3 树的逻辑表示

  12. 6.1.4 树的性质 性质1:树中的结点数等于所有结点的度数和加1。 证明:对于一棵树,除根结点外,每个结点有且只有一个分支连接到该结点的一个孩子,一个结点有几个分支(度)就有几个孩子,所以树的结点数等于所有结点的分支数(度数)之和加上一个根结点,因此,树的结点数等于所有结点的度数和加1。 例6.2,求图6.3所示树的结点数 解:图6.3所有结点的度数D(x)分别为D(A)=5,D(C)=3,

  13. 6.1.4 树的性质 D(F)=2,D(J)=3,D(K)=2,其余的结点度数为0,所以该树的分支数之和为5+3+3+2+2=15,显然该树的结点数为16。 性质2:度为m的树中第i层上至多有mi-1个结点(i≥1),即第i层上的结点数n1≤mi-1= m1-1=1。 证明:使用归纳法进行证明,证明如下: 设i=1,树中只有根结点,n1≤mi-1= m1-1=1,结论显然成立; 假设对于第(i-1)层(i>1)命题成立,即ni-1≤mi-2 (度

  14. 6.1.4 树的性质 为m的树中第i-1层的结点数至多有mi-2个结点数); 对于第i层,因为树的度数为m,树中每个结点至多有m个孩子,所以第i层的结点数至多是第i-1层的m倍,即mi-2×m= mi-1个,故命题成立。 性质3:高度为h的m叉树至多有(mh-1)/(m-1)个结点。 证明:m叉树意味着树的度为m,根据性质2,第i层上的结点数至多为mi-1(i=1,2…h)。当高度为h的m叉树每一层都为满(即每个结点都有m个子结点,第i层的结点为mi-1个)

  15. 6.1.4 树的性质 时,此m叉树拥有的结点数最多,因此m叉树的结点数n至多为: n= m0+ m1+ m2+……+ mh-1=( mh-1)/(m-1) 证毕。 性质4:具有n个结点的m叉树的最小高度为 。 证明:设具有n个结点的m叉树的树高为h,若该树的前第h-1层都是满的(即每一层的结点数都等于mi-1个(i=1,2,h-1)),第h层的结点数可能满,也可能不满,则此树的高度h与结点数n满足如下的关系:

  16. 6.1.4 树的性质 (mh-1-1)/(m-1)<n≤( mh-1)/(m-1) (1) 对(1)式进行整理可得: mh-1<n(m-1)+1≤mh 两边以m为底取对数,则有: h-1<logm(n(m-1)+1)≤h (2) 整理(2)式,有 logm(n(m-1)+1)≤h< logm(n(m-1)+1)+1 h只能取整数,所以: h= 证毕。

  17. 6.1.4 树的性质 例6.3 计算①高度为4的满3叉树的结点数,②具有20个结点的2叉树的最小高度,③具有20个结点的3叉树的最小高度。 解:① (mh-1)/(m-1)=(34-1)/(3-1)=40 ② = = 5 ③ = = 4

  18. 6.1.5 树的存储结构 树的存储结构可以分为顺序存储结构和链表存储结构。这里重点讨论树的链表存储结构。树的链表存储结构分为多重链表和二重链表表示法。除了这种分法,还有双亲存储结构、孩子存储结构和孩子兄弟存储结构。现在分别来讨论这几种存储结构。 1. 多重链表示法 多重链表示法分为定长结点多重链和非定长结点多重链。 (1)定长结点多重链

  19. 6.1.5 树的存储结构 取树的度数m作为每个结点的指针域个数。设树的度为3,则结点逻辑结构为: 结点结构定义为: 定义 6.1 typedef char DataType; typedef struct node { DataType data; /*定义某种类型的结点值*/ struct tnode *next[3];/*定义度为3的指针域的个数,对于任意的m,*/ }tnode; /*可以定义成next[m]*/

  20. 6.1.5 树的存储结构 这种存储方式,因为以树的度数作为指针域,而树中的多数结点度数不会都是树的度数,所以,很多结点将有大量的空闲指针域,因而造成存储空间浪费。 对于度为m的n个结点的树,这种结构中共有nm个指针域,有n-1条边,所以指针域的使用率为: (n-1)/nm≈1/m 当m越大时,存储空间的利用率越低。因此这种方式适合于存储度数小的树。

  21. 6.1.5 树的存储结构

  22. 6.1.5 树的存储结构 (2)非定长结点多重链 每个结点由数据域、度数域、以及由度数来给定的指针域。因而指针域随着度的不同而变化,这就是非定长多重链表示法。其结点的逻辑结构为: 结点结构定义为: 定义 6.2

  23. 6.1.5 树的存储结构 typedef char DataType; typedef struct node { DataType data; /*定义某种类型的结点值*/ int degree; /*定义结点的度*/ struct tnode *next[degree]; /*根据结点的度定义指针域*/ }tnode; 对于图6.5(a)的 树,其存储结构表示 如图6.6。

  24. 6.1.5 树的存储结构 2. 二重链表示法 树中每个结点设置三个域:数据域、长子指针域firstC和次弟指针域secendC,其逻辑结构如: 结点结构定义为: 定义 6.3

  25. 6.1.5 树的存储结构 typedef char DataType; typedef struct node { DataType data; struct tnode *firstC,*secondC; /*定义指向长子和次子的指针域*/ }tnode; 此时,图6.5(a)的 树表示成图6.7。

  26. 6.1.5 树的存储结构 采用这种结构时,图6.5(a)的树可以表示成图6.7。 这种结构实际上与后面讨论的二叉树的结构极为相似,所以树的这种存储结构容易转换成二叉树的存储结构。 3. 双亲存储结构 双亲存储结构使用一个连续的内存空间存储树的所有结点,每个结点用一个附加的指针域来指示其双亲结点的位置。根结点无双亲结点,指针域的值设置成-1,孩子结点的伪指针设置为双亲结点的存储地址。这种结构可以定义如下:

  27. 6.1.5 树的存储结构 定义 6.4 typedef char DataType; typedef struct node { DataType data; int father; /*定义结点指向父亲指针*/ }tnode; Tnode t[n]; /*定义一个具有双亲存储结构的数组t*/ int root; /*定义根的父亲指针*/ 这种存储结构首先给根结点编号为0,树中的其他结点从左到

  28. 6.1.5 树的存储结构 右从上到下按1、2、3……的顺序编号,图6.8中的第1行就是图6.5(a)中树的结点的编号。这种编号有两个意义,一个是给出下标来确定结点的位置,另一个是为其孩子生成父亲结点索引号,即上面所说的附加指针域。例如,结点A的下标是0,其孩子B、C、D的指向父亲指针域中存放的值是0;结点E的双亲是C,而C的下标是2,故E的指针域中存放的值为2;其余的结点均按照这样的办法来设计其存储结构,因此就有了图6.8中的第3行的值。显然从图6.8很容易找到各个结点的双亲结点。

  29. 6.1.5 树的存储结构 右从上到下按1、2、3……的顺序编号,图6.8中的第1行就是图6.5(a)中树的结点的编号。这种编号有两个意义,一个是给出下标来确定结点的位置,另一个是为其孩子生成父亲结点索引号,即上面所说的附加指针域。 例如,结点A的下标是0,其孩子B、C、D的指向父亲指针

  30. 6.1.5 树的存储结构 域中存放的值是0;结点E的双亲是C,而C的下标是2,故E的指针域中存放的值为2;其余的结点均按照这样的办法来设计其存储结构,因此就有了图6.8中的第3行的值。显然从图6.8很容易找到各个结点的双亲结点。 这种结构很容易从孩子结点找到其双亲结点,但是从双亲结点寻找孩子结点时出现了问题,因为这种结构中没有孩子结点的地址。

  31. 6.1.6 树的基本运算 树是非线性结构,结点间的关系比线性结构要复杂,因此,定义在树结构上的运算比线性结构上的运算要复杂。树的基本运算有三类:查找满足某种特定关系的结点;插入或删除某个结点;遍历树中所有结点并执行某种操作。树的遍历是一种重要的运算,许多其他操作都以它为基础,是本章的重点讨论对象。 树的遍历是指按照某种顺序访问树的每个结点,且只访问一次。根据访问根结点的次序的不同,把遍历分为先(根)序

  32. 6.1.6 树的基本运算 遍历,后(根)序遍历两种遍历方式。 1. 先序遍历 先序遍历是一种树的重要操作,它的算法思想是:首先访问根结点,然后访问根结点的孩子,从左至右,依次访问根的所有孩子。这个算法可以递归定义成下面的形式。 算法6.1 先序递归遍历树的算法 preorder(T,x) {visit(x); /*进行访问结点x的操作*/

  33. 6.1.6 树的基本运算 for z∈children(x) do /* children(x)为x的所有孩子*/ preorder(T,z); /*对于x的所有孩子,递归调用preorder()函数*/ } 其中,visit(x)表示对结点的访问操作。如果对结点的操作是进行记数,需要把visit(x)设计成一个记数器n,初始值为0,每遍历一个结点进行一次n++操作,当遍历结束时就可以得到树中的结点总数n。如果是输出结点的值,visit(x)函数可以写成printf("%c\t",q->data)。所以,在实际应用中,应该根据具体的访问操作来设计visit函数。

  34. 6.1.6 树的基本运算 若执行visit(x)所需的时间为O(1),算法6.1的时间复杂度为T(n)=T(n-1)+O(1)=n×O(1)=n,则访问n个结点所需的时间为O(n)。 根据这个算法,可以画出图6.3的树在先序遍历下的遍历情况(如图6.9)。在先序遍历下,如果对结点的操作是输出结点的值,则得到的元素值序列为ABCGHIDEFJLMNKOP。

  35. 6.1.6 树的基本运算

  36. 6.1.6 树的基本运算 2. 后序遍历 后序遍历也是一种重要的操作,它的思想是:首先访问根结点的孩子,从左至右,依次访问根的所有孩子,最后访问根结点。这个算法可以递归定义成下面的形式。 算法6.2 后序递归遍历树的算法 postorder(T,x) { for z∈children(x) do /* children(x)为x的所有孩子*/ postorder(T,z); /*对于x的所有孩子,递归调用preorder()函数*/ visit(x); /*进行访问结点x的操作*/ }

  37. 6.1.6 树的基本运算 若执行visit(x)所需的时间为O(1),算法6.2的时间复杂度的计算与算法6.1类似,也是O(n)。 根据这个算法,可以画出图6.3的树在后序遍历下的遍历情况(如图6.10)。如果访问树的结点的操作是输出结点的值,则后序遍历得到的结点序列为:BGHICDELMNJOPKFA。

  38. 6.1.6 树的基本运算

  39. 6.1.6 树的基本运算 树的后序遍历有广泛的用途,它的一种应用将在6.6.8节中进行讨论。 例6.4 图6.11是一棵磁盘文件系统,图中的数字表示该文件或文件夹的大小,求该磁盘文件树所需的磁盘空间数。

  40. 6.1.6 树的基本运算 解:要计算图6.11中/home/user/下的文件树所需的磁盘容量,可以把算法6.2中的visit(x)设计成对每个子文件夹中的文件大小进行求和,最后把求和一直进行到根元素。在每个子文件夹的计算中,先计算子文件夹下各个文件的大小,然后返回到子文件夹,给出该子文件夹下文件的大小;每个子文件夹进行类似的操作;最后返回到根,从而得到该文件树所需要的磁盘空间大小(计算结果标在图6.11中)。这种运算在文件管理中经常使用。

  41. 6.1 二叉树 当树的度m为2时,m叉树变成只有两个分支的二叉树。二叉树是一种十分重要的树。具有十分广泛的应用。可以用二叉树进行查找排序、表示算术表达式、解决决策问题等。研究二叉树可以为理解计算机中的某些问题提供解决方案。图6.2中的判断树可以抽象化成图6.12。

  42. 6.2.1 二叉树的定义 定义:二叉树是由n(n≥0)个结点的有限集。它或为空树,或为非空树,对于非空树有: (1)有且仅有一个特定的称为根的结点。 (2)除根结点外,其余结点分为互不相交的左子树Tl和右子树Tr,其中,每个子树本身又是一棵树,它们的孩子也构成二叉树,所以二叉树的定义是递归定义。 二叉树是一种数据结构: Binary_Tree=(D,R)

  43. 6.2.1 二叉树的定义 其中:D是具有相同性质的数据元素的集合;R是D上二元关系r的集合,若D为空,则R为空集,称此二叉树为空二叉树。 根据这个定义,二叉树有如图6.13的五种基本形态,任何复杂的二叉树形态都可以用这五种基本形态组合起来表示。

  44. 6.2.2 二叉树的性质 性质1:二叉树T第i (i≥1)层上的结点数ni至多有2i-1个,即ni≤2i-1。 证明:利用数学归纳法进行证明。 首先,当i=1,只有一个根结点,n1≤2i-1=20=1,命题显然成立。 假设对于第(i-1)层(i>1)命题成立,即ni-1≤2(i-1)-1=2i-2。 对于第i层,由于二叉树的度为2,因此树中每个结点至多有2个孩子,第i层上的结点数最多是第i-1层的2倍,所以:

  45. 6.2.2 二叉树的性质 ni-1≤2×ni-1≤×2i-2=2i-1 证毕。 此性质也可以从树的性质2推导得出,读者可以自行推导。 性质2:深度为k(k≥1)的二叉树T结点数n至多有2 k-1个,即n≤2 k-1。 证明:树深为k,则此二叉树共有k层,深度为k的二叉树的结点数就是这k层结点数之和,根据性质1,有:

  46. 6.2.2 二叉树的性质 n=n1+n2+……+nk ≤20+21+22+……+2k-1 =2 k-1 证毕。 此性质也可以从树的性质3推导得出,读者不妨自行推导。 性质3:具有n个结点的二叉树T的高度至少为 。 证明: 设树T的高度为h,根据性质2,该树满足:

  47. 6.2.2 二叉树的性质 n≤2 h-1 n<2 h 两边以2为底取对数,得 h>log2n log2n为实数,h为整数,因此有。 证毕。 性质4:在任意二叉树T中,若叶子结点个数为n0,度为1的结点数为n1,度为2的结点数为n2,那么n0= n2+1。

  48. 6.2.2 二叉树的性质 证明: 设:n为T的结点总数,n0,n1,n2分别为叶子结点数,1分支结点数,2分支结点数。则 n= n0+ n1+ n2 (1) 设B为二叉树的总分支数,除根结点外,每个结点都有一个分支进入,则 B=n-1 (2) 这些分支由度数为1和度数为2的结点发出,所以有:

  49. 6.2.2 二叉树的性质 B= n1+ 2n2 (3) 从(1)、(2)、(3)可得:n0= n2+1 证毕。

  50. 6.2.2 二叉树的性质 几个重要概念:深度为k并且包含2k-1个结点的二叉树叫满二叉树,如图6.14(a)。对满二叉树的结点进行编号,从根结点开始自上而下,从左到右编号,如图6.14(a)中的数字。深度为k,含有n(n<2k-1)个结点,且每个结点的编号与满二叉树中1~n个结点的编号对应的树叫完全二叉树,如图6.14(b)。不满足此条件的二叉树叫非完全二叉树,如图6.14(c)(d)。 性质5:具有n个结点的完全二叉树T树深为。 证明:

More Related