女神一直不懂遍历二叉树,半夜突然给我发了一条消息
简介
作者简介:青铜码农,和大多数同学一样从零开始一步步学习,一步步积累。期待您的关注,让我们一起成长~注:本人学疏才浅,文章如有错误之处,敬请指正~
一、二叉树的遍历原理
二叉树的遍历次序不同于线性结构。树的结点之间不存在唯一的前驱和后继关系,在访问一个结点后,下一个被访问的结点将面临不同的选择。
二、二叉树的遍历方法
二叉树的遍历方式主要分为以下4种:
01
前序遍历
02
中序遍历
03
后序遍历
04
层序遍历
1.前序遍历
2.中序遍历
3.后序遍历
4.层序遍历
三、遍历算法
二叉树的定义是用递归的方式,所以实现遍历算法,也可以采用递归。
1.前序遍历算法
相关代码如下:
/* 初始条件: 二叉树T存在 */
/* 操作结果: 前序递归遍历T */
void PreOrderTraverse(BiTree T)
{
if(T==NULL)
return;
printf("%c",T->data); /* 显示结点数据,可以更改为其它对结点操作 */
PreOrderTraverse(T->lchild);/* 再先序遍历左子树 */
PreOrderTraverse(T->rchild);/* 最后先序遍历右子树 */
}
现在有如下图这棵二叉树T:
这里有必要做个说明,请认真看,以免影响接下来的阅读。
下文出现的PT(T->lchild)代表PreOrderTraverse(T->lchild); 同样的,PT(T->rchild)代表PreOrderTraverse(T->rchild);
”往下执行“代表程序将运行到下一行代码。
”A左B”表示结点A的左孩子B,同样的,“A右C”表示结点A的右孩子C。
(过程难免有点繁琐,请一定要耐心看下去!)
如果到这里能够明白前序遍历算法是怎么一回事,那么恭喜你,可以继续往下看。如果没看懂,也没关系,回去重复看几遍,先跟着文章思路一边理解一边自己写出来,到最后自己独立完整写一遍,在脑中把整个过程捋一遍。如果做到以上几点还是看不懂的话,那不是你的问题,是我的问题。
2.中序遍历算法
别担心,中序遍历算法和前序遍历算法仅仅是代码顺序上的差异。
/* 初始条件: 二叉树T存在 */
/* 操作结果: 中序递归遍历T */
void InOrderTraverse(BiTree T)
{
if(T==NULL)
return;
InOrderTraverse(T->lchild); /* 中序遍历左子树 */
printf("%c",T->data); /* 显示结点数据,可以更改为其它对结点操作 */
InOrderTraverse(T->rchild); /* 最后中序遍历右子树 */
}
让我们来看看当调用InOrderTraverse(BiTree T)函数时,程序是如何运行的:
(1)调用InOrderTraverse(T) ,T的根结点不为null,于是调用IT(B->lchild); 访问B左D,不为null,继续调用IT(D->lchild),访问D左H,继续调用IT(H->lchild),访问H左孩子,为null,返回IT(H->lchild),往下执行printf打印H
(2)再往下执行IT(H->rchild),访问H右K,不为null,执行IT(K->lchild),访问K的左孩子,为null,返回IT(K->lchild),往下执行printf打印K
(3)再往下执行IT(K->rchild),访问K右孩子,为null,返回IT(K->rchild),至此,此函数执行完毕。返回IT(D->lchild)处,往下执行printf打印D
(4)再往下执行IT(D->rchild),访问D的右孩子,为null,返回IT(D->rchild)处,至此,此函数执行完毕。返回IT(B->lchild)处,往下执行printf打印B
(5)再往下执行IT(B->rchild),访问B右E,不为null,执行IT(E->lchild),访问E的左孩子,为null,返回IT(E->lchild)处,往下执行printf打印E
(6)再往下执行IT(E->rchild),访问E的右孩子,为null,返回IT(E->rchild),至此,结点B的递归函数执行完毕。回到最初的IT(A->lchild)处,往下执行printf打印A
(7)再往下执行IT(A->rchild),访问A右C,再递归访问结点C的左孩子F,结点F的左孩子I。因为I无左孩子,打印I,之后分别打印F、C、G、J
综上,中序遍历这棵二叉树的结点顺序是:HKDBEAIFCGJ
3.后序遍历算法
代码如下:
/* 初始条件: 二叉树T存在 */
/* 操作结果: 后序递归遍历T */
void PostOrderTraverse(BiTree T)
{
if(T==NULL)
return;
PostOrderTraverse(T->lchild); /* 先后序遍历左子树 */
PostOrderTraverse(T->rchild); /* 再后序遍历右子树 */
printf("%c",T->data); /* 显示结点数据,可以更改为其它对结点操作 */
}
四、推导遍历方法
【例题】已知一棵二叉树的前序遍历序列是ABDECF,中序遍历序列为DBEAFC,请问这棵二叉树的后序遍历结果是多少?
(先做再往下看答案哦)
【解析】三种遍历都是从根结点开始,前序遍历是先打印再递归左和右,因为题目中前序遍历序列是ABDECF,第1个字母是A先被打印出来的,就说明A是根结点。再由中序遍历DBEAFC,可以得知D、B、E是A的左子树的结点,F、C是A右子树的结点,如下图:
然后看前序中的DBE,它的顺序是ABDECF,是先打印B再D最后E,所以B应该是A的左孩子,而D、E只能是B的孩子,注意,它们两不一定都是孩子,还有可能是子孙。再看中序遍历是DBEAFC,由于D在B的左侧,而E在右侧,所以可以确定D是B的左孩子,E是B的右孩子。
再看前序中的F、C,它的顺序是ABDECF,意味着C是A的右孩子,而F就只能是C的孩子,此时是左孩子还是右孩子还不确定。再看中序序列DBEAFC,F是在C的前面打印,这就说明F是C的左孩子,否则在C后面打印就是右孩子了。最终得到的二叉树如下图显示:
如果题目是这样的:二叉树中的中序序列是BFDGACE,后序序列是FGDBECA,求前序序列?
(先做再往下看答案哦)
【解析】 由后序的FGDBECA,得到A是根结点,因此前序首字母为A。根据中序序列BFDGACE可分为BFDG和CE这两棵树,由后序序列FGDBECA,知道B是A的左孩子,目前前序序列已知为AB
再由中序序列BFDGACE,知道FDG为B的右子孙(这里得好好思考下),再由后序序列的FGDBECA,知道D是B的右孩子,目前前序序列已知为ABD
在这里我们可以得出两个二叉树遍历的性质:
已知前序遍历序列和中序遍历序列,可以唯一确定一棵二叉树。
已知中序遍历序列和后序遍历序列,可以唯一确定一棵二叉树。
比如:前序序列为ABC,后序序列为CBA,可知道A为根结点,但接下来无法知道哪个结点时左子树,哪个是右子树。
END
我是码龙,如果我的文章对你有帮助,请点个 赞👍🏻 支持我一下