对二叉树非递归遍历的理解
假设有二叉树如下
一、先序遍历
先序遍历结果为:ABDFGEC
先来看看先序遍历递归法的流程描述:
描述:
传递A结点作参数
第 一 层
(1)直接输出当前结点值A
(2)传递A结点的左子结点B作参数,调用第二层
第 二 层
(1)直接输出当前结点值B
(2)传递B结点的左子结点D作参数,调用第三层
第 三 层
(1)直接输出当前结点值D
(2)传递D结点的左子结点F作参数,调用第四层
第 四 层
(1)直接输出当前结点值F
(2)F无左子结点
(3)F有右子结点,以右子结点G为参数重走整个流程
(4)F彻底访问完,退回第三层D
第 三 层
(1)D左子结点被访问过
(2)D无右子结点,退回第二层B
第 二 层
(1)B左子结点被访问过
(2)B有右子结点,以右子结点E为参数重走整个流程
(3)B彻底访问完,退回第一层A
第 一 层
(1)A左子结点被访问过
(2)A有右子结点,以右子结点C为参数重走整个流程
(3)A彻底访问完,退回主调函数
分析:
根据上面的描述不难发现,最初传递的参数为根节点A,由于采用的是递归方式遍历这棵树,因此参数(假设只是参数)被依次压入栈中。
因为是先序遍历,因此对于每个参数,在被压入栈之后就要马上输出这个参数,而后将该参数的左子结点压入栈,重复上述步骤直至遍历到最左下角的叶子结点。
访问完最左下角的叶子后,便意味着结束了第17、18行,现在只差第20行没有执行了,因此将该叶子结点的右子结点作为参数传递给下一层函数,接着重复上面的步骤直至访问到头。
访问到头后,便要一步一步退回(pop),直到退回到主调函数(main)为止。
设计:
因此,可以通过堆栈(stack)模拟参数的存放过程,对于根节点:
(1)首先使用一层循环访问到最左下角的叶子结点,边访问边输出,将参数压栈
(2)接着判断栈是否为空,不为空则访问其右子结点,同时退回上一层(pop)
(3)重复步骤直至结点与栈均为空
二、中序遍历
与先序遍历类似,只不过输出的位置在一口气访问到左下角叶子结点之后。
三、后序遍历
与上面两者不同,由于输出位于 分别调用左右结点作为参数的函数之后,因此对于一个结点的值是否输出这个问题,需要先判断此结点的左右孩子是否已经访问完,考虑后序遍历 左-右-上 的特点,只要右孩子被访问过了,那么左右孩子一定已经被访问完。
如何判断右孩子是否被访问过呢?
可以用一个结点 pre 记录当前访问的结点,在下一次执行while循环时,pre还没有被更新,依旧保存的是上一层访问的结点,如果本次访问的结点的右孩子正好在上一次已经被访问过,那么就可以直接输出了。否则就去访问该结点的右子结点。
需要注意的是,如果左右孩子都被访问过,需要将该元素指针置为 NULL,以防止下次循环时反复卡在这个元素处,不能终止循环。
代码
#include<iostream>
#include<cstdio>
#include<stack>
#include<cstdlib>
using namespace std;
typedef char ElemType;
typedef struct Node{
ElemType data;
struct Node *lnode, *rnode;
struct Node *parent;
}BiNode;
void PreOrderTraverse(BiNode *btree)
{
if(!btree)
printf("#");
else{
printf("%c", btree->data);
PreOrderTraverse(btree->lnode);
PreOrderTraverse(btree->rnode);
}
}
void CreateBiNode(BiNode *&btree) // 二叉链表表示树
{
ElemType data;
scanf("%c", &data);
if(data == '#')
btree = NULL;
else{
if(!(btree = (BiNode *)malloc(sizeof(BiNode)))) exit(0);
btree->data = data;
CreateBiNode(btree->lnode);
CreateBiNode(btree->rnode);
}
}
// 中序遍历
void InOrderWithoutRecursion(BiNode *tree)
{
stack<BiNode*> s;
BiNode *p = tree;
while(p || !s.empty())
{
while(p)
{
s.push(p);
p = p->lnode;
}
if(!s.empty())
{
p = s.top();
s.pop();
cout<<p->data;
p = p->rnode;
}
}
cout<<endl;
}
// 先序遍历
void PreOrderWithoutRecursion(BiNode *tree)
{
stack<BiNode*> s;
BiNode *p = tree;
while(p || !s.empty())
{
while(p)
{
cout<<p->data;
s.push(p);
p = p->lnode;
}
if(!s.empty())
{
p = s.top();
s.pop();
p = p->rnode;
}
}
cout<<endl;
}
// 后序遍历
void PostOrderWithoutRecursion(BiNode *tree)
{
stack<BiNode*> s;
BiNode *p = tree, *pre = NULL;
while(p || !s.empty())
{
while(p)
{
s.push(p);
p = p->lnode;
}
if(!s.empty())
{
p = s.top();
if(p->rnode && p->rnode!=pre)
p = p->rnode;
else
{
s.pop();
cout<<p->data;
pre = p;
p = NULL;
}
}
}
cout<<endl;
}
int main()
{
BiNode *root;
CreateBiNode(root);
InOrderWithoutRecursion(root);
PreOrderWithoutRecursion(root);
PostOrderWithoutRecursion(root);
return 0;
}