<mark>简单解释:</mark>
- 前序遍历:需要先输出栈顶,再把左子树压入直到左儿子为空,删除栈顶,转向右儿子,继续下一次循环输出栈顶。。。
- 中序遍历:与前序遍历相似,先将左子树压入栈中,输出当前栈顶,删除栈顶,转向右子树,继续下一次循环压入左子树。。。
- 后序遍历:略微复杂,因为输出根节点时需要知道上次输出的节点是左子树还是右子树:
1、若为左子树,需要将右子树压入栈中才能访问当前跟节点。
2、若为右子树,可以直接输出根节点。
<mark>如图:</mark>
#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <algorithm>
using namespace std;
typedef long long ll;
#define maxn 1000005
#define mod 7654321
#define NIL -1
typedef struct Tree
{
int data;
Tree *lChild,*rChild;
}*TREE;
void creatTree(TREE &T)
{
int element;
cin>>element;
if(element == NIL)
T = NULL;
else
{
T = (TREE)malloc(sizeof(Tree));
T->data=element;
printf("输入%d的左子节点的值:",element);
creatTree(T->lChild);
printf("输入%d的右子节点的值:",element);
creatTree(T->rChild);
}
}
void preTraverse(TREE T)
{
if(T == NULL)
return;
TREE p=T;
stack<TREE> s;
while(!s.empty()||p)
{
while(p)
{
cout<<" "<<p->data;
s.push(p);
p = p->lChild;
}
if(!s.empty())
{
p=s.top();
s.pop();
p = p->rChild;
}
}
cout<<endl;
}
void inTraverse(TREE T)
{
if(T == NULL)
return;
TREE p=T;
stack<TREE> s;
while(!s.empty()||p)
{
//将左孩子压到空为止
while(p)
{
s.push(p);
p = p->lChild;
}
//输出左孩子的最后一个,再转向右孩子
if(!s.empty())
{
p=s.top();
s.pop();
cout<<" "<<p->data;
p = p->rChild;//转向右孩子
}
}
cout<<endl;
}
void postTraverse(TREE T)
{
if(T == NULL)
return;
stack<TREE> s;
//标记当前的和上一个访问节点
//pLast指向每次输出的节点的位置
TREE pCur,pLast;
//初始化
pCur = T;
pLast = NULL;
//先将左儿子都压入栈中
while(pCur)
{
s.push(pCur);
pCur = pCur->lChild;
}
while(!s.empty())
{
//pCur指向当前的栈顶节点
pCur = s.top();
s.pop();
//若当前节点没有右儿子或者右儿子是上一次访问输出的节点
if(pCur->rChild==NULL||pCur->rChild==pLast)
{
//输出根节点
cout<<" "<<pCur->data;
//修改上一次访问的节点为当前输出节点
pLast = pCur;
}
//若当前节点的左儿子刚刚访问过,则需要先进入右子树
//else if(pCur->lChild==pLast)//这种写法也可以
//或者说不能输出的话就需要将右子树压入栈中
else
{
//将开始取出的未处理的栈顶继续入栈
s.push(pCur);
//转向右子树
pCur = pCur->rChild;
while(pCur)
{
s.push(pCur);
//转向右子树继续先入栈左子树
pCur = pCur->lChild;
}
}
}
cout<<endl;
}
int main()
{
TREE T;
cout<<"输入根节点:";
creatTree(T);
preTraverse(T);
inTraverse(T);
postTraverse(T);
return 0;
}