ImageVerifierCode 换一换
格式:PPT , 页数:182 ,大小:2.38MB ,
资源ID:6484077      下载积分:10 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.docduoduo.com/d-6484077.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录   微博登录 

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(数据结构 第6章.ppt)为本站会员(tkhy51908)主动上传,道客多多仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知道客多多(发送邮件至docduoduo@163.com或直接QQ联系客服),我们立即给予删除!

数据结构 第6章.ppt

1、第6章 树和二叉树,6.1 树的概念与定义 6.2 二叉树 6.3 二叉树的遍历与线索化 6.4 树、森林和二叉树的关系 6.5 哈夫曼树及其应用,本章重点和难点:,掌握树的基本概念; 掌握二叉树的基本概念和性质;掌握二叉树的存储结构;掌握二叉树的遍历方法;了解二叉树线索化方法及其线索化二叉树相关的运算; 掌握Haffman树及其应用; 掌握掌握树的存储结构;掌握树、森林和二叉树相互转化方法。,6.1 树的概念与定义,树是n(n0)个结点的有限集合T。当n=0时,称为空树;当n0时, 该集合满足如下条件: (1) 其中必有一个称为根(root)的特定结点,它没有直接前驱,但有零个或多个直接后继

2、。 (2) 其余n-1个结点可以划分成m(m0)个互不相交的有限集T1,T2,T3,Tm,其中Ti又是一棵树,称为根root的子树。 每棵子树的根结点有且仅有一个直接前驱,但有零个或多个直接后继。,图6.1 树的图示方法, 结点:包含一个数据元素及若干指向其它结点的分支信息。 结点的度:一个结点的子树个数称为此结点的度。 叶结点:度为0的结点,即无后继的结点,也称为终端结点。 分支结点:度不为0的结点,也称为非终端结点。 孩子结点:一个结点的直接后继称为该结点的孩子结点。在图6.1中, B、C是A的孩子。 双亲结点:一个结点的直接前驱称为该结点的双亲结点。在图6.1中,A 是B、C的双亲。 兄

3、弟结点:同一双亲结点的孩子结点之间互称兄弟结点。在图6.1中,结点H、I、 J互为兄弟结点。, 祖先结点:一个结点的祖先结点是指从根结点到该结点的路径上的所有结点。在图6.1中,结点K的祖先是A、B、E。 子孙结点:一个结点的直接后继和间接后继称为该结点的子孙结点。在图6.1中,结点D的子孙是H、I、 J、 M。 树的度: 树中所有结点的度的最大值。 结点的层次:从根结点开始定义,根结点的层次为1,根的直接后继的层次为2,依此类推。 树的高度(深度): 树中所有结点的层次的最大值。 有序树:在树T中,如果各子树Ti之间是有先后次序的,则称为有序树。 森林: m(m0)棵互不相交的树的集合。将一

4、棵非空树的根结点删去,树就变成一个森林;反之,给森林增加一个统一的根结点,森林就变成一棵树。,结点A的度:3 结点B的度:2 结点M的度:0,叶子结点:K,L,F,G,M,I,J,结点A的孩子:B,C,D 结点B的孩子:E,F,结点I的双亲:D 结点L的双亲:E,结点B,C,D为兄弟 结点K,L为兄弟,树的度:3,结点A的层次:1 结点M的层次:4,树的深度:4,结点F的祖先:A,B 结点M的祖先:A,D,H,ADT Tree数据对象D:一个集合,该集合中的所有元素具有相同的特性。 数据关系R: 若D为空集,则为空树。 若D中仅含有一个数据元素,则R为空集,否则R=H,H是如下的二元关系: (

5、1) 在D中存在唯一的称为根的数据元素root, 它在关系H下没有前驱。 (2) 除root以外, D中每个结点在关系H下都有且仅有一个前驱。,基本操作: (1) InitTree(Tree): 将Tree初始化为一棵空树。 (2) DestoryTree(Tree): 销毁树Tree。 (3) CreateTree(Tree): 创建树Tree。 (4) TreeEmpty(Tree): 若Tree为空, 则返回TRUE, 否则返回FALSE。 (5) Root(Tree): 返回树Tree的根。 (6) Parent(Tree, x): 树Tree存在, x是Tree中的某个结点。 若x为

