数据结构及应用算法教程(修订版) 数据结构_第6章_二叉树和树.ppt
《数据结构及应用算法教程(修订版) 数据结构_第6章_二叉树和树.ppt》由会员分享,可在线阅读,更多相关《数据结构及应用算法教程(修订版) 数据结构_第6章_二叉树和树.ppt(153页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、6.1 二叉树 6.3 树和森林 6.1.1 二叉树的定义和术语 6.3.1 树和森林的定义 6.1.2 二叉树的基本性质 6.3.2 树和森林的存储结构 6.1.3 二叉树的存储结构 6.3.3 树和森林的遍历 6.2 二叉树遍历 6.4 树的应用 6.2.1 问题的提出 6.4.1 堆排序 6.2.2 遍历算法的描述 6.4.2 二叉排序树 6.2.3 二叉树遍历应用举例 6.4.3 赫夫曼树及其应用 6.2.4 线索二叉树,主要内容,线性结构,线性表,定义 基本操作,顺序表,链 表,逻辑结构,存储结构,比较,基本操作的实现 时间性能 优缺点,知识回顾,特殊线性表,栈,栈的定义 操作特性,
2、顺序栈,链 栈,逻辑结构,存储结构,比 较,比较,基本操作的实现 时间性能,队 列,队列定义 操作特性,循环队列,链队列,操作的实现 时间性能,逻辑结构,存储结构,串,逻辑结构,存储结构,定义 基本操作,顺序存储,块 链存储,模式匹配,树型结构是一类重要的非线性数据结构,用来描述数据元素之间存在的一对多的层次关系。树结构所描述的信息模型在客观世界普遍存在,是现实生活和实际应用中一类问题的抽象。,例:磁盘文件结构,6.1 二叉树 6.1.1 二叉树的定义和术语 1.二叉树的结构定义: 二叉树是n(n=0)个数据元素的有限集,它或为空集(n=0),或 为非空集。对于非空集有: (1)有一个特定的称
3、之为根的元素; (2)除根以外的其余元素分为两个互不相交的子集,每个子集自身也是一棵二叉树,分别称为根的左子树和右子树。 结点:二叉树中的数据元素,除根结点外每个结点有且仅有一个直接前驱,但有零个或多个直接后继。,二叉树的定义是采用递归方法,注意: (1)二叉树中的左子树和右子树是两棵互不相交的二叉树,因此,二叉树上除根之外的任何结点不可能同时在两棵子 树中出现,它或者在左子树中,或者在右子树中。 (2)二叉树上每个结点至多有两棵子树,并且,二叉树 的两棵子树有左右之分,其次序不能任意颠倒。,具有3个结点的二叉树的形态,2.基本术语,借用了家族中的一些惯用名词: 孩子结点 双亲结点 兄弟结点
4、堂兄弟结点 祖先结点 子孙结点,结点:包含一个数据元素及若干指向其它结点的分支信息 若r是二叉树中某个结点,n是它的左子树(或右子树)的根,则称n是r的左孩子(或右孩子),r是n的双亲。 注意:二叉树中的根结点没有双亲 若两个结点的双亲为同一结点,则这两个结点互为兄弟。 如右图,H和J及M和I 均互为兄弟,而K和M 不是兄弟,但可以称为 堂兄弟。 祖先结点:是从根到该结点所经分支上的所有结点。 子孙结点:以某结点为根的子树中的任一结点,都称为该 结点的子孙。,D,H,I,J,M,K,结点的度:一个结点的子树个数称为此结点的度。二叉树 中结点度数的最大值为2。 树的度:是树内各结点的度的最大值。
5、 叶子结点(或终端结点):度为0的结点,即无后继的结点, 二叉树中其左右子树均为空的结点。 非叶子结点(分支结点):度不为0的结点,至少有一棵子树。 结点在二叉树中的层次:从根开始定义起,根所在的层次为1,根的孩子为第2层,依次类推,若某节点在第L层,则其子树的 根在L+1层。 二叉树的深度:二叉树中叶子结点的最大层次数定义为二叉树的深度。,两种特殊形态的二叉树: (1)满二叉树:若二叉树中所有的分支结点的度数都为2,且叶 子结点都在同一层次上,则称这类二叉树为满二叉树。,满二叉树的特点:,叶子只能出现在最下一层; 只有度为0和度为2的结点。,(2)完全二叉树: 对满二叉树从上到下,从左到右进
6、行从1开始的编号,则得完全二叉树的定义:对一棵包含n个结点的二叉树中每个结点,都可以和满二叉树中编号为1至n的结点一一对应,则称这类二叉树 为完全二叉树。,完全二叉树特点: 若某结点没有左孩子,则它一定没有右孩子;即该结点必是叶子结点。 一棵深度为h的完全二叉树中,前h-1层中的结点都是“满”的,且 第h层的结点都集中在左边。 满二叉树本身也是完全二叉树.,3.基本操作 1)InitBiTree( / 二叉树的最大结点数 typedef struct TElemType *data; /存储空间基址 int nodenum; /树中结点数 SqBiTree; / 完全二叉树的顺序存储结构 若地
7、址从0编号,则第i号结点的左右孩子一定保存在第2(i+1)-1及2(i+1)号单元中;其双亲保存在(i+1)/2-1号单元中。 缺点:对非完全二叉树而言,浪费存储空间。 2.二叉树的链式存储表示 用链表存储二叉树中的结点,即利用指针表示结点之间的关系。由二叉树的定义可知,二叉树中的结点由一个数据元素和分别指向其左、右子树的两个分支构成。,通常采用的方法是: 二叉链表:每个结点中设置三个域,数据域和分别指向左、右子树的指针域。 结点结构: 三叉链表:为了便于找结点的双亲,可以在上述结点结构中增加一个指向其双亲的指针。 链表的头指针指向二叉树的根结点。 结点结构:, 二叉链表 typedef st
8、ruct BiTNode TElemType data; struct BiTNode *lchild, *rchild; BiTNode, *BiTree;,A,D,F,C,B,E,root,G,H,I, 三叉链表 typedef struct TriTNode struct TriTNode *parent; TElemType data; struct TriTNode *lchild, *rchild; TriTNode, *TriTree;,6.2 二叉树遍历 6.2.1 问题的提出 1. 概念 问题:如何不重复地访问二叉树中每一个结点? 遍历:是指按某一条搜索路径巡访二叉树中的结点
9、,使得每个结点均被访问一次,而且仅被访问一次。(将树线性化) “访问”的含义可以很广,如:输出结点的信息或修改数据信息等。 “遍历”是任何类型均有的操作,对线性结构而言,只有一条搜索路径(因为每个结点均只有一个后继),故不需要另加讨论。而二叉树是非线性结构,每个结点有两个后继, 则存在按什么样的搜索路径遍历的问题。,2. 遍历二叉树方法: (1) 访问根,遍历左子树,遍历右子树(记做DLR); (2) 访问根,遍历右子树,遍历左子树(记做DRL); (3) 遍历左子树,访问根,遍历右子树(记做LDR); (4) 遍历左子树,遍历右子树,访问根(记做LRD); (5) 遍历右子树,访问根,遍历左
10、子树(记做RDL); (6) 遍历右子树,遍历左子树,访问根(记做RLD)。 先左后右的遍历算法: DLR:先(根)序遍历(又称前序遍历) LDR:中(根)序的遍历算法 LRD:后(根)序的遍历算法 层次遍历(从上到下,从左向右),若二叉树为空树,则空操作;否则:,虚线代表先左后右的搜索路径:向下箭头为递归调用,向上箭头为从递归调用返回。 :先序访问序列(ABDEC); :中序访问序列(DBEAC); :后序访问序列(DEBCA)。,三种遍历方式使用时注意: 在3种不同遍历方式中,各叶子结点之间的相对次序是相同 的,它们都按叶子结点之间从左到右的次序排列 ; 前序遍历有助于查询结点间的祖先和子
11、孙关系(先祖先 ,后子 孙); 后序遍历也有助于查询结点间的子孙和祖先关系.(先子孙,后 祖先)。 6.2.2 遍历算法的描述 二叉树的三种遍历,递归的终止条件是二叉树为空,此时为空操作。假设以二叉链表为存储结构,并将结点的访问操作抽象为一个函数visit,则先序遍历二叉树的递归算法如下:,算法 6.1 先序遍历以T为根指针的二叉树 void visit (BiTree T) coutdatalchild, visit); / 先序遍历左子树 PreOrder(T-rchild, visit); / 先序遍历右子树 /PreOrder,下面是一二叉树的先序递归算法的详细执行情况: 总结:在树中
12、,树深为2,递归调用的深度为3。,void InOrder (BiTree T , void (*visit)(BiTree) ) /中序遍历递归算法 if (T!=NULL) InOrder (T-lchild, visit); / 遍历左子树 visit(T); / 访问结点 InOrder (T-rchild, visit); / 遍历右子树 /InOrder void PostOrder (BiTree T , void (*visit)(BiTree) /后序遍历递归算法 if (T!=NULL) PostOrder (T-lchild, visit); / 遍历左子树 PostOr
13、der (T-rchild, visit); / 遍历右子树 visit(T); / 访问结点 /PostOrder,中序遍历算法的非递归描述 (1)需要设计一个栈S来存放所经过的根结点的指针;(2)对中序遍历来说,第一次遇到根结点并不访问,而是入栈,然后中序遍历左子树,左子树遍历结束后,第二次遇到根结点,就将根结点(指针)退栈,并且访问根结点,随后中序遍历右子树,在需要退栈时,若栈空则结束。定义栈的元素类型, 其中的任务性质域task记录遍历过程每一步的工作状态. typedef enumTravel=1,Visit=0 TaskType; /Travel为1:工作状态是遍历;Visit为0
14、:工作状态是访问. typedef struct BiTree ptr; /指向二叉树结点的指针 TaskType task; /任务的性质 SElemType; /栈元素的类型定义,算法 6.2 void InOrder_iter(BiTree BT,void(*visit)(BiTree) / 利用栈实现中序遍历二叉树,BT为指向二叉树的根结 /点的头指针 InitStack(S); e.ptr=BT; e.task=Travel; / e为栈元素 if(BT) Push(S, e); / 布置初始任务 while(!StackEmpty(S) / 每次处理一项任务 Pop(S,e); i
15、f(e.task=Visit) visit(e.ptr); / 处理访问任务 else,if(e.ptr) / 处理非空树的遍历任务 p=e.ptr; e.ptr=p-rchild; e.task=Travel; Push(S,e); / 最不迫切任务(遍历右子树)进栈 e.ptr=p; e.task=Visit; Push(S,e); /处理访问任务的工作状态进栈 e.ptr=p-lchild; e.task=Travel; Push(S,e); /迫切任务(遍历左子树)进栈 /if /while /InOrder_iter,/直接利用栈: void InOrder(BiTree root)
16、 SqStack S; InitStack (S); BiTree p=root; while(p!=NULL|!StackEmpty(S) if (p!=NULL) / 根指针进栈, 遍历左子树 Push(S,p); p=p-lchild; else Pop(S, p); visit(p); p=p-rchild; /根指针退栈, 访问根结点, 遍历右子树 /Inorder,对照下图所示的二叉树,在中根非递归遍历过程中其栈s的内容变化 :,T,B,遇根D进栈 遍D左子树,C,D,补:二叉树的层次遍历 层次遍历是指从二叉树的每一层(根结点)开始,按从上到下逐层遍历,每一层则按从左到右的顺序逐个
17、访问。如下图的二叉树,遍历结果为:A B C D E 分析:根据层次遍历的定义,在进行层次遍历时,对每一层结点访问完后,再按照它们的访问次序对各个结点的左右孩子顺序访问,这样一层一层进行,先遇到的结点其左右孩子也先被访问,与队列的操作原则吻合。,算法:设置一队列,根结点指针入队列,然后队首元素出队列,每出队一个元素,执行如下操作: 访问该元素所指结点 若该元素所指结点的左右孩子非空,则该元素所指结点的左右孩子指针入队列 如此不断进行,当队列为空,遍历结束。,层次遍历,遍历序列:,A,A,B,C,B,D,C,E,F,G,D,E,F,G,二叉树的层次遍历 void LevelOrder(BiTre
18、e T) SqQueue Q; /为循环队列 BiTree e; if(T=NULL) return;/二叉树为空,返回 EnQueue(Q,T); while(Q.front!=Q.rear) DeQueue(Q,e); visit(e); if(e-lchild!=NULL) EnQueue(Q,e-lchild); if(e-rchild!=NULL) EnQueue(Q,e-rchild); /while /LevelOrder,补充习题: 7.具有100个结点的二叉树中,若用二叉链表存储,其指针域部分用来指向结点的左、右孩子,其中( )个指针域为空。 A)50 B)99 C)100
19、D)101 8.首先访问结点的左子树,然后访问该结点,最后访问结点的右子树,这种遍历称为( )。 A)前序遍历 B)后序遍历 C)中序遍历 D)层次遍历 9.任何一棵二叉树的叶子结点在先序、中序和后序遍历序列中的相对次序( )。 A)不发生变化 B)发生变化 C)不能确定 D)以上都不对,7.说明:已知:n=n0+n1+n2,指针域为空个数:2*n0+n1=n0+n1+n2+1, 即n+1. D 8.C 9.A,补充习题: 10.某非空二叉树的前序序列和后序序列正好相反,则二叉树一定是( )的二叉树。 A)空或只有一个结点 B)高度等于其结点数 C)任一结点无左孩子 D)任一结点无右孩子 11
20、.如果某二叉树的先序遍历序列是abdcef,中序遍历序列是dbaefc,则其后序遍历序列是( )。 A)dbafec B)fecdba C)efcdba D)dbfeca 12.按照二叉树的定义,具有3个结点的二叉树形态有( )种。 A)3 B)4 C)5 D)6 13.二叉树的后序遍历序列中,任意一个结点均处在其孩子结点的前面( )。 A)正确 B)错误,10.B 11.D 12.C 13.B,6.2.3 二叉树遍历应用举例 例6.1 建立二叉树的存储结构-二叉链表(算法6.3) 假设按先序遍历的顺序建立二叉链表,T为指向根结点的指针: 首先输入一个根结点,若输入的是#,则表明该二叉树为 空
21、树,即T=NULL; 否则输入的字符应赋给T-data,之后依次递归建立它的左 子树T-lchild和右子树T-rchild。 如图二叉树,输入顺序为:AB#DE#C# 其中#表示空子树.,void CreateBiTree(BiTree / 递归建(遍历)右子树 /else /CreateBiTree,算法执行过程举例如下:,cin ch; if (ch= #) T = NULL; else T = new BiTNode; T-data = ch; CreateBiTree(T-lchild); CreateBiTree(T-rchild); ,例6.2 求二叉树的深度(算法 6.4) 二
22、叉树的深度为二叉树中叶子结点所在层次的最大值。结点的层次需从根结点递推,设根结点为第1层,第k层结点的子树根在第k+1层。遍历二叉树时求每个结点的层次数,其中的最大值为二叉树的深度. void BiTreeDepth(BiTree T, int h, int /BiTreeDepth,主函数中求T所指二叉树的深度: d=0; BiTreeDepth(T, 1,d); 若T所指为空树,则算法6.4空操作,d 仍等于0。非空时执行过程:,L=1 H=0,L=1 H=1,L=2 H=2,L=3 H=3,L=2 H=3,L=3 H=3,L=4 H=4,L=3 H=4,H=4,求二叉树的深度(后序遍历
23、算法 6.5 ) 算法基本思想:从二叉树深度的定义可知,二叉树的深度应为其左、右子树深度的最大值加1。由此,需先分别求得左、右子树的深度,算法中“访问结点”的操作为:求得左、右子 树深度的最大值,然后加1。 int BiTreeDepth(BiTree T) / 后序遍历求T所指二叉树的深度 if (!T) return 0; else hL=BiTreeDepth(T-lchild); hR=BiTreeDepth(T-rchild); if (hL=hR) return hL+1; else return hR+1; /BiTreeDepth,例6.3 复制一棵二叉树 复制一棵二叉树即按原
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构及应用算法教程修订版 数据结构_第6章_二叉树和树 数据结构 应用 算法 教程 修订版 二叉
限制150内