开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第17天,点击查看活动详情
3.3.2 中序非递归遍历
二叉树的非递归遍历
中序遍历非递归遍历算法
非递归算法实现的基本思路: 使用堆栈
这里建议看视频的演示,非常形象
1.遇到一个结点,就把它压栈,并去遍历它的左子树;
2.当左子树遍历结束后,从栈顶弹出这个结点并访问它;
3.然后按其右指针再去中序遍历该结点的右子树
以下是完整代码实现演示
void InOrderTraversal(BinTree BT)
{
BinTree T = BT;//把BT赋给临时变量T
Stack S = CreateStack(MaxSize);//创建并初始化堆栈
while(T || !IsEmpty(S) ){//树不空且堆栈不空
while(T){//判断堆栈空不空
//一直向左并将沿途结点压入堆栈
Push(S,T);//把T压入堆栈S中
T = T->Left;//然后把T往左挪,就是边挪边把结点压到堆栈里面去,压到底T为NULL就退出来
}
if(!IsEmpty(S)){
T = Pop(S);//结点弹出堆栈
printf("%5d",T->Data);//(访问)打印结点
T = T->Right;//转向右子树
}
}
}
ppoopoppoo错误
PPOPOOPPOO正确
第二次碰到同一个的时候就print出来
先序遍历的非递归遍历算法?
把上方那个算法中if中的printf("%5d",T->Data)移到while(T)中Push的后面
后序遍历非递归遍历算法?
3.3.3 层序遍历
二叉树遍历的核心问题:二维结构的线性化(变成一维的)
1.从结点访问其左、右儿子结点
2.访问左儿子后,右儿子结点怎么办?
1.需要一个存储结构保存暂时不访问的结点
2.存储结构:堆栈、队列
队列实现
遍历从根结点开始,首先将根结点入队,然后开始执行循环:结点出队、访问该结点、其左右儿子入队
最后结果就是:层序遍历 => A B C D F G I E H
//代码实现
void LevelOrderTraversal(BinTree BT)
{
Queue Q; BinTree T;
if(!BT) return;//若是空树直接返回
Q = CreateQueue(MaxSize);//创建并初始化队列Q
AddQ(Q,BT);//把BT这个根节点放到Q这个队列里
while(!IsEmptyQ(Q)){
T = DeleteQ(Q);//抛出元素赋给T就是一个指针
printf("%d\n",T->Data);//访问去除队列的结点
if(T->Left) Add(Q,T->Left);//左右儿子放到队列里去
if(T->Right) AddQ(Q,T->Right);
}
}
3.3.4 遍历应用例子
【例】遍历二叉树的应用:输出二叉树中的叶子结点
在二叉树的遍历算法中增加检测结点的"左右子树是否都为空"
void PreOrderPrintLeaves(BinTree BT)
{
if(BT){
if(!BT-Left && !BT->Right)
printf("%d",BT->Data);
PreOrderPrintLeaves(BT -> Left);
PreOrderPrintLeaves(BT -> Right);
}
}
【例】求二叉树的高度
void PreOrderGetHeight(BinTree BT)
{
int HL,HR,MaxH
if(BT){
HL = PostOrderGetHeight(BT->Left);//求左子树的深度,这两个都是递归哦
HR = PostOrderGetHeight(BT->Right);//求右子树的深度
MaxH = (HL > HR) ? HL :HR;//取左右子树较大的深度
return (MaxH + 1);//返回树的深度
}
else return 0;//空树深度为0
}
【例】二元运算表达式树及其遍历
中缀表达式是不准的,会收到运算符优先度的影响,其它都是准的
解决中缀表达式不准的问题:左子树开始前加个左括号,结束后加个右括号,通过加括号的形式解决优先度问题
【例】由两种遍历序列确定二叉树
已知三种遍历中的任意两种遍历序列,能否唯一确定一颗二叉树呢?
答案:必须要有中序遍历才行
没有中序的困扰:
1.先序遍历序列:A B
2.后序遍历序列:B A
会发现符合条件的树不止一个
先序第一个是根,后序最后一个是根
问:已知有颗5个结点的二叉树,其前序遍历序列是a????,中序遍历序列是a????,可以断定:
答案: 该树根结点是a,且没有左子树