6、非根结点,则返回它的双亲, 否则返回“空”。 (7) FirstChild(Tree,x): 树Tree存在, x是Tree中的某个结点。若x为非叶子结点,则返回它的第一个孩子结点, 否则返回“空”。,(8) NextSibling(Tree,x): 树Tree存在,x是Tree中的某个结点。若x不是其双亲的最后一个孩子结点,则返回x后面的下一个兄弟结点, 否则返回“空”。 (9) InsertChild(Tree, p, Child):树Tree存在,p指向Tree中某个结点,非空树Child与Tree不相交。将Child插入Tree中, 做p所指向结点的子树。 (10) DeleteChi

7、ld(Tree,p,i): 树Tree存在, p指向Tree中某个结点, 1id,d为p所指向结点的度。 删除Tree中p所指向结点的第i棵子树。 (11) TraverseTree(Tree,Visit(): 树Tree存在,Visit()是对结点进行访问的函数。按照某种次序对树Tree的每个结点调用Visit()函数访问一次且最多一次。若Visit()失败, 则操作失败。,6.2 二 叉 树,6.2.1 二叉树的定义与基本操作,定义:我们把满足以下两个条件的树形结构叫做二叉树(Binary Tree): (1) 每个结点的度都不大于2; (2) 每个结点的孩子结点次序不能任意颠倒。 由此定

8、义可以看出,一个二叉树中的每个结点只能含有0、 1或2个孩子,而且每个孩子有左右之分。我们把位于左边的孩子叫做左孩子,位于右边的孩子叫做右孩子。,图6.2 二叉树的五种基本形态,例1:分别画出具有3个结点的树和3个结点的二叉树的所有不同形态。 例2:有关二叉树下列说法正确的是( )。A. 二叉树的度为2 B. 一棵二叉树的度可以小于2 C. 二叉树中至少有一个结点的度为2 D. 二叉树中任何一个结点的度都为2E. 二叉树的左右子树可任意交换,具有3个结点的树 具有3个结点的二叉树,二叉树基本操作: (1) Initiate(bt):将bt初始化为空二叉树。 (2) Create(bt): 创建

9、一棵非空二叉树bt。 (3) Destory(bt): 销毁二叉树bt。 (4) Empty(bt):若bt为空,则返回TRUE,否则返回FALSE。 (5) Root(bt): 求二叉树bt的根结点。若bt为空二叉树, 则函数返回“空”。 (6) Parent(bt, x):求双亲函数。求二叉树bt中结点x的双亲结点。若结点x是二叉树的根结点或二叉树bt中无结点x, 则返回“空”。,(7) LeftChild(bt, x):求左孩子。 若结点x为叶子结点或x不在bt中, 则返回“空”。 (8) RightChild(bt, x):求右孩子。 若结点x为叶子结点或x不在bt中, 则返回“空”。

10、 (9) Traverse(bt): 遍历操作。按某个次序依次访问二叉树中每个结点一次且仅一次。 (10) Clear(bt): 清除操作。 将二叉树bt置为空树。,6.2.2 二叉树的性质,性质1: 在二叉树的第i层上至多有2i-1个结点(i1)。 证明: 用数学归纳法。 归纳基础:当i=1时,整个二叉树只有一根结点,此时2i-1=20=1,结论成立。归纳假设:假设i=k时结论成立,即第k层上结点总数最多为2k-1个。 现证明当i=k+1时, 结论成立。 因为二叉树中每个结点的度最大为2,则第k+1层的结点总数最多为第k层上结点最大数的2倍,即22k-1=2(k+1)-1,故结论成立。,性质

11、2: 深度为k的二叉树至多有2k-1个结点(k1)。 证明:因为深度为k的二叉树,其结点总数的最大值是将二叉树每层上结点的最大值相加,所以深度为k的二叉树的结点总数至多为,故结论成立。,性质3: 对任意一棵二叉树T,若终端结点数为n0,而其度数为2的结点数为n2,则n0=n2+1。证明:设二叉树中结点总数为n, n1为二叉树中度为1的结点总数。 因为二叉树中所有结点的度小于等于2,所以有 n=n0+n1+n2设二叉树中分支数目为B, 因为除根结点外, 每个结点均 对应一个进入它的分支,所以有n=B+1,又因为二叉树中的分支都是由度为1和度为2的结点发出, 所以分支数目为 B=n1+2n2整理上

12、述两式可得到n=B+1=n1+2n2+1将n=n0+n1+n2代入上式,得出n0+n1+n2=n1+2n2+1,整理后得n0=n2+1,故结论成立。,例3:已知一棵度为k的树中有n1个度为1的结点,n2个度为2的结点,nk个度为k的结点,则该树中有多少个叶子结点?,【解答】 设树中结点总数为n,则n=n0 + n1 + + nk 树中分支数目为B,则B=n1 + 2n2 + 3n3 + + knk 因为除根结点外,每个结点均对应一个进入它的分支,所以有 n= B + 1 即n0 + n1 + + nk = n1 + 2n2 + 3n3 + + knk + 1 由上式可得叶子结点数为:n0 =

13、n2 + 2n3 + + (k-1)nk + 1,例4 若一棵二叉树具有10个度为2的结点,5个度为1的结点,则度为0的结点个数是( )。 A9 B11 C15 D6 例5 在一棵三叉树中度为3的结点数为2个,度为2的结点数为1个,度为1的结点数为2个,则度为0的结点数为( )个。 A4 B5 C6 D7 例6 深度为h的m叉树的第k层最多有( )个结点。(1=k=h) Amk-1 Bmk-1 Cmh-1 Dmh-1,满二叉树:,深度为k且有2k-1个结点的二叉树。在满二叉树中,每层结点都是满的,即每层结点都具有最大结点数。 图6.3(a)所示的二叉树,即为一棵满二叉树。,图6.3 满二叉树,

14、完全二叉树:深度为k,结点数为n的二叉树,如果其结点1n的位置序号分别与满二叉树的结点1n的位置序号一一对应,则为完全二叉树, 如图6.3(b)所示。 满二叉树必为完全二叉树, 而完全二叉树不一定是满二叉树。,图6.3 完全二叉树,思考:完全二叉树中度为1的结点个数?,性质4:具有n个结点的完全二叉树的深度为 log2n +1。 证明:假设n个结点的完全二叉树的深度为k,根据性质2可知,k-1层满二叉树的结点总数为 n1=2k-1-1k层满二叉树的结点总数为 n2=2k-1显然有n1nn2,进一步可以推出n1+1nn2+1。将n1=2k-1-1和n2=2k-1代入上式,可得2k-1n2k,即k

15、-1log2nk。 因为k是整数,所以k-1= log2n ,k= log2n +1, 故结论成立。 ,性质5: 对于具有n个结点的完全二叉树, 如果按照从上到下和从左到右的顺序对二叉树中的所有结点从1开始顺序编号, 则对于任意的序号为i的结点有: (1) 如i=1,则序号为i的结点是根结点, 无双亲结点; 如i1, 则序号为i的结点的双亲结点序号为 i/2 。 (2) 如2in,则序号为i的结点无左孩子;如2in,则序号为i的结点的左孩子结点的序号为2i。 (3) 如2i1n,则序号为i的结点无右孩子;如2i1n, 则序号为i的结点的右孩子结点的序号为2i1。,例7 一棵完全二叉树上有100

16、1个结点,其中叶子结点的个数是( )。 A. 250 B. 500 C. 254 D. 505 E. 以上答案都不对 例8 当一棵有n个结点的二叉树按层次从上到下,同层次从左到右将数据存放在一维数组 Aln中时,数组中第i个结点的左孩子为( )。 A. A2i(2i=n) B. A2i+1(2i+1= n) C. Ai/2 D. A2i+1,6.2.3 二叉树的存储结构,二叉树的结构是非线性的, 每一结点最多可有两个后继。 二叉树的存储结构有两种: 顺序存储结构和链式存储结构。,1. 顺序存储结构,图6.4 二叉树与顺序存储结构,1 2 3 4 5 6 7 8 9 10 11 12,图6.4

17、二叉树与顺序存储结构(续),1 2 3 4 5 6 7 8 9 10 11 12,(d)二叉树的顺序存储结构,(c) 二叉树T,图6.5 单支二叉树与其顺序存储结构,1 2 3 4 5 6 7 8 9 10 11 12 13 14 15,2. 链式存储结构对于任意的二叉树来说,每个结点只有两个孩子,一个双亲结点。可以设计每个结点至少包括三个域:数据域、 左孩子域和右孩子域:,其中,LChild域指向该结点的左孩子Data域记录该结点的信息RChild域指向该结点的右孩子,用C语言可以这样声明二叉树的二叉链表结点的结构:,typedef struct Node DataType data; st

18、ruct Node *LChild; struct Node *RChild; BiTNode, *BiTree;,有时,为了便于找到父结点,可以增加一个Parent域, Parent域指向该结点的父结点。 该结点结构如下:,图6.6(a) 二叉树和二叉链表,图6.6(b) 三叉树和三叉链表,若一个二叉树含有n个结点,则它的二叉链表中必含有2n个指针域, 其中必有n1个空的链域。此结论证明如下: 证明:分支数目B=n-1,即非空的链域有n-1个,故空链域有2n-(n-1)=n+1个。 不同的存储结构实现二叉树的操作也不同。如要找某个结点的父结点,在三叉链表中很容易实现;在二叉链表中则需从根指针

19、出发一一查找。可见,在具体应用中,需要根据二叉树的形态和需要进行的操作来决定二叉树的存储结构。思考:三叉树含有n个结点,则它的三叉链表中必含有多少个指针域, 其中有多少个空的链域?,6.3 二叉树的遍历与线索化,6.3.1 二叉树的遍历,图6.7 二叉树结点的基本结构,我们用L、D、R分别表示遍历左子树、访问根结点、 遍历右子树, 那么对二叉树的遍历顺序就可以有六种方式: (1) 访问根,遍历左子树,遍历右子树(记做DLR)。 (2) 访问根,遍历右子树,遍历左子树(记做DRL)。 (3) 遍历左子树,访问根,遍历右子树(记做LDR)。 (4) 遍历左子树,遍历右子树,访问根(记做LRD)。

20、(5) 遍历右子树,访问根,遍历左子树(记做RDL)。 (6) 遍历右子树,遍历左子树,访问根(记做RLD)。,注意:先序、中序、后序遍历是递归定义的, 即在其子树中亦按上述规律进行遍历。 下面就分别介绍三种遍历方法的递归定义。 先序遍历(DLR)操作过程: 若二叉树为空, 则空操作, 否则依次执行如下3个操作: (1) 访问根结点; (2) 按先序遍历左子树; (3) 按先序遍历右子树。, 中序遍历(LDR)操作过程: 若二叉树为空, 则空操作, 否则依次执行如下3个操作: (1) 按中序遍历左子树; (2) 访问根结点; (3) 按中序遍历右子树。 后序遍历(LRD)操作过程: 若二叉树为

21、空, 则空操作, 否则依次执行如下3个操作: (1) 按后序遍历左子树; (2) 按后序遍历右子树; (3) 访问根结点。,D L R,先序遍历序列:A B D C,先序遍历:,L D R,中序遍历序列:B D A C,中序遍历:,L R D,后序遍历序列: D B C A,后序遍历:,对于如图6.8所示的二叉树, 其先序、 中序、 后序遍历的序列如下: 先序遍历: A、 B、 D、 F、 G、 C、 E、 H 。 中序遍历: B、 F、 D、 G、 A、 C、 E、 H 。 后序遍历: F、 G、 D、 B、 H、 E、 C、 A 。,图6.8 二叉树,最早提出遍历问题是对存储在计算机中的表

22、达式求值。例如:(a+b*c)-d/e。该表达式用二叉树表示如图6.9所示。当我们对此二叉树进行先序、中序、后序遍历时,便可获得表达式的前缀、 中缀、 后缀书写形式: 前缀: -+a*bc/de 中缀: a+b*c-d/e 后缀: abc*+de/- 其中中缀形式是算术表达式的通常形式,只是没有括号。 前缀表达式称为波兰表达式。算术表达式的后缀表达式被称作逆波兰表达式。 在计算机内, 使用后缀表达式易于求值。,先序遍历:,中序遍历:,后序遍历:,波兰式,逆波兰式,图6.9 算术式的二叉树表示,写出二叉树的三种遍历结果。,1) 先序遍历,void PreOrder(BiTree root) /*

23、先序遍历二叉树, root为指向二叉树(或某一子树)根结点的指针*/ if (root! =NULL)Visit(root -data); /*访问根结点*/PreOrder(root -LChild); /*先序遍历左子树*/PreOrder(root -RChild); /*先序遍历右子树*/,【算法6.1 先序遍历二叉树】,void PreOrder(BiTree T) if (T=NULL) return; Visite(T-data); /printf() PreOrder(T-lchild); PreOrder(T-rchild); ,返回,返回,返回,返回,A,C,B,D,返回,

