第六章 树完整.docx
- 文档编号:30080371
- 上传时间:2023-08-04
- 格式:DOCX
- 页数:48
- 大小:774.12KB
第六章 树完整.docx
《第六章 树完整.docx》由会员分享,可在线阅读,更多相关《第六章 树完整.docx(48页珍藏版)》请在冰豆网上搜索。
第六章树完整
第六章树和二叉树
从对线性结构的研究过渡到对树形结构的研究,是数据结构课程学习的一次跃变。
6.1树的定义和基本术语
1.树的定义
树是由n(n0)个结点组成的有限集合。
如果n=0,称为空树;
如果n>0,则:
有一个特定的称之为根(root)的结点,它只有后继,但没有前驱;
其余结点有且仅有一个直接前驱,但可以有0个或多个后继。
判断上述图形是不是一棵树?
看它满足不满足定义中的两个条件?
有一个特定的称之为根(root)的结点A,它只有后继,但没有前驱;
其余结点BCDEFGHIJKLM都满足有且仅有一个直接前驱,但可以有0个或多个后继条件。
2、树的基本术语
结点:
一个圆圈就是一个结点。
结点的子树:
结点射出几个分支结点就有几棵子树。
结点A有三棵子树,粉色的方框所划。
结点B有几棵子树?
两棵。
绿色的方框所划。
结点的度:
结点射出的分支数。
结点A的度是3。
B的度是2。
C的度是1。
……
M的度是0。
树的度:
树内各结点度的最大值。
图示树的度是3。
叶子结点(终端):
度为0的结点。
F、G、I、J、K、L、M.
非终端结点:
度不为0的结点。
A、B、C、D、E、H.
结点的层次:
树中根结点的层次为1,下一层结点的层次是2,以此类推。
A的层次是1
B、C、D的层次是2。
E、F、G、H、I、J的层次是3。
K、L、M的层次是4
树的深度:
树中所有结点层次的最大值。
图示树的深度是4
父结点:
结点的前驱称为该结点的父亲。
B、C、D的父亲都是A。
孩子结点:
结点的后继称为该结点的孩子。
A有三个孩子:
分别是B、C、D。
兄弟:
同一个父亲的孩子之间互称兄弟。
B、C、D互为兄弟。
堂兄弟:
兄弟的孩子之间互称堂兄弟。
F和G互称堂兄弟。
有序树、无序树:
如果树中每棵子树从左向右的排列拥有一定的顺序,不得互换,则称为有序树,否则称为无序树。
如果A的三棵子树不能互换,A称为有序树。
如果A的三棵子树的排列顺序是无关紧要的,可以互换,A称为无序树。
填空:
对于一棵具有n个结点的树,该树中所有结点的度数之和为n-1。
6.2二叉树(BinaryTree)
6.2.1二叉树的定义
一、特点:
1、每个结点至多有两棵子树。
(即二叉树中不存在度大于2的结点)
2、二叉树的子树有左右之分,其次序不能任意颠倒。
下面的树是不是二叉树?
判断题
二叉树是度为2的有序树.()
二、二叉树的五种形态
(a)空二叉树
(b)仅有根结点的二叉树
(c)只有左子树,右子树为空的二叉树
(d)只有右子树,左子树为空的二叉树
(e)左右子树均非空的二叉树
6.2.2二叉树的性质
二叉树具有下列5个重要的性质。
【性质1】在二叉树的第i层上最多有
个结点(i≥1)。
证明:
数学归纳法。
当i=1时,2i-1=1;二叉树的第1层上也只有一个根结点,第一层的结点数1<=2i-1,所以命题成立。
假设i=k时命题成立,即第k层上结点数目最多为2k-1,
则i=k+1时,第k+1层上结点数目最多为第k层上的两倍,即2*2k-1=2k+1-1;命题也成立。
综上所述:
命题成立。
选择题:
在二叉树的第三层上最多有几个结点()()
A.3B.4C.5D.6
性质背过,到时候直接用。
【性质2】深度为K的二叉树最多有
个结点(K≥1)。
利用性质1的结论每一层上具有的最大结点数如下表所示:
树的第I层
k
3
2
1
每层结点数
2k-1
...
22
21
20
二叉树所具有的最大结点数=
选择题:
二叉树的深度为4,则二叉树最多有(C)个结点。
A.13B.14
C.15D.16
【性质3】对于任意一棵二叉树BT,如果度为0的结点(即叶子结点)个数为
,度为2的结点个数为
,则
。
证明:
设度为1的结点有n1个,总结点个数为n,分支数为e,
因为二叉树中所有结点的度都小于等于2,所以有下式成立:
n=n0+n1+n2
(总结点数=度为1的结点数+度为2的结点数+度为3的结点数)
除了根结点外,其余结点都有一个分支进入,所以有下式成立:
n=e+1(总结点数=总分支数+1)
又因为这些分支都是由度为1或度为2的结点射出的,所以有下式成立:
e=2n2+n1
综合上面三式:
n0+n1+n2=2n2+n1+1
即n0=n2+1
选择题
假定一棵二叉树中,度为2的结点数为15,度为1的结点数为30,则叶子结点数为(B)。
A.15B.16C.17D.47
定义1:
满二叉树(FullBinaryTree)
一棵深度为k且有2k-1个结点的二叉树称为满二叉树。
下面两棵树是否是满二叉树?
深度是3,但结点数为6,不等于23-1,所以不是满二叉树
深度是4,结点数是15=24-1,所以是满二叉树。
可以对满二叉树的结点进行连续编号,约定编号从根结点起,自上而下,自左至右。
上述满二叉树结点的编号如下图所示:
由满二叉树引出完全二叉树的定义。
定义2:
完全二叉树:
(CompleteBinaryTree)
深度为k,有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号从1至n的结点一一对应时,称之为完全二叉树。
判断一棵二叉树是不是完全二叉树:
1)对二叉树从上到下、自左至右进行编号。
2)对比二叉树结点与同编号满二叉树结点位置是否一一对应;若一一对应,则是完全二叉树;如不一一对应,则不是完全二叉树。
习题:
判断下列二叉树是否是完全二叉树(对二叉树已经编好号了)
二叉树a
每一个结点都与同编号的满二叉树结点一一对应,故是完全二叉树。
二叉树b
从结点6开始与同编号的满二叉树结点不对应,故不是完全二叉树。
二叉树c
也是从结点6开始与同编号的满二叉树结点不对应,故不是完全二叉树。
完全二叉树的另一种定义:
若设二叉树的深度为h,则共有h层。
除第h层外,其它各层(0h-1)的结点数都必须达到最大个数,第h层可以从右向左连续缺若干结点。
(言外之意,第h层也可以为满。
)
判断二叉树是否是完全二叉树,直接根据定义判断就是。
1、2、3层结点数都达到了最大个数,第4层满足从右向左连续缺3个结点。
故是完全二叉树。
第3层结点数都没达到最大个数,故不是完全二叉树。
第1、2层结点数都达到了最大数,但第三层不满足从右往左缺结点。
故不是完全二叉树。
完全二叉树的特点是:
1)只允许最后一层有空缺结点且空缺在右边,即叶子结点只能在层次最大的两层上出现;
2)对任一结点,如果其右子树的深度为j,则其左子树的深度必为j或j+1。
1)显然成立。
3结点右子树的深度是1,左子树的深度是2。
2结点右子树的深度是2,左子树的深度是1。
【性质4】具有n个结点的完全二叉树的深度为log2n+1。
其中,log2n的结果是不大于log2n的最大整数。
证明:
设完全二叉树深度为k,根据二叉树定义,完全二叉树的k-1层上的结点数必须达到最大值,根据性质1,各层结点数最大值如下图所示:
树的第I层
k-1
3
2
1
每层结点数
2k-2
...
22
21
20
k-1层的结点总数为2k-1-1,第k层最少有1个结点,最多有2k-1个结点,所以结点数n满足:
2k-1n<=2k-1即2k-1n<2k
两边取以2为底的对数:
k-1≤log2n<k
log2n<k≤log2n+1;
因为k是整数,所以k=
选择题
一棵完全二叉树有18个结点,则完全二叉树的深度为C.
A.3B.4C.5D.6
一棵具有n个结点的完全二叉树的树高度(深度)是(A)【南京理工大学1996一、8(2分)】
A.log2n+1B.log2n+1C.log2nD.log2n-1
一棵完全二叉树上有1001个结点,其中叶子结点的个数是(B)【西安交通大学1996三、2(3分)】
A.250B.501C.254D.505
解:
在完全二叉树中,度为1的结点数n1或为0或为1。
由性质3可知
又因为n=n0+n1+n2
所以n=2n0+n1-1
将n=1001代入得:
2n0+n1=1002
又因为n0必须为整数,所以n1的值必为0。
所以n0=501
【性质5】如果将一棵有n个结点的完全二叉树的结点按层序(自顶向下,同一层自左向右)连续编号1,2,…,n,对结点i(1in)有以下关系:
⏹若i==1,则i是二叉树的根,无双亲
若i>1,则i的双亲为i/2
⏹若2*i≤n,则i的左孩子为2*i,否则无左孩子
⏹若2*i+1≤n,则i的右孩子为2*i+1,否则无右孩子
证明不做讨论,背过,到时候直接用。
可以这样记:
对于结点i,双亲为i/2,i的左孩子为2*i,i的右孩子为2*i+1。
在上图所示二叉树中,4的父亲是2,左孩子是8,右孩子是9。
6.2.3二叉树的存储结构
1、完全二叉树的顺序存储:
c语言中认为:
将完全二叉树中的结点按照从上至下、自左往右的顺序存储到一维数组中。
31存储到下标为0的数组分量中,23存储到下标为1的数组分量中…依次类推。
普通二叉树的顺序存储:
也是将普通二叉树中的结点按照从上至下、自左往右的顺序存储到一维数组中。
(中间的空缺结点也留出相应的位置)
练习:
画出下图所示二叉树的顺序存储结构
1)把空缺结点补齐
按照从上到下、从左至右的顺序存储到一维数组中,给空缺结点留出相应的位置。
图示二叉树尽管只有3个结点,也要存储到一个长度为7的数组中,浪费存储空间。
结点数为3的单支树,存储空间的浪费还不太明显。
如果存储结点数为30的单支树,需要一个多大的一维数组?
(同学们自算)
把30层的空缺结点全部补齐,共有多少结点?
答:
利用性质2,算出共有230-1个结点。
存储一个30个结点的单支树,要用长度为230-1的数组(1G),微型机根本不支持。
存储空间的浪费异常明显。
怎样来解决这个问题?
不给空缺的结点留位置。
按照从上到下,从左到右的顺序将二叉树的结点存储到一维数组中。
这样30个结点的单支树只需要存储到长度为30的一维数组中。
但是如果二叉树采用这种顺序存储方式会出现什麽样的问题呢?
不给空缺结点留位置,两棵二叉树对应的顺序存储结构如下所示:
第一棵二叉树对应的顺序存储结构
0
1
2
3
4
5
6
31
23
12
4
05
17
8
第二棵二叉树对应的顺序存储结构
0
1
2
3
4
5
6
31
23
12
4
05
17
8
两棵不同的二叉树对应的存储结构是完全相同的。
计算机要严格避免二义性。
不同的二叉树必须对应不同的存储结构。
如果两棵不同的二叉树对应的存储结构是完全相同的,计算机在看到这样的一个数组的时候就不知道它表示的是那棵二叉树了。
用这种方法解决存储空间的浪费是不可行的,寻求别的解决问题的方式。
下面讨论二叉树的链式存储。
2、二叉树的链式存储
1)二叉链表
结点结构:
包含两个指针域和一个数据域:
指针域存储指向左右孩子的指针,数据域存储结点本身的信息。
结点的C语言描述:
structBiTNode{
TElemTypedata;
BiTNode*leftchild,*rightchild;
};
二叉树a的链式存储结构如下图所示:
因每个结点中包含两个指针,所以这种形式的链式存储结构又被称为二叉链表。
课堂练习:
请画出下面二叉树的二叉链表结构。
n个结点的二叉链表共有n+1个空指针域,为什麽?
在含有n个结点的二叉链表中,共有2n个指针域,但实际有效的指针数等于二叉树中的分支数(即n-1),所以共存在n+1个空的指针域。
选择题
10个结点的二叉链表中共有(B)个空的指针域。
A.9B.10C.11D.12
2)三叉链表
结点结构:
包含三个指针域和一个数据域:
指针域存储指向左右孩子的指针以及指向父亲的指针,数据域存储结点本身的信息。
结点的C语言描述:
structBiTNode{
TElemTypedata;
BiTNode*leftchild,*rightchild;
BiTNode*parent;
};
二叉树a的三叉链表结构如下图所示:
无论三叉链表,二叉链表都要会画。
6.3遍历二叉树(TraversingBinaryTree)p144
所谓树的遍历,就是按某种次序访问树中的结点,要求每个结点访问一次且仅访问一次。
遍历的结果:
产生一个关于结点的线性序列。
设访问根结点记作D
遍历根的左子树记作L
遍历根的右子树记作R
则可能的遍历次序有
先序DLRDRL逆先序
中序LDRRDL逆中序
后序LRDRLD逆后序
我们只讲二叉树的先序、中序、和后序遍历。
逆先序、逆中序和逆后序不讲。
先序遍历(PreorderTraversal)
先序遍历二叉树算法的框架是
若二叉树为空,则空操作;
否则
访问根结点(D);
先序遍历左子树(L);
先序遍历右子树(R)。
先序遍历的结果:
+*abc
(学过编译原理的话就会知道这是表达式的前缀形式,又称波兰式)
根据先序遍历二叉树算法的框架写出用c语言表示的算法:
voidPreOrderTraverse(BiTreeT)
{
if(T){
printf("%c",T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
}
中序遍历(InorderTraversal)
中序遍历二叉树算法的框架是:
若二叉树为空,则空操作;
否则
中序遍历左子树(L);
访问根结点(D);
中序遍历右子树(R)。
图示树中序遍历的结果:
a*b-c
(学过编译原理的话就会知道这是表达式的中缀形式)
根据中序遍历二叉树算法的框架写出用c语言表示的算法:
中序遍历二叉树的递归算法
voidInOrderTraverse(BiTreeT)
{
if(T){
InOrderTraverse(T->lchild);
printf("%c",T->data);
InOrderTraverse(T->rchild);
}
}
后序遍历(PostorderTraversal)
后序遍历二叉树算法的框架是
若二叉树为空,则空操作;
否则
后序遍历左子树(L);
后序遍历右子树(R);
访问根结点(D)。
图示树后序遍历的结果(后缀表达式):
ab*c-
后序遍历二叉树的递归算法
voidPostOrderTraverse(BiTreeT)
{
if(T){
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
printf("%c",T->data);
}
}
6.3.2二叉线索链表
写出图示树的中序遍历结果,图示树的二叉链表结构。
图示树按照中序遍历的结果是:
BDAEC
图示树的二叉链表结构:
当以二叉链表作存储结构时,只能找到结点的左右孩子信息,却无法直接得到结点的前驱和后继信息(按照中序遍历次序确定的)。
同时n个结点的二叉树有n+1个空指针域。
能否利用这些空的指针域存储结点的前驱和后继信息(按照中序遍历次序确定的)?
当然是可以的。
利用空的左指针指向它的前驱,利用空的右指针指向它的后继。
我们称这种存储结构为二叉线索链表。
6.2.3二叉线索链表
1、二叉线索链表的结点结构
lpointer
ltag
data
rtag
rpointer
为了区别左指针指向的是左孩子还是前驱,加一个ltag标志位,ltag=0,表示左指针指向的是左孩子;ltag=1表示左指针指向的是前驱。
为了区别右指针指向的是右孩子还是后继,加一个rtag标志位,rtag=0,表示右指针指向的是右孩子;rtag=1表示右指针指向的是后继。
用c语言描述一下结点结构
structBiThrNode
{TElemTypedata;
BiThrNode*lpointer,*rpointer;
intltag,rtag;
};
如果空的左指针指向的是中序遍历下的前驱,空的右指针指向的是中序遍历下的后继,称这种二叉线索链表为中序线索链表。
如果空的左指针指向的是先序遍历下的前驱,空的右指针指向的是先序遍历下的后继,称这种二叉线索链表为先序线索链表。
如果空的左指针指向的是后序遍历下的前驱,空的右指针指向的是后序遍历下的后继,称这种二叉线索链表为后序线索链表。
下面请同学们画出图示二叉树的中序线索链表。
1)画出二叉树的二叉链表
2)把标志位给添上。
有孩子的地方填“0”,没孩子的地方填“1”。
3)根据中序遍历的结果BDAEC把空的指针给补上
在中序遍历下,B是第一个结点,B没有前驱,所以B的左指针仍旧为空。
C是最后一个结点,C没有前驱,所以C的右指针仍旧为空。
如能一步画出当然更好。
为了处理的方便,一般情况下都给线索链表加上一个头结点。
令剩下的两个空指针都指向头结点。
头结点的左指针指向根结点,头结点的右指针指向按中序遍历的最后一个结点。
头结点的左标志是0,右标志是1。
要求:
先序线索链表、后序线索链表都要会画。
山东大学2005硕士研究生考试试题(10分)
写一算法,完成对中序线索二叉树的中序扫描。
也就是怎样根据中序线索二叉树得到二叉树中序遍历的线性序列。
作业:
画出图示树的先序线索链表
先序遍历结果:
ABDCE
6.4树和森林
6.4.1树的存储
1、双亲表示法
主要描述的是结点的双亲关系。
指出结点的双亲是谁。
把图示树的结点按照从上至下从左往右的顺序存储到一维数组中,同时附设一个指示器指示其双亲结点
在数组中的位置。
解释:
ABC的双亲是R,DE的双亲是A,F的双亲是C,GHK的双亲是F。
用c语言描述一下这个数组。
每一个元素都是两项的组合,可以考虑用结构体表示。
元素类型是结构体类型
structPTNode{//元素类型
TElemTypedata;
intparent;//双亲位置
};
此数组一共有7个元素
PTNodeTREE[7];
此种存储结构找结点的双亲容易,找结点的孩子困难。
2、孩子表示法
主要描述的是结点的孩子关系。
指出结点的孩子有哪些。
由于每个结点的孩子个数不一定相等,所以利用链式存储结构更加适宜。
把每个结点的孩子都用一条链把它们串起来。
(父亲牵着丢不了)
用C语言描述一下此种结构:
链表中结点:
structCTNode{//孩子结点
intchild;
CTNode*next;
};
数组中结点:
structCTBox{
TElemTypedata;
CTNode*firstchild;
//孩子链表头指针
};
整个数组:
CTBoxTREE[9];
下一种方法是上述两种方法的组合,称之为孩子双亲表示法
3、孩子双亲表示法
指出结点的父亲是谁,同时指出结点的孩子有哪些。
用C语言描述一下此种结构:
链表中结点:
structCTNode{//孩子结点
intchild;
CTNode*next;
};
数组中结点:
structCTBox{
TElemTypedata;
intparent;
CTNode*firstchild;
//孩子链表头指针
};
整个数组:
CTBoxTREE[9];
4、孩子兄弟表示法(二叉链表表示)
结点的左指针指向结点的第一个孩子结点,右指针指向下一个兄弟结点。
以二叉链表为媒介可以导出树和二叉树之间的一个对应关系。
给定一棵树,可以找到唯一的一棵二叉树与之对应。
图示树对应的二叉树是什麽?
同学们很容易得就可以画出。
练习:
将下面的树转化成二叉树
二叉树都没有右子树,为什麽?
因为树的根结点都没有兄弟。
6.4.2森林与二叉树的转换
1、森林转换成二叉树:
1)将森林中的每一棵树都转化成二叉树
2)第二棵二叉树作为第一棵二叉树的右子树,第三棵二叉树作为第二棵二叉树的右子树,依次类推。
例题:
将下面三棵树的森林转化成二叉树。
1)将森林中的每一棵树都转化成二叉树。
2)第二棵二叉树作为第一棵二叉树的右子树。
第三棵二叉树作为第二棵二叉树的右子树。
思考:
怎样用计算机实现转换过程?
(本是数据结构课程学习的重点。
)
2、二叉树转化成森林(跟上述过程相反的过程)
1)分解二叉树
取二叉树的根及左子树为第一棵二叉树,取其右子树的根及左子树为第二棵二叉树。
。
。
依次类推。
2)把没有右子树的二叉树转化成树。
思考:
怎样用计算机实现转换过程?
(本是数据结构课程学习的重点。
)
6.4.3树与森林的遍历
1、树的遍历(先根遍历、后根遍历、层次遍历)
(1)先根遍历:
先根访问树的根结点,然后依次先根遍历根的每棵子树
(2)后根遍历:
先依次后根遍历每棵子树,然后访问根结点
图示树的先根遍历结果:
ABCDE
图示树的后根遍历结果:
BDCEA
对应二叉树的先序遍历结果:
ABCDE
对应二叉树的中序遍历结果:
BDCEA
由此可见:
树的先根遍历等价于转换后的二叉树的先序遍历
树的后根遍历等价于转换后的二叉树的中序遍历
2、森林的遍历
(1)先根次序遍历的规则:
访问F的第一棵树的根结点;
先根次序遍历第一棵树的子树森林;
先根次序遍历其它树组成的森林。
(2)中根次序遍历的规则:
中根次序遍历第一棵树的子树森林;
访问F的第一棵树的根结点;
中根次序遍历其它树组成的森林。
同学们自己回去验证一下:
森林的先序遍历:
对应二叉树的先序遍历
森林的中序遍历:
对应二叉树的中序遍历
6.6赫夫曼树(HuffmanTree)及其应用
1、路径长度(PathLength)
两个结点之间的路径长度是连接两结点的路径上的分支数。
树的路径长度是各结点到根结点的路径长度之和。
树a中1和8之间的路径长度是3,1和6之间的路径长度是2。
树a的路径长度=1
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第六章 树完整 第六 完整
![提示](https://static.bdocx.com/images/bang_tan.gif)