目录
【例2】求二叉树的叶子结点的个数。可以用两种方法求解这个问题。
【例3】设计一个算法,在二叉树中求在先序序列中处于第k个位置的结点。
问题的提出
遍历算法描述
遍历算法应用举例
线索二叉树
问题的提出
顺着某一条搜索路径巡访二叉树中的结点,使得每个结点均被访问一次,而且仅被访问一次。
“访问”的含义可以很广,如:输出结点的数据、判断结构信息等。
“遍历”是任何类型均有的操作,对线性结构而言,只有一条搜索路径(因为每个结点均只有一个后继),故不需要另加讨论。而二叉树是非线性结构,每个结点有两个后继,则存在如何遍历即按什么样的搜索路径遍历的问题。
对“二叉树”而言,可以有三条搜索路径:1.先上后下的按层次遍历;2.先左(子树)后右(子树)的遍历;3.先右(子树)后左(子树)的遍历。
先左后右的遍历算法
二叉树的遍历的常用方法有三种:DLR、LDR和LRD,分别称作先根次序(前序,先序)遍历、中根次序(中序)遍历和后根次序(后序)遍历。
先(根)序的遍历算法
中(根)序的遍历算法
后(根)序的遍历算法
(1)先序遍历若二叉树为空,则空操作;否则依次执行以下操作;
访问根结点;
先序遍历根结点的左子树;
先序遍历根结点的右子树;
(2) 中序遍历若二叉树为空,则空操作;否则依次执行以下操作:
中序遍历根结点的左子树;
访问根结点;
中序遍历根结点的右子树;
(3) 后序遍历若二叉树为空,则空操作;否则依次执行以下操作:
后序遍历根结点的左子树;
后序遍历根结点右子树;
访问根结点;
二叉树遍历的输出顺序示例
二叉树遍历过程的示例演示
如果表达式用二叉树存放二叉树的先序,中序,后序遍历就是表达式的前缀,中缀,后缀表示表达式的后缀表示称为逆波兰式,计算机中一般都这样表示这种表示方法不用考虑运算符的优先级,从左到右机械运算即可
运算符组成的树,用不同的方式遍历,会得到不同的结果。
遍历算法描述
◆先序(前序)遍历二叉树的递归算法
◆中序遍历二叉树的递归算法
◆后序遍历二叉树的递归算法
二叉树遍历算法的实现
(1)先序遍历
(2)中序遍历
(3)后序遍历
先序遍历示范
三种遍历算法的不同之处仅在于访问根结点和遍历左右子树的先后次序,若在算法中暂时抹去和递归无关的printf语句,则三种遍历算法基本上相同,这说明这三种遍历算法的搜索路线相同,从递归执行过程的角度来看三种遍历算法也是完全相同的。
3.二叉树遍历算法的非递归实现
二叉树遍历的递归实现思路自然、简单,易于理解,但执行效率较低。为了提高程序的执行效率,可以显式的设置栈,写出相应的非递归遍历算法。非递归的遍历算法可以根据递归算法的执行过程写出。
中序遍历非递归算法图示
遍历序列与二叉树的结构
对一棵二叉树进行遍历得到的遍历序列(先序或中序或后序)是唯一的。但仅由一个二叉树的遍历序列(先序或中序或后序)不能决定一棵二叉树,例如图(a)和(b)所示的两棵不同的二叉树,它们的先序遍历序列是相同的
由二叉树的先序和中序序列建树
仅知二叉树的先序序列“abcdefg”不能唯一确定一棵二叉树,如果同时已知二叉树的中序序列“cbdaegf”,则会如何?
可以证明,如果同时知道一棵二叉树的先序序列和中序序列,或者同时知道一棵二叉树的中序序列和后序序列,就能唯一地确定这棵二叉树。那么知道一棵二叉树的先序序列和中序序列,如何构造二叉树呢?由定义,二叉树的先序遍历是先访问根结点D,然后遍历根的左子树L,最后遍历根的右子树R。因此在先序序列中的第一个结点必是根结点D;另一方面,中序遍历是先遍历根的左子树L,然后访问根结点D,最后遍历根的右子树R,于是根结点D把中序序列分成两部分:在D之前的是由左子树中的结点构成的中序序列,在D之后的是由右子树中的结点构成的中序序列。反过来,根据左子树的中序序列的结点个数,又可将先序序列除根以外的结点分成左子树的先序序列和右子树的先序序列。依次类推,即可递归得到整棵二叉树。
例如已知一棵二叉树的先序序列为abcdefg,中序序列为cbdaegf,构造其对应的二叉树。首先由先序序列得知二叉树的根为a ,则其左子树的中序序列必为cbd,右子树的中序序列为egf。反过来得知其左子树的先序序列必为bcd,右子树的先序序列为efg。
典型题例
【例1】建立二叉树的二叉链表存储结构
构造二叉链表的方法很多,这里介绍一个基于先序遍历的构造算法。
假设二叉树中结点的元素均为单个字符。算法的输入是二叉树的先序序列,但必须在其中加入虚结点(以“#”表示)以示空指针的位置,这样的先序序列称为扩展的先序序列。如图所示的二叉树,输入的扩展先序遍历的字符序列为:ABD#E###C#F##。首先输入一个根结点,若输入的是“#”字符,表示该二叉树为空树,即root=NULL;否则向系统申请结点空间,由root指向该结点,把输入的字符赋给root->data,之后,依次递归地建立它的左子树root->lchild和右子树root->rchild。
算法描述如下:
【例2】求二叉树的叶子结点的个数。可以用两种方法求解这个问题。
方法一:设置一个初值为0的变量leaf进行计数,在遍历的过程中每访问一个结点就对该结点进行判断,若是叶子,将leaf加1。当遍历完整个二叉树后,leaf的值就是叶子结点的个数。可以采用任何遍历算法,在此采用先序遍历算法实现。具体算法描述如下
方法二:当二叉树为空时,叶子结点的个数为0;当二叉树只有一个结点时,叶子结点的个数为1;否则,叶子结点的个数等于左、右子树叶子结点个数之和。因此,可用下面的递归公式计算二叉树root的叶子结点个数BtLeaf(root)
【例3】设计一个算法,在二叉树中求在先序序列中处于第k个位置的结点。
【分析与解答】设置一个初值为0的变量count进行计数,在先序遍历的过程中每访问一个结点就进行计数,即将count加1,然后判断count的值是否等于给定的k,等于返回当前指针值,遍历完成还没有找到第k个结点即二叉树中结点个数小于k,返回空指针NULL。
【例4】在二叉树中查找值为x的结点,找到,返回指向该结点的指针,否则返回空指针。首先将根结点的值与x比较,若相等,则返回指向根结点的指针;否则,在根的左子树中继续同样的查找,若未找到,则在右子树中继续查找,找到,返回指向该结点的指针,否则说明在二叉树中不存在值为x的结点,返回空指针。
【例5】求二叉树的深度。
和例2类似,也可以用两种方法求解这个问题。
方法一:以先序遍历二叉树的算法为基础,二叉树的深度为二叉树中结点层次的最大值。根结点的层次为1,其余结点的层数等于其双亲结点的层数加1。因此,可以通过遍历计算二叉树中的每个结点的层次,其中最大值即为二叉树的深度。tdeep为全局变量,调用前置初值零,在调用函数TreeDeep之后,tdeep的值就是二叉树的深度
方法二:当二叉树为空时,其深度为0;否则,其深度为其左右子树深度的最大值加1。因此,可用下面的递归公式计算二叉树root的深度:
到线索二叉树
资料仅供学习使用
如有错误欢迎留言交流
上理考研周导师的其他专栏:
上理考研周导师了解更多