24、先序序列:A B D C,2)中序遍历 void InOrder(BiTree root) /*中序遍历二叉树, root为指向二叉树(或某一子树)根结点的指针*/ if (root! =NULL)InOrder(root -LChild); /*中序遍历左子树*/Visit(root -data); /*访问根结点*/InOrder(root -RChild); /*中序遍历右子树*/ ,【算法6.2 中序遍历二叉树】,3) 后序遍历 void PostOrder(BiTree root) /* 后序遍历二叉树, root为指向二叉树(或某一子树)根结点的指针*/ if(root! =NUL

25、L)PostOrder(root -LChild); /*后序遍历左子树*/PostOrder(root -RChild); /*后序遍历右子树*Visit(root -data); /*访问根结点*/ ,【算法6.3 后序遍历二叉树】,图6.10 中序遍历二叉树的递归过程,依据:递归算法执行过程中工作栈的状态变化情况思路(中序非递归为例)1) 从根结点开始进行考察,即根结点作为当前结点,当前结点进栈;2)当前结点的左孩子,左孩子的左孩子,依次进栈,直到左孩子为空;3)一旦左孩子为空,则访问左孩子为空的结点,即栈顶元素,弹出栈顶元素并访问,此时将栈顶元素的右孩子作为新的考察结点;4)重复上述2

