版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
二叉树的逻辑结构二叉树的遍历二叉树的存储结构及实现二叉树的应用树的逻辑结构树的存储结构及实现森林第6章二叉树和树本章的主要内容是红楼梦家族关系的组织方式贾母贾政贾赦贾琏贾迎春贾元春贾宝玉贾探春...元素间关系?每个结点最多只有一个前驱,但可有多个后继树的定义树:n(n≥0)个结点的有限集合。当n=0时,称为空树;任意一棵非空树满足以下条件:⑴
有且仅有一个特定的称为根的结点;⑵
当n>1时,除根结点之外的其余结点被分成m(m>0)个互不相交的有限集合T1,T2,…,Tm,其中每个集合又是一棵树,并称为这个根结点的子树。6.1树的逻辑结构树的定义是采用递归方法(a)一棵树结构(b)一个非树结构(c)一个非树结构6.1树的逻辑结构树的定义ACBGFEDHIACBGFDACBGFDE树的应用举例——文件结构6.1树的逻辑结构MyComputerC:D:E:etcWINDOWSProgramFilesPictureMusic…………………………………………树的基本术语结点的度:结点所拥有的子树的个数。树的度:树中各结点度的最大值。6.1树的逻辑结构CGBDEFKLHMIJA6.1树的逻辑结构叶子结点:度为0的结点,也称为终端结点。分支结点:度不为0的结点,也称为非终端结点。CGBDEFKLHMIJA树的基本术语孩子、双亲:树中某结点子树的根结点称为这个结点的孩子结点,这个结点称为它孩子结点的双亲结点;兄弟:具有同一个双亲的孩子结点互称为兄弟。
6.1树的逻辑结构CGBDEFKLHMIJA树的基本术语路径:如果树的结点序列n1,n2,…,nk有如下关系:结点ni是ni+1的双亲(1<=i<k),则把n1,n2,…,nk称为一条由n1至nk的路径;路径上经过的边的个数称为路径长度。CGBDEFKLHMIJA6.1树的逻辑结构树的基本术语祖先、子孙:在树中,如果有一条路径从结点x到结点y,则x称为y的祖先,而y称为x的子孙。6.1树的逻辑结构CGBDEFKLHMIJA树的基本术语结点所在层数:根结点的层数为1;对其余任何结点,若某结点在第k层,则其孩子结点在第k+1层。树的深度:树中所有结点的最大层数,也称高度。1层2层4层3层高度=4CGBDEFKLHMIJC6.1树的逻辑结构树的基本术语CBDEFKLHJA71234568910层序编号:将树中结点按照从上层到下层、同层从左到右的次序依次给他们编以从1开始的连续自然数。6.1树的逻辑结构树的基本术语有序树、无序树:如果一棵树中结点的各子树从左到右是有次序的,称这棵树为有序树;反之,称为无序树。数据结构中讨论的一般都是有序树
6.1树的逻辑结构树的基本术语ACBGFEDACBGFEDCBDEFKLHJ森林:m(m≥0)棵互不相交的树的集合。
6.1树的逻辑结构树的基本术语A树结构和线性结构的比较线性结构树结构第一个数据元素根结点(只有一个)无前驱无双亲最后一个数据元素叶子结点(可以有多个)无后继无孩子其它数据元素其它结点一个前驱,一个后继一个双亲,多个孩子一对一一对多6.1树的逻辑结构二叉树的定义
二叉树是n(n≥0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成。6.2二叉树的逻辑结构问题转化:将树转换为二叉树,从而利用二叉树解决树的有关问题。研究二叉树的意义?二叉树的特点⑴每个结点最多有两棵子树;⑵二叉树是有序的,其次序不能任意颠倒。
6.2二叉树的逻辑结构注意:二叉树和树是两种树结构。ABCDEFGABAB二叉树的基本形态Ф空二叉树只有一个根结点左子树根结点只有左子树右子树根结点只有右子树左子树右子树根结点同时有左右子树6.2二叉树的逻辑结构6.2二叉树的逻辑结构具有3个结点的树和具有3个结点的二叉树的形态二叉树和树是两种树结构。基本术语父结点、左(右)子结点、边<a,b>兄弟(b和c)、祖先、子孙路径(acdf)、路径长度(acdf为3)结点的层数结点的度数(c是2,d是1)二叉树的高度:二叉树中结点的最大层数(4)树叶(b,e,f)、分支结点(a,c,d)abcdef6.2二叉树的逻辑结构特殊的二叉树斜树1.所有结点都只有左子树的二叉树称为左斜树;2.所有结点都只有右子树的二叉树称为右斜树;3.左斜树和右斜树统称为斜树。1.在斜树中,每一层只有一个结点;2.斜树的结点个数与其深度相同。
6.2二叉树的逻辑结构斜树的特点:ABCABC满二叉树如果一棵二叉树的任何结点或者是树叶,或有两棵非空子树,则此二叉树称作“满二叉树”(离散数学中称此树是“正则的”)。满二叉树的特点:只有度为0和度为2的结点。6.2二叉树的逻辑结构特殊的二叉树ABCDEFGHIJKLMNO完全二叉树如果一棵二叉树至多只有最下面的两层结点度数可以小于2,并且最下面一层的结点都集中在该层最左边的若干位置上,则此二叉树称为“完全二叉树”。完全二叉树不一定是满二叉树。6.2二叉树的逻辑结构特殊的二叉树ABCDEFGHIJKLMNOABCDEFGHIJ6.2二叉树的逻辑结构ABCDEFGHIJ不是完全二叉树特殊的二叉树1.叶子结点只能出现在最下两层且最下层的叶子结点都集中在二叉树的左面;2.完全二叉树中如果有度为1的结点,只可能有一个,且该结点只有左孩子。完全二叉树的特点6.2二叉树的逻辑结构特殊的二叉树ABCDEFGHIJ1231145891213671014151231145891267101234567123456哪个是完全二叉树?6.2二叉树的逻辑结构扩充二叉树:扩充的方法是:把原二叉树的结点都变为度数为2的分支结点,也就是说,如果原结点的度数为2,则不变,度数为1,则增加一个分支,度数为0(树叶)增加两个分支。在扩充的二叉树里外部结点(叶结点)都是新增加的结点。外部结点的个数比原来的内部结点个数多1(性质7)。6.2二叉树的逻辑结构扩充二叉树都是满二叉树“外部路径长度”E:在扩充的二叉树里从根到每个外部结点的路径长度之和。“内部路径长度”I:在扩充的二叉树里从根到每个内部结点的路径长度之和。
E=I+2nE=21I=9n=66.2二叉树的逻辑结构二叉树的基本性质
性质6-1二叉树的第i层上最多有2i-1个结点(i≥1)。
证明:当i=1时,第1层只有一个根结点,而2i-1=21-1=1,结论显然成立。假定i=k(1≤k<i)时结论成立,即第k层上至多有2k-1个结点,则
i=k+1时,因为第k+1层上的结点是第k层上结点的孩子,而二叉树中每个结点最多有2个孩子,故在第k+1层上最大结点个数为第k层上的最大结点个数的二倍,即2×2k-1=2(k-1)+1。结论成立。6.2二叉树的逻辑结构性质6-2一棵深度为k的二叉树中,最多有2k-1个结点,最少有k个结点。
证明:由性质1,深度为k的二叉树中结点个数最多==2k-1;每一层至少要有一个结点,因此深度为k的二叉树,至少有k个结点。6.2二叉树的逻辑结构深度为k且具有2k-1个结点的二叉树一定是满二叉树,深度为k且具有k个结点的二叉树不一定是斜树。二叉树的基本性质
性质6-3在一棵二叉树中,如果叶子结点数为n0,度为2的结点数为n2,则有:n0=n2+1。
6.2二叉树的逻辑结构二叉树的基本性质
证明:
设
n1
是度为1结点数,n
是总的结点数.那么
n=设
B
是全部分枝数.则
n~B?n=B+1.因为所有分枝都来自度为1或2的结点,所以B~n1
&n2
?B=n1
+
2n2.
123n0=n2+1
6.2二叉树的逻辑结构n个结点的满二叉树有多少个叶子结点?解:因为在满二叉树中没有度为1的结点,只有度为0的叶子结点和度为2的分支结点,所以,n=n0+n2n0=n2+1
即叶子结点n0=(n+1)/2
二叉树的基本性质
性质6-3在一棵二叉树中,如果叶子结点数为n0,度为2的结点数为n2,则有:n0=n2+1。
性质6-4具有n个结点的完全二叉树的深度为log2n+1。
6.2二叉树的逻辑结构证明:假设具有n个结点的完全二叉树的深度为k,根据完全二叉树的定义和性质2,有下式成立
2k-1
≤n<2k最少结点数最多结点数完全二叉树的基本性质
2k-1-1…2k-1———第k-1层———第k层…2k-16.2二叉树的逻辑结构证明:假设具有n个结点的完全二叉树的深度为k,根据完全二叉树的定义和性质2,有下式成立
2k-1
≤n<2k完全二叉树的基本性质
性质6-4具有n个结点的完全二叉树的深度为log2n+1。
对不等式取对数,有:
k-1≤log2n<k即:
log2n<k≤log2n+1由于k是整数,故必有k=log2n+1
。性质6-5对一棵具有n个结点的完全二叉树中从1开始按层序编号,则对于任意的序号为i(1≤i≤n)的结点(简称为结点i),有:
(1)如果i>1,则结点i的双亲结点的序号为
i/2;如果i=1,则结点i是根结点,无双亲结点。(2)如果2i≤n,则结点i的左孩子的序号为2i;如果2i>n,则结点i无左孩子。(3)如果2i+1≤n,则结点i的右孩子的序号为2i+1;如果2i+1>n,则结点
i无右孩子。
6.2二叉树的逻辑结构完全二叉树的基本性质
i/2结点i的左孩子为2i结点i的右孩子为2i+1
6.2二叉树的逻辑结构性质5表明,在完全二叉树中,结点的层序编号反映了结点之间的逻辑关系。完全二叉树的基本性质
6.在满二叉树中,叶结点的个数比分支结点个数多1。
7.在扩充二叉树中,外部结点的个数比内部结点的个数多1。8.对扩充二叉树,外部路径长度E和内部路径长度I的关系:E=I+2n,n是内部结点个数6.2二叉树的逻辑结构完全二叉树的基本性质
1.具有10个叶结点的二叉树中有()个度为2的结点,【北京航空航天大学2000一、5(2分)】A.8B.9C.10D.ll2.一棵完全二叉树上有1001个结点,其中叶子结点的个数是()【西安交通大学1996三、2(3分)】A.250B.500C.254D.505E.以上答案都不对3.有关二叉树下列说法正确的是()【南京理工大学2000一、11(1.5分)】A.二叉树的度为2B.一棵二叉树的度可以小于2C.二叉树中至少有一个结点的度为2D.二叉树中任何一个结点的度都为24.一个具有1025个结点的二叉树的高h为()【南京理工大学1999一、19(2分)】A.11B.10C.11至1025之间D.10至1024之间6.2二叉树的逻辑结构二叉树的抽象数据类型定义ADTBinTreeisoperationsBinTreecreateEmptyBinTree(void)
创建一棵空的二叉树。BinTreeconsBinTree(BinTreeNoderoot,BinTreeleft,BinTreeright)
返回一棵二叉树,其根结点是root,左右二叉树分别为left和right。intisNull(BinTreet)
判断二叉树t是否为空。
6.2二叉树的逻辑结构由于二叉树的概念是递归定义的,二叉树中的每个结点也可标识以这个结点为根的二叉树,所以二叉树类型和二叉树中结点类型在具体实现时常常看成是同一种类型。
BinTreeNoderoot(BinTreet)
返回二叉树t的根结点。若为空二叉树,则返回一特殊值。BinTreeNodeparent(BinTreet,BinTreeNodep)
返回结点p的父结点。当指定的结点为根时,返回一个特殊值。BinTreeleftChild(BinTreet,BinTreeNodep)
返回p结点的左子树,当指定结点没有左子树时,返回一个特殊值。BinTreerightChild(BinTreet,BinTreeNodep)
返回p结点的右子树,当指定结点没有右子树时,返回一个特殊值。endADTBinTree
二叉树的抽象数据类型定义6.2二叉树的逻辑结构顺序存储结构二叉树的顺序存储结构就是用一维数组存储二叉树中的结点,并且结点的存储位置(下标)应能体现结点之间的逻辑关系——父子关系。
如何利用数组下标来反映结点之间的逻辑关系?完全二叉树中结点的序号可以唯一地反映出结点之间的逻辑关系。6.2.3二叉树的存储结构及实现
A
B
C
D
E
F
G
H
I
J数组下标12345678910完全二叉树的顺序存储6.2.3二叉树的存储结构及实现CDEFGHIJ以编号为下标二叉树的顺序存储ABC∧DE∧∧∧F∧∧G数组下标123456789101112136.2.3二叉树的存储结构及实现ABCDEGF以编号为下标ABCDEGF123561013按照完全二叉树编号一棵斜树的顺序存储会怎样呢?深度为k的右斜树,k个结点需分配2k-1个存储单元一棵二叉树改造后成完全二叉树形态,需增加很多空结点,造成存储空间的浪费。6.2.3二叉树的存储结构及实现二叉树的顺序存储结构一般仅存储完全二叉树ABC137D15二叉链表基本思想:令二叉树的每个结点对应一个链表结点,链表结点除了存放与二叉树结点有关的数据信息外,还要设置指示左右孩子的指针。
结点结构:
LChildData
RChild其中,Data:数据域,存放该结点的数据信息;LChild:左指针域,存放指向左孩子的指针;RChild:右指针域,存放指向右孩子的指针。
6.2.3二叉树的存储结构及实现typedefstructNode{DataTypedata;strctNode*LChild;structNode*RChild;}BiTNode,*BiTree;6.2.3二叉树的存储结构及实现LChild
DataRChild左孩子结点右孩子结点二叉链表GFEDBAABCDEFG∧∧∧∧∧∧∧∧C二叉链表6.2.3二叉树的存储结构及实现具有n个结点的二叉链表中,有多少个空指针?GFEDBAABCDEFG∧∧∧∧∧∧∧∧C二叉链表6.2.3二叉树的存储结构及实现具有n个结点的二叉链表中,有n+1个空指针。三叉链表6.2.3二叉树的存储结构及实现GFEDBAABCDEFG∧∧∧∧∧∧∧∧C在二叉链表中,如何求某结点的双亲?三叉链表
LChildDataParentRChild在二叉链表的基础上增加了一个指向双亲的指针域。结点结构其中:data、lchild和rchild三个域的含义同二叉链表的结点结构;parent域为指向该结点的双亲结点的指针。
6.2.3二叉树的存储结构及实现ABCDEFGA∧B∧D∧E∧F∧CG∧∧∧∧三叉链表6.2.3二叉树的存储结构及实现二叉树的遍历操作
二叉树的遍历是指从根结点出发,按照某种次序访问二叉树中的所有结点,使得每个结点被访问一次且仅被访问一次。二叉树遍历操作的结果?非线性结构线性化6.3二叉树的周游抽象操作,可以是对结点进行的各种处理,这里简化为输出结点的数据。前序遍历中序遍历后序遍历层序遍历
二叉树的遍历方式:DLR、LDR、LRD、DRL、RDL、RLD
如果限定先左后右,则二叉树遍历方式有三种:前序:DLR中序:LDR后序:LRD层序遍历:按二叉树的层序编号的次序访问各结点。
考虑二叉树的组成:根结点D左子树L右子树R二叉树6.3二叉树的周游前序(根)遍历若二叉树为空,则空操作返回;否则:①访问根结点;②前序遍历根结点的左子树;③前序遍历根结点的右子树。二叉树的遍历操作
6.3二叉树的周游ADBCDLRADLRDLR>B>>D>>CDLR前序遍历序列:ABDC前序遍历:6.3二叉树的周游前序遍历序列:ABDGCEFABCDEFG二叉树的遍历操作
6.3二叉树的周游中序(根)遍历若二叉树为空,则空操作返回;否则:①中序遍历根结点的左子树;②访问根结点;③中序遍历根结点的右子树。
二叉树的遍历操作
6.3二叉树的周游LDRBLDRLDR>A>>D>>CLDR中序遍历序列:BDAC中序遍历:ADBC6.3二叉树的周游中序遍历序列:DGBAECFABCDEFG二叉树的遍历操作
6.3二叉树的周游后序(根)遍历若二叉树为空,则空操作返回;否则:①后序遍历根结点的左子树;②后序遍历根结点的右子树。③访问根结点;二叉树的遍历操作
6.3二叉树的周游
LRDLRDLRD>A>>D>>CLRD后序遍历序列:DBCA后序遍历:BADBC6.3二叉树的周游后序遍历序列:GDBEFCAABCDEFG二叉树的遍历操作
6.3二叉树的周游层序遍历二叉树的层次遍历是指从二叉树的第一层(即根结点)开始,从上至下逐层遍历,在同一层中,则按从左到右的顺序对结点逐个访问。
层序遍历序列:ABCDEFGABCDEFG二叉树的遍历操作
6.3二叉树的周游--/+*abcdef二叉树遍历操作练习前序遍历结果:-+a*b-cd/ef中序遍历结果:a+b*c-d-e/f后序遍历结果:abcd-*+ef/-6.3二叉树的周游若已知一棵二叉树的前序(或中序,或后序,或层序)序列,能否唯一确定这棵二叉树呢?ABC例:已知前序序列为ABC,则可能的二叉树有5种。ABC二叉树的遍历操作
6.3二叉树的周游例:已知前序遍历序列为ABC,后序遍历序列为CBA,则下列二叉树都满足条件。ABCABC若已知一棵二叉树的前序序列和后序序列,能否唯一确定这棵二叉树呢?二叉树的遍历操作
6.3二叉树的周游若已知一棵二叉树的前序序列和中序序列,能否唯一确定这棵二叉树呢?怎样确定?
例如:已知一棵二叉树的前序遍历序列和中序遍历序列分别为ABCDEFGHI和BCAEDGHFI,如何构造该二叉树呢?
二叉树的遍历操作
6.3二叉树的周游前序:ABCDEFG
HI中序:BCAEDGHFI前序:BC中序:BC
BCDEFGHIA前序:DEFGHI中序:EDGHFIABCDEFGHI6.3二叉树的周游前序:FG
HI中序:GHFI前序:DEFGHI中序:EDGHFIABCDEFGHIABCDEFIGH6.3二叉树的周游1.根据前序序列的第一个元素建立根结点;2.在中序序列中找到该元素,确定根结点的左右子树的中序序列;3.在前序序列中确定左右子树的前序序列;4.由左子树的前序序列和中序序列建立左子树;5.由右子树的前序序列和中序序列建立右子树。已知一棵二叉树的前序序列和中序序列,构造该二叉树的过程如下:
二叉树的遍历操作
6.3二叉树的周游以二叉链表作为存储结构,讨论二叉树的遍历算法1)先序遍历voidPreOrder(BiTreeroot)/*先序遍历二叉树,root为指向二叉树(或某一子树)根结点的指针*/{ if(root!=NULL) {Visit(root->data);/*访问根结点*/ PreOrder(root->LChild);/*先序遍历左子树*/ PreOrder(root->RChild);/*先序遍历右子树*/ }}2)中序遍历voidInOrder(BiTreeroot)/*中序遍历二叉树,root为指向二叉树(或某一子树)根结点的指针*/{ if(root!=NULL) { InOrder(root->LChild);/*中序遍历左子树*/ Visit(root->data);/*访问根结点*/ InOrder(root->RChild);/*中序遍历右子树*/ }}3)后序遍历voidPostOrder(BiTreeroot)/*后序遍历二叉树,root为指向二叉树(或某一子树)根结点的指针*/{ if(root!=NULL) { PostOrder(root->LChild);/*后序遍历左子树*/ PostOrder(root->RChild);/*后序遍历右子树*
Visit(root->data);/*访问根结点*/ }}建立二叉树为了建立一棵二叉树,将二叉树中每个结点的空指针引出一个虚结点,其值为一特定值如“.”,以标识其为空,把这样处理后的二叉树称为原二叉树的扩展二叉树。
为什么如此处理?如何由一种遍历序列生成该二叉树?遍历是二叉树各种操作的基础,可以在遍历的过程中进行各种操作,例如建立一棵二叉树。6.3二叉树的周游扩展二叉树的前序遍历序列:AB.D..C..DBAC.DBAC....建立二叉树6.3二叉树的周游设二叉树中的结点均为一个字符。假设扩展二叉树的前序遍历序列由键盘输入,root为指向根结点的指针,二叉链表的建立过程是:首先输入根结点,若输入的是一个“.”字符,则表明该二叉树为空树,即root=NULL;否则输入的字符应该赋给root->data,,之后依次递归建立它的左子树和右子树。建立二叉树6.3二叉树的周游建立二叉链表方式存储的二叉树voidCreateBiTree(BiTree*bt){charch;ch=getchar();if(ch=='.')*bt=NULL;else{*bt=(BiTree)malloc(sizeof(BiTNode));(*bt)->data=ch;CreateBiTree(&((*bt)->LChild));CreateBiTree(&((*bt)->RChild));}}二叉树算法设计练习遍历二叉树是二叉树各种操作的基础,遍历算法中对每个结点的访问操作可以是多种形式及多个操作,根据遍历算法的框架,适当修改访问操作的内容,可以派生出很多关于二叉树的应用算法。voidInOrder(BiTreeroot){if(root==NULL)return;else{InOrder(root->lchild);
printf(“%c”,root->data);InOrder(root->rchild);}}二叉树算法设计练习设计算法求二叉树的结点个数。voidCount(BiTreeroot)//count为全局量并已初始化为0{if(root==NULL)return;else{Count(root->lchild);count++;Count(root->rchild);}}二叉树算法设计练习设计算法按前序次序打印二叉树中的叶子结点。voidPreOrder(BiTreeroot){if(root==NULL)return;else{if(!root->lchild&&!root->rchild)printf(“%c”,root->data);PreOrder(root->lchild);PreOrder(root->rchild);}}6.3.2遍历算法应用1.输出二叉树中的结点【算法描述】voidPreOrder(BiTreeroot){ if(root!=NULL){ printf(root->data);/*输出根结点*/ PreOrder(root->LChild);/*先序遍历左子树*/ PreOrder(root->RChild);/*先序遍历右子树*/}}2.输出二叉树中的叶子结点voidPreOrder(BiTreeroot){ if(root!=NULL){
if(root->LChild==NULL&&root->RChild==NULL)printf(root->data);/*输出叶子结点*/PreOrder(root->LChild);/*先序遍历左子树*/PreOrder(root->RChild);/*先序遍历右子树*/}}3.统计叶子结点数目/*LeafCount为保存叶子结点数目的全局变量,调用之前初始化值为0*/voidleaf(BiTreeroot){if(root!=NULL){leaf(root->LChild);leaf(root->RChild);if(root->LChild==NULL&&root->RChild==NULL)LeafCount++;}}
方法一:intleaf(BiTreeroot){intLeafCount;if(root==NULL) LeafCount=0;elseif((root->LChild==NULL)&&(root->RChild==NULL))LeafCount=1; else/*叶子数为左右子树的叶子数目之和*/
LeafCount=leaf(root->LChild)+leaf(root->RChild); returnLeafCount;}方法二:3.统计叶子结点数目5.求二叉树的高度设函数表示二叉树bt的高度,则递归定义如下:
若bt为空,则高度为0
若bt非空,其高度应为其左右子树高度的最大值加1
左子树右子树bthlhrHigh=max(hl+hr)+1intPostTreeDepth(BiTreebt){inthl,hr,max;if(bt!=NULL){hl=PostTreeDepth(bt->LChild);/*求左子树的深度*/hr=PostTreeDepth(bt->RChild);/*求右子树的深度*/max=hl>hr?hl:hr;/*得到左、右子树深度较大者*/return(max+1);/*返回树的深度*/}elsereturn(0);/*如果是空树,则返回0*/}二叉树前序遍历的非递归算法的关键:在前序遍历过某结点的整个左子树后,如何找到该结点的右子树的根指针。解决办法:在访问完该结点后,将该结点的指针保存在栈中,以便以后能通过它找到该结点的右子树。
在前序遍历中,设要遍历二叉树的根指针为root,则有两种可能:⑴若root!=NULL,则表明?如何处理?⑵若root=NULL,则表明?如何处理?前序遍历——非递归算法6.3二叉树遍历的非递归算法访问结点序列:A栈S内容:BD
A
B前序遍历的非递归实现
ADBC6.3二叉树遍历的非递归算法访问结点序列:A栈S内容:BD
A前序遍历的非递归实现
ADBC
D6.3二叉树遍历的非递归算法访问结点序列:A栈S内容:BD
C前序遍历的非递归实现
ADBCC6.3二叉树遍历的非递归算法1.栈s初始化;2.循环直到root为空或栈s为空
2.1当root不空时循环
2.1.1输出root->data;2.1.2将指针root的值保存到栈中;
2.1.3继续遍历root的左子树
2.2如果栈s不空,则
2.2.1将栈顶元素弹出至root;
2.2.2准备遍历root的右子树;前序遍历——非递归算法(伪代码)6.3二叉树遍历的非递归算法前序遍历——非递归算法
voidPreOrder(BiTreeroot){InitStack(&S);//采用顺序栈p=root;
while(p!=NULL||!isEmpty(S))
{if(p!=NULL){printf(“%c”,p->data);push(&S,p);p=p->lchild;}else{pop(&S,&p);p=p->rchild;}}}6.3二叉树遍历的非递归算法中序遍历——非递归算法在二叉树的中序遍历中,访问结点的操作发生在该结点的左子树遍历完毕并准备遍历右子树时,所以,在遍历过程中遇到某结点时并不能立即访问它,而是将它压栈,等到它的左子树遍历完毕后,再从栈中弹出并访问之。中序遍历的非递归算法只需将前序遍历的非递归算法中的输出语句printf(“%c”,p->data)移到pop(&S,&p)之后即可。6.3二叉树遍历的非递归算法中序遍历——非递归算法
voidPreOrder(BinTreeroot){InitStack(&S);//采用顺序栈p=root;
while(p!=NULL||!isEmpty(S)){if(p!=NULL){push(&S,p);p=p->lchild;}else{pop(&S,&p);printf(“%c”,p->data);p=p->rchild;}}}6.3二叉树遍历的非递归算法后序遍历——非递归算法voidPostOrder(BiTreeroot){BiTNode*p,*q;StackS;q=NULL;p=root;InitStack(&S);while(p!=NULL||!isEmpty(S)){while(p!=NULL){push(&S,p);p=p->lchild;}if(!isEmpty(S)){GetTop(&S,&p);if(p->rchild==NULL)||(p->rchild==q){printf(“%c”,p->data);q=p;pop(&s,&p);p=NULL;}elsep=p->rchild;}}}6.3二叉树遍历的非递归算法层序遍历ABCDEFG遍历序列:AABCBDCEFGDEFG6.3二叉树遍历的非递归算法层序遍历队列Q初始化;2.如果二叉树非空,将根指针入队;3.循环直到队列Q为空3.1p=队列Q的队头元素出队;3.2访问结点p的数据域;3.3若结点p存在左孩子,则将左孩子指针入队;3.4若结点p存在右孩子,则将右孩子指针入队;6.3二叉树遍历的非递归算法层序遍历voidLeverOrder(BiTreeroot){InitQueue(&Q);//采用顺序队列if(root==NULL)return;//二叉树为空,算法结束p=root;EnterQueue(&Q,p);//指针入队while(!isEmptyQueue(Q))//当队列非空时{DelQueue(&Q,&p);//出队printf(“%c”,p->data);if(p->lchild!=NULL)EnterQueue(&Q,p->lchild);if(p->rchild!=NULL)EnterQueue(&Q,p->rchild);}}6.3二叉树遍历的非递归算法线索链表线索:将二叉链表中的空指针域指向前驱结点和后继结点的指针被称为线索;线索化:使二叉链表中结点的空链域存放其前驱或后继信息的过程称为线索化;线索链表:加上线索的二叉链表称为线索链表。6.3二叉树的线索化如何保存二叉树的某种遍历序列?将二叉链表中的空指针域指向其前驱结点和后继结点
LtagLChild
dataRChildRtag0:Lchild指向该结点的左孩子1:Lchild指向该结点的前驱结点0:Rchild指向该结点的右孩子1:Rchild指向该结点的后继结点Ltag=Rtag=结点结构线索链表6.3二叉树的线索化typedefstructThrNode{DataTypedata;PThrNodelchild,rchild;intltag,rtag;}*PThrNode;线索链表结点结构
LtagLChild
dataRChildRtag6.3二叉树的线索化二叉树的遍历方式有4种,故有4种意义下的前驱和后继,相应的有4种线索二叉树:⑴前序线索二叉树⑵中序线索二叉树⑶后序线索二叉树⑷层序线索二叉树线索二叉树6.3二叉树的线索化FABDCEG中序线索二叉树线索二叉树中序序列:DGBAECF6.3二叉树的线索化分析:建立线索链表,实质上就是将二叉链表中的空指针改为指向前驱或后继的线索,而前驱或后继的信息只有在遍历该二叉树时才能得到。建立二叉链表遍历二叉树,将空指针改为线索中序线索链表的建立6.3二叉树的线索化A头指针BCDEFG∧∧∧∧∧∧00000000000000∧∧中序线索链表的建立过程已经建立起二叉链表6.3二叉树的线索化A头指针BCDEFG∧∧∧∧∧∧00000000000000∧∧中序线索链表的建立过程中序遍历二叉链表p为正在访问的结点pre为刚访问的结点p16.3二叉树的线索化A头指针BCDEFG∧∧∧∧∧∧00000000000000∧∧中序线索链表的建立过程中序遍历二叉链表p为正在访问的结点pre为刚访问的结点pre1p16.3二叉树的线索化A头指针BCDEFG∧∧∧∧∧∧00000000000000∧中序线索链表的建立过程中序遍历二叉链表p为正在访问的结点pre为刚访问的结点pre11p16.3二叉树的线索化A头指针BCDEFG∧∧∧∧∧∧00000000000000中序线索链表的建立过程中序遍历二叉链表p为正在访问的结点pre为刚访问的结点pre11p116.3二叉树的线索化A头指针BCDEFG∧∧∧∧∧00000000000000中序线索链表的建立过程中序遍历二叉链表p为正在访问的结点pre为刚访问的结点pre11p1116.3二叉树的线索化A头指针BCDEFG∧∧∧∧00000000000000中序线索链表的建立过程中序遍历二叉链表p为正在访问的结点pre为刚访问的结点pre11p11116.3二叉树的线索化A头指针BCDEFG∧∧∧00000000000000中序线索链表的建立过程中序遍历二叉链表p为正在访问的结点pre为刚访问的结点pre11p111116.3二叉树的线索化A头指针BCDEFG∧∧00000000000000中序线索链表的建立过程中序遍历二叉链表p为正在访问的结点pre为刚访问的结点pre111111116.3二叉树的线索化在遍历过程中,访问当前结点root的操作为:⑴如果root的左、右指针域为空,则将相应标志置1;⑵若root的左指针域为空,则令其指向它的前驱,这需要设指针pre始终指向刚刚访问过的结点,显然pre的初值为NULL;若pre的右指针域为空,则令其指向它的后继,即当前访问的结点root;⑶令pre指向刚刚访问过的结点root;中序线索链表的建立6.3二叉树的线索化1.建立二叉链表,将每个结点的左右标志置为0;2.遍历二叉链表,建立线索;2.1如果二叉链表root为空,则空操作返回;2.2对root的左子树建立线索;2.3对根结点root建立线索;
2.3.1若root没有左孩子,则为root加上前驱线索;2.3.2若结点pre右标志为1,则为pre加上后继线索;2.3.3令pre指向刚刚访问的结点root;2.4对root的右子树建立线索。中序线索链表的建立
6.3二叉树的线索化voidThread(PThrNoderoot){if(root==NULL)return;Thread(root->lchild);if(root->lchild==NULL){//对root的左指针进行处理root->ltag=1;root->lchild=pre;//设置pre的前驱线索}if(pre!=NULL&&pre->rtag==1){pre->rchild=root;pre->rtag=1;}//设置pre的后继线索pre=root;Thread(root->rchild);}中序线索链表的建立
6.3二叉树的线索化中序线索链表查找后继FABDCEG⑴如果结点p的右标志为1,则表明该结点的右指针是线索;⑵如果结点p的右标志为0,则表明该结点有右孩子。根据中序遍历的操作定义,它的后继结点应该是遍历其右子树时第一个访问的结点,即右子树中的最左下结点。6.3二叉树的线索化
PThrNodeNext(PThrNodep){if(p->ltag==1)q=p->lchild;//右标志为1,可直接得到后继结点
else{q=p->lchild;//工作指针q指向结点p的右孩子
while(q->rtag==0)//查找最左下结点
q=q->rchild;}returnq;}中序线索链表查找前驱6.3二叉树的线索化
PThrNodeNext(PThrNodep){if(p->rtag==1)q=p->rchild;//右标志为1,可直接得到后继结点
else{q=p->rchild;//工作指针q指向结点p的右孩子
while(q->ltag==0)//查找最左下结点
q=q->lchild;}returnq;}中序线索链表查找后继6.3二叉树的线索化6.4树的存储结构实现树的存储结构,关键是什么?什么是存储结构?树中结点之间的逻辑关系是什么?思考问题的出发点:如何表示结点的双亲和孩子如何表示树中结点之间的逻辑关系。数据元素以及数据元素之间的逻辑关系在存储器中的表示。双亲表示法(父指针表示法)基本思想:用一维数组来存储树的各个结点(一般按层序存储),数组中的一个元素对应树中的一个结点,包括结点的数据信息以及该结点的双亲在数组中的下标。
6.4树的存储结构
data
parentdata:存储树中结点的数据信息parent:存储该结点的双亲在数组中的下标structParTreeNode{
DataTypedata;//数据域intparent;//指针域,双亲在数组中的下标};
data
parent6.4树的存储结构树的双亲表示法实质上是一个静态链表。双亲表示法下标
dataparent012345678
A-1B0C0D1E1F1G2H2I
46.4树的存储结构如何查找双亲结点?时间性能?双亲表示法ACBHFEDGI6.4树的存储结构双亲表示法ACBHFEDGI如何查找孩子结点?时间性能?下标
dataparentfirstchild136-18-1-1-1-1012345678
A-1B0C0D1E1F1G2H2I
4下标
dataparentrightsib-12-145-17-1-16.4树的存储结构双亲表示法012345678
A-1B0C0D1E1F1G2H2I
4ACBHFEDGI如何查找兄弟结点?时间性能?链表中的每个结点包括一个数据域和多个指针域,每个指针域指向该结点的一个孩子结点。如何表示孩子?6.4树的存储结构孩子链表表示法(子表)方案一:指针域的个数等于树的度datachild1child2……childd其中:data:数据域,存放该结点的数据信息;
child1~childd:指针域,指向该结点的孩子。
6.4树的存储结构∧缺点:浪费空间ACBHFEDGIA∧B∧C∧D∧E∧F∧G∧H∧I∧∧∧∧∧∧∧∧∧∧∧链表中的每个结点包括一个数据域和多个指针域,每个指针域指向该结点的一个孩子结点。如何表示孩子?6.4树的存储结构孩子链表表示法方案二:
指针域的个数等于该结点的度data
degree
child1
child2
……
childd其中:data:数据域,存放该结点的数据信息;
degree:度域,存放该结点的度;
child1~childd:指针域,指向该结点的孩子。
6.4树的存储结构缺点:结点结构不一致ACBHFEDGIA2B3C2E1I0G0H0F0D0孩子链表表示法孩子链表的基本思想:把每个结点的孩子排列起来,看成是一个线性表,且以单链表存储,则n个结点共有n个孩子链表。这n个单链表共有n个头指针,这n个头指针又组成了一个线性表,为了便于进行查找采用顺序存储。最后,将存放n个头指针的数组和存放n个结点的数组结合起来,构成孩子链表的表头数组。
6.4树的存储结构如何表示孩子?将结点的所有孩子放在一起,构成线性表。childnext孩子结点structCTNode{
intchild;CTNode*next;};6.4树的存储结构structCBNode{DataTypedata;CTNode*firstchild;};孩子链表表示法datafirstchild表头结点ACBHFEDGI012345678下标
datafirstchild
ABCDEFG
H
I
∧∧∧∧6.4树的存储结构如何查找孩子结点?时间性能?∧12∧345∧7∧68∧ACBHFEDGI012345678下标
datafirstchild
ABCDEFG
H
I
∧∧∧∧∧6.4树的存储结构12∧345∧7∧68∧如何查找双亲结点?时间性能?双亲孩子表示法6.4树的存储结构012345678
A-1B0C0D1
∧
E1F1
∧
G
2
∧H
2
∧I
4
∧dataparentfirstchild12∧345∧7∧68∧ACBHFEDGI孩子兄弟表示法(长子兄弟)6.4树的存储结构ACBHFEDGI某结点的第一个孩子是惟一的某结点的右兄弟是惟一的设置两个分别指向该结点的第一个孩子和右兄弟的指针
structTNode{DataTypedata;StructTNode*firstchild,*nextsib;};6.4树的存储结构结点结构firstchild
data
nextsibdata:数据域,存储该结点的数据信息;firstchild:指针域,指向该结点第一个孩子;rightsib:指针域,指向该结点的右兄弟结点。
孩子兄弟表示法6.4树的存储结构孩子兄弟表示法ACBHFEDGI
A
B
C
D
E
F
G
H
I∧∧∧∧∧∧∧∧∧∧如何查找兄弟结点?时间性能?6.4树的存储结构孩子兄弟表示法ACBHFEDGI
A
B
C
D
E
F
G
H
I∧∧∧∧∧∧∧∧∧∧如何查找孩子结点?时间性能?6.4树、森林与二叉树的转换是哪些树结构的存储结构?树和二叉树之间具有对应关系AEBCFDGA∧BC∧E∧D∧F∧∧G∧∧ABCDEFG6.4树、森林与二叉树的转换树和二叉树之间的对应关系
树:兄弟关系二叉树:双亲和右孩子树:双亲和长子二叉树:双亲和左孩子AEBCFDGABCDEFG6.4树、森林与二叉树的转换1.兄弟加线.树和二叉树之间的对应关系ABCDEFG6.4树、森林与二叉树的转换2.保留双亲与第一孩子连线,删去与其他孩子的连线.ABCDEFG树和二叉树之间的对应关系1.兄弟加线.3.顺时针转动,使之层次分明.6.4树、森林与二叉树的转换树和二叉树之间的对应关系2.保留双亲与第一孩子连线,删去与其他孩子的连线.1.兄弟加线.ABCDEFG3.顺时针转动,使之层次分明.6.4树、森林与二叉树的转换树和二叉树之间的对应关系2.保留双亲与第一孩子连线,删去与其他孩子的连线.1.兄弟加线.GDABECF树转换为二叉树
⑴加线——树中所有相邻兄弟之间加一条连线。
⑵去线——对树中的每个结点,只保留它与第一个孩子结点之间的连线,删去它与其它孩子结点之间的连线。
⑶层次调整——以根结点为轴心,将树顺时针转动一定的角度,使之层次分明。
6.4树、森林与二叉树的转换树转换成的二叉树其右子树一定为空CBEDFGAABEFCDG前序遍历AEBCFDGABEFCDG前序遍历树的前序遍历等价于二叉树的前序遍历!6.4树、森林与二叉树的转换EFBCGDA后序遍历EFBCGDA中序遍历树的后序遍历等价于二叉树的中序遍历!6.4树、森林与二叉树的转换CBEDFGAAEBCFDG森林转换为二叉树
⑴将森林中的每棵树转换成二叉树;⑵从第二棵二叉树开始,依次把后一棵二叉树的根结点作为前一棵二叉树根结点的右孩子,当所有二叉树连起来后,此时所得到的二叉树就是由森林转换得到的二叉树。6.4树、森林与二叉树的转换FEDCBAGHIJBAFEDCGHIKKIFEHABCGD6.4树、森林与二叉树的转换二叉树转换为树或森林
⑴加线——若某结点x是其双亲y的左孩子,则把结点x的右孩子、右孩子的右孩子、……,都与结点y用线连起来;⑵去线——删去原二叉树中所有的双亲结点与右孩子结点的连线;⑶
层次调整——整理由⑴、⑵两步所得到的树或森林,使之层次分明。
6.4树、森林与二叉树的转换FHGEAICDBFHGDCEBAIFEDCBAHGI加线去线层次调整IHGBCDAFE6.4树、森林与二叉树的转换森林的遍历森林有两种遍历方法:⑴前序(根)遍历:前序遍历森林即为前序遍历森林中的每一棵树。⑵后序(根)遍历:后序遍历森林即为后序遍历森林中的每一棵树。
6.4树、森林与二叉树的转换树的遍历操作
树的遍历:从根结点出发,按照某种次序访问树中所有结点,使得每个结点被访问一次且仅被访问一次。
如何理解访问?抽象操作,可以是对结点进行的各种处理,这里简化为输出结点的数据。如何理解次序?树通常有前序(根)遍历、后序(根)遍历和层序(次)遍历三种方式。树结构(非线性结构)→线性结构。遍历的实质?6.4树、森林与二叉树的转换前序遍历
树的前序遍历操作定义为:若树为空,则空操作返回;否则⑴访问根结点;⑵
按照从左到右的顺序前序遍历根结点的每一棵子树。
前序遍历序列:ABDEHIFCGACBGFEDHI6.4树、森林与二叉树的转换后序遍历
树的后序遍历操作定义为:若树为空
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 建筑通风与空调设计技术合同
- 版简单股权合同
- 泥工分包合同中的权益保障
- 养殖场养殖养殖鱼苗承包合同
- 2024年度铜芯电缆供应合同
- 电力架线施工作业分包合同文本
- 模板安装班组合同范本
- 购货合同与购销合同的合同签订要点
- 景观设计草花合同
- 2024年厂房配套仓储物流场地租赁合同
- DB36T+2036-2024地下病害体三维地质雷达探测技术规程
- 《电气控制系统设计与装调》教案 项目五 任务二小车自动往返控制线路设计与安装
- 意识形态知识培训课
- 网络安全行业防火墙解决方案
- 2024固态电池需求趋势产业链发展现状及龙头企业布局分析报告
- JGJT46-2024《建筑与市政工程施工现场临时用电安全技术标准》知识培训
- 四川公务员考试(公共基础知识)真题试卷汇编1
- 中国历史人文地理(上)学习通超星期末考试答案章节答案2024年
- 期中测试卷-2024-2025学年统编版语文五年级上册
- 《算法设计与分析基础》(Python语言描述) 课件 第9章NP完全问题
- 2024三新供电服务限公司第二批供电服务职工招聘261人高频难、易错点500题模拟试题附带答案详解
评论
0/150
提交评论