26、)、3)过程,直到栈及当前考察结点为空为止。,6.3.2 基于栈的递归消除,过程如下:,中序遍历二叉树的非递归算法首先应用递归进层的三件事与递归退层的三件事的原则, 直接先给出中序遍历二叉树的非递归算法基本实现思路。,void inorder(BiTree root); int i=0; p=bt; L1: if (p!=NULL) /* 遍历左子树 */ top=top+2; if(topm);,stop-1=p; /* 本层参数进栈 */ stop=L2; /* 返回地址进栈 */p=p-LChild; /* 给下层参数赋值 */goto L1; /* 转向开始 */ L2: Visit(

27、p-data); /* 访问根 */top=top+2; if(topRChild; goto L1; ,L3: if(top! =0) addr=stop; p=stop-1; /* 取出返回地址 */top=top-2; /* 退出本层参数 */goto addr; ,【算法6.4(a) 中序遍历二叉树的非递归算法初步】,/* sm 表示栈, top表示栈顶指针 */ void inorder(BiTree root) /* 中序遍历二叉树, bt为二叉树的根结点 */ top=0; p=bt; dowhile(p! =NULL)if (topm) return(overflow); to

28、p=top+1; stop=p; p=p-LChild; /* 遍历左子树 */if(top! =0)p=stop; top=top-1; Visit(p-data); /* 访问根结点 */p=p-RChild; /* 遍历右子树 */ while(p! =NULL | top! =0) ,【算法6.4(b) 中序遍历二叉树的非递归算法(直接实现栈操作),void InOrder(BiTree root)/* 中序遍历二叉树的非递归算法 */ InitStack ( ,【算法6.4(c) 中序遍历二叉树的非递归算法(调用栈操作的函数)】,2) 后序遍历二叉树的非递归算法 void PostO

29、rder(BiTree root) BiTNode * p, *q; BiTNode *S; int top=0; q=NULL; p=root; S=(BiTNode*)malloc(sizeof(BiTNode*)*NUM); /* NUM为预定义的常数 */while(p! =NULL | top!=0),while(p! =NULL) top=+; stop=p; p=p-LChild; /* 遍历左子树 */if(top0) p=stop; if(p-RChild=NULL) |(p-RChild=q)/* 无右孩子, 或右孩子已遍历过 */visit(p-data); /* 访问根

30、结点* /q=p; /* 保存到q, 为下一次已处理结点前驱 */top-; p=NULL; else p=p-RChild;free(s); ,【算法6.5 后序遍历二叉树的非递归算法(调用栈操作的函数)】,6.3.3 遍历算法应用,1. 输出二叉树中的结点遍历算法将走遍二叉树中的每一个结点,故输出二叉树中的结点并无次序要求,因此可用三种遍历中的任何一种算法完成。 下面写出先序遍历顺序的实现算法。,void PreOrder(BiTree root) /* 先序遍历输出二叉树结点, root为指向二叉树根结点的指针 */ if (root! =NULL)printf (root -data)

31、; /* 输出根结点 */PreOrder(root -LChild); /* 先序遍历左子树 */PreOrder(root -RChild); /* 先序遍历右子树 */ ,【算法6.6 先序遍历输出二叉树中的结点】,2. 输出二叉树中的叶子结点输出二叉树中的叶子结点与输出二叉树中的结点相比,它是一个有条件的输出问题,即在遍历过程中走到每一个结点时需进行测试,看是否有满足叶子结点的条件。故只需改变算法6.6 的黑体部分。,void PreOrder(BiTree root) /* 先序遍历输出二叉树中的叶子结点, root为指向二叉树根结点的指针 */ if (root! =NULL)if

32、 (root -LChild=NULL /* 先序遍历右子树 */ ,【算法6.7 先序遍历输出二叉树中的叶子结点】,3. 统计叶子结点数目,/* LeafCount是保存叶子结点数目的全局变量, 调用之前初始化值为0 */ void leaf(BiTree root) if(root! =NULL)leaf(root-LChild); leaf(root-RChild); if (root -LChild=NULL ,【算法6.8(a) 后序遍历统计叶子结点数目】,/* 采用递归算法,如果是空树,返回0;如果只有一个结点,返回1;否则为左右子树的叶子结点数之和 */ int leaf(BiT

33、ree root) int LeafCount; if(root=NULL) LeafCount =0; else if(root-lchild=NULL) ,【算法6.8(b) 后序遍历统计叶子结点数目】,4. 建立二叉链表方式存储的二叉树给定一棵二叉树,我们可以得到它的遍历序列;反过来,给定一棵二叉树的遍历序列,我们也可以创建相应的二叉链表。 这里所说的遍历序列是一种“扩展的遍历序列”。在通常的遍历序列中,均忽略空子树,而在扩展的遍历序列中,必须用特定的元素表示空子树。例如,图6.8 中二叉树的“扩展先序遍历序列”为:,AB.DFGC.E.H 其中用小圆点表示空子树。,利用“扩展先序遍历序

34、列” 创建二叉链表的算法如下: void CreateBiTree(BiTree *bt) char ch; ch=getchar(); if(ch=.) *bt=NULL; else*bt=(BiTree)malloc(sizeof(BiTNode); (*bt)-data=ch; CreateBiTree( ,【算法6.9 用“扩展先序遍历序列”创建二叉链表】,图6.12 二叉树高度示意图,设函数表示二叉树bt的高度,则递归定义如下: 若bt为空,则高度为0。 若bt非空,其高度应为其左右子树高度的最大值加1, 如图6.12所示。二叉树的高度(深度)为二叉树中结点层次的最大值,即结点的层次

35、自根结点起递推。设根结点为第1层的结点,所有h层的结点的左右孩子结点在h+1层,则可以通过先序遍历计算二叉树中的每个结点的层次,其中最大值即为二叉树的高度。,int PostTreeDepth(BiTree bt) /* 后序遍历求二叉树的高度递归算法 */ int hl, hr, max; if(bt! =NULL)hl=PostTreeDepth(bt-LChild); /* 求左子树的深度 */hr=PostTreeDepth(bt-RChild); /* 求右子树的深度 */max=hlhr?hl: hr; /* 得到左、 右子树深度较大者*/return(max+1); /* 返回树

36、的深度 */else return(0); /* 如果是空树, 则返回0 */ ,【算法6.10 后序遍历求二叉树的高度递归算法】,6. 按树状打印的二叉树例:假设以二叉链表存储的二叉树中,每个结点所含数据元素均为单字母, 要求实现如图6.13所示打印结果。 这实际是一个二叉树的横向显示问题:因为二叉树的横向显示应是二叉树竖向显示的90旋转,又由于二叉树的横向显示算法一定是中序遍历算法,所以把横向显示的二叉树算法改为先右子树再根结点再左子树的RDL结构, 实现算法如下:,图6.13 树状打印的二叉树示意,void PrintTree(TreeNode Boot, int nLayer) /*

37、按竖向树状打印的二叉树 */if(Boot= =NULL) return; PrintTree(Boot-pRight, nLayer+1); for(int i=0; ich); PrintTree(Boot-pLeft, nLayer+1); ,【算法6.11 按竖向树状打印的二叉树】,6.3.4 线索二叉树,1. 基本概念二叉树的遍历运算是将二叉树中结点按一定规律线性化的过程。 当以二叉链表作为存储结构时,只能找到结点的左、右孩子信息, 而不能直接得到结点在遍历序列中的前驱和后继信息。 要得到这些信息可采用以下两种方法:第一种方法是将二叉树遍历一遍,在遍历过程中便可得到结点的前驱和后继,

38、但这种动态访问浪费时间;第二种方法是充分利用二叉链表中的空链域, 将遍历过程中结点的前驱、 后继信息保存下来。,我们知道,在有n个结点的二叉链表中共有2n个链域,但只有n-1个有用的非空链域,其余n+1个链域是空的。我们可以利用剩下的n+1个空链域来存放遍历过程中结点的前驱和后继信息。 现作如下规定:若结点有左子树,则其LChild域指向其左孩子,否则LChild域指向其前驱结点;若结点有右子树,则其RChild域指向其右孩子,否则RChild域指向其后继结点。为了区分孩子结点和前驱、后继结点,为结点结构增设两个标志域,如下所示:,其中:,在这种存储结构中,指向前驱和后继结点的指针叫做线索。

39、以这种结构组成的二叉链表作为二叉树的存储结构,叫做线索链表。对二叉树以某种次序进行遍历并且加上线索的过程叫做线索化。线索化了的二叉树称为线索二叉树。,Ltag=,Rtag=,0,0,0,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,头结点: lt=0, lc指向根结点 rt=1, rc指向遍历序列中最后一个结点遍历序列中第一个结点的lc域和最后 一个结点的rc域都指向头结点,2. 二叉树的线索化,void Inthread(BiTree root) /* 对root所指的二叉树进行中序线索化, 其中全局变量pre始终指向刚访问过的结

40、点, 其初值为NULL* / if (root! =NULL)Inthread(root-LChild); /* 线索化左子树 */if (root-LChild=NULL)root-Ltag=1; root-LChile=pre; / *置前驱线索 */if (pre! =NULL /*线索化右子树*/ ,【算法6.12 建立中序线索树】,图6.14 线索二叉树,JD *zxxsh(JD *bt) JD *p,*pr,*sM,*t;int i=0;t=(JD *)malloc(sizeof(JD);t-lt=0; t-rt=1; t-rc=t;if(bt=NULL) t-lc=t;else

41、t-lc=bt; pr=t; p=bt;do while(p!=NULL) si+=p; p=p-lc; if(i0) p=s-i;printf(“%c “,p-data);if(p-lc=NULL) p-lt=1; p-lc=pr;if(pr-rc=NULL) pr-rt=1; pr-rc=p;pr=p; p=p-rc;while(i0|p!=NULL);pr-rc=t; pr-rt=1; t-rc=pr;return(t); ,非 递 归 算 法,算法 按中序线索化二叉树,Ch5_20.c,JD *zxxsh(JD *bt) JD *p,*pr,*sM,*t;int i=0;t=(JD *

42、)malloc(sizeof(JD);t-lt=0; t-rt=1; t-rc=t;if(bt=NULL) t-lc=t;else t-lc=bt; pr=t; p=bt;do while(p!=NULL) si+=p; p=p-lc; if(i0) p=s-i;printf(“%c “,p-data);if(p-lc=NULL) p-lt=1; p-lc=pr;if(pr-rc=NULL) pr-rt=1; pr-rc=p;pr=p; p=p-rc;while(i0|p!=NULL);pr-rc=t; pr-rt=1; t-rc=pr;return(t); ,算法 按中序线索化二叉树,Ch5

43、_20.c,JD *zxxsh(JD *bt) JD *p,*pr,*sM,*t;int i=0;t=(JD *)malloc(sizeof(JD);t-lt=0; t-rt=1; t-rc=t;if(bt=NULL) t-lc=t;else t-lc=bt; pr=t; p=bt;do while(p!=NULL) si+=p; p=p-lc; if(i0) p=s-i;printf(“%c “,p-data);if(p-lc=NULL) p-lt=1; p-lc=pr;if(pr-rc=NULL) pr-rt=1; pr-rc=p;pr=p; p=p-rc;while(i0|p!=NULL

44、);pr-rc=t; pr-rt=1; t-rc=pr;return(t); ,算法 按中序线索化二叉树,Ch5_20.c,i,输出:B,JD *zxxsh(JD *bt) JD *p,*pr,*sM,*t;int i=0;t=(JD *)malloc(sizeof(JD);t-lt=0; t-rt=1; t-rc=t;if(bt=NULL) t-lc=t;else t-lc=bt; pr=t; p=bt;do while(p!=NULL) si+=p; p=p-lc; if(i0) p=s-i;printf(“%c “,p-data);if(p-lc=NULL) p-lt=1; p-lc=p

45、r;if(pr-rc=NULL) pr-rt=1; pr-rc=p;pr=p; p=p-rc;while(i0|p!=NULL);pr-rc=t; pr-rt=1; t-rc=pr;return(t); ,1,算法 按中序线索化二叉树,Ch5_20.c,输出:B,i,P-C,JD *zxxsh(JD *bt) JD *p,*pr,*sM,*t;int i=0;t=(JD *)malloc(sizeof(JD);t-lt=0; t-rt=1; t-rc=t;if(bt=NULL) t-lc=t;else t-lc=bt; pr=t; p=bt;do while(p!=NULL) si+=p; p

46、=p-lc; if(i0) p=s-i;printf(“%c “,p-data);if(p-lc=NULL) p-lt=1; p-lc=pr;if(pr-rc=NULL) pr-rt=1; pr-rc=p;pr=p; p=p-rc;while(i0|p!=NULL);pr-rc=t; pr-rt=1; t-rc=pr;return(t); ,算法 按中序线索化二叉树,Ch5_20.c,i,P-C,输出:B,JD *zxxsh(JD *bt) JD *p,*pr,*sM,*t;int i=0;t=(JD *)malloc(sizeof(JD);t-lt=0; t-rt=1; t-rc=t;if(bt=NULL) t-lc=t;else t-lc=bt; pr=t; p=bt;do while(p!=NULL) si+=p; p=p-lc; if(i0) p=s-i;printf(“%c “,p-data);if(p-lc=NULL) p-lt=1; p-lc=pr;if(pr-rc=NULL) pr-rt=1; pr-rc=p;pr=p; p=p-rc;while(i0|p!=NULL);pr-rc=t; pr-rt=1; t-rc=pr;return(t); ,

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


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

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

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