对于一个二叉树,我们来精确模拟他的递归遍历过程
后序递归遍历的代码如下:
void posttravel(BinTree t){
if(!t){
posttravel(t->left);
posttravel(t->right);
printf("%c "t->data);
}
}
我们知道,递归遍历要借助堆栈,并且前序、中序、后序遍历经过节点的次序是一样的,不同的是在不同的时刻访问他们(即打印出来),对于下面的一颗二叉树,我们按照上面的递归代码走一遍
首先,先将A入栈(A并没有执行完,需要先保存起来),
栈中是这样:
A |
执行posttravel(t->left),
A | B
执行posttravel(t->left),
A | B | D
执行posttravel(t->left)
A | B | D | NULL;
由于此时的t = NULL. 所以退出posttravel(t->left), 退到上一层,D的左子树执行完了
D先出栈再进栈, t = D,执行posttravel(t->right)
A | B | D | F
由于F的左右子树都空,就不详述了,D最后出栈,返回上一层, t = D,此时D的左右子树都已经执行完了,D出栈
从D我们可以看到,每个元素都是两次进栈,两次入栈的。第一次遇到D,D第一次入栈,遍历完他的左子树后,D第一次出栈,要遍历他的右子树前,D第二次入栈,遍历完他的右子树后,D第二次出栈
一下的过程相同,有兴趣可以自己走一遍。
下面我们就根据这个过程用非递归方式精确模拟遍历二叉树的过程,注意,这里的遍历单单指遍历二叉树的每个节点,并不是要访问(打印)它,我们要知道,无论哪种遍历方式,走过的路线是一样的,只是打印的时间不同而已.
enum State{
start, return_from_left, return_from_right
// 访问左子树、右子树前都要经过根节点,我们以这两次“经过”为标准,将根节点划分为访问了自己,访问完左子树,访问完
// 右子树,即过程是:第一次经过自己->访问左子树->第二次经过自己->访问右子树-第三次经过自己(返回上层)
};
typedef struct StackElem{
enum State state; // 节点状态
BinTree t; // 节点
}StackElem;
void postorder(BinTree t){
// if(!t) return;
StackElem item = {start, t}; // 根节点
stack s = createstack(MAX); // 遍历要借助堆栈实现
while(1){ // 退出条件是所有节点都遍历完(每个节点两进两出)
if(item.t){
if(item.state == start){ // 遍历左子树
push(s, item);
item.t = item.t->left;
item.state = start;
}else if(item.state == return_from_left){ // 遍历右子树
push(s, item);
item.t = item.t->right;
item.state = start;
}else{
// 返回上一层
// 左(右)子树遍历完后返回他的根节点(上一层)
if(!isempty(s)){
item = pop(s);
item.state++;
}else{
break;
}
}
}else{
// 当前为空的话,也要返回上一层
if(!isempty(s)){
item = pop(s);
item.state++;
}else{
break;
}
}
}
return;
}
下面是一个后序遍历的具体实现:
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define ElementType char
#define MAX 50
enum State{
start, return_from_left, return_from_right
// 访问左子树、右子树前都要经过根节点,我们以这两次“经过”为标准,将根节点划分为访问了自己,访问完左子树,访问完
// 右子树,即过程是:第一次经过自己->访问左子树->第二次经过自己->访问右子树-第三次经过自己(返回上层)
};
typedef struct TNode *BinTree;
struct TNode{
ElementType data;
struct TNode *left;
struct TNode *right;
};
typedef struct StackElem{
enum State state;
BinTree t;
}StackElem;
typedef struct Stack{
StackElem *data;
int MAXSIZE;
int top;
} *stack;
/*******************************/
BinTree createtree(BinTree t, bool isroot);
stack createstack(int max);
void push(stack s, StackElem se);
StackElem pop(stack s);
int isempty(stack s);
void postorder(BinTree t);
BinTree createtree(BinTree t, bool isroot);
void freetree(BinTree t);
/********************************/
int main(){
BinTree t;
t = createtree(t, true);
postorder(t);
freetree(t);
return 0;
}
// 创建空栈
stack createstack(int max){
stack s = (stack)malloc(sizeof(struct Stack));
s->data = (StackElem *)malloc(sizeof(StackElem) *max);
s->MAXSIZE = max;
s->top = -1;
return s;
}
// 进栈
void push(stack s, StackElem se){
if(s->top+1 == s->MAXSIZE)
return;
s->data[++(s->top)] = se;
}
// 出栈
StackElem pop(stack s){
StackElem tmp = s->data[s->top];
--s->top;
return tmp;
}
// 判空
int isempty(stack s){
return s->top == -1;
}
// 后序遍历
void postorder(BinTree t){
// if(!t) return;
StackElem item = {start, t};
stack s = createstack(MAX);
while(1){
if(item.t){
if(item.state == start){ // 遍历左子树
push(s, item);
item.t = item.t->left;
item.state = start;
}else if(item.state == return_from_left){ // 遍历右子树
push(s, item);
item.t = item.t->right;
item.state = start;
}else{
// 返回上一层
printf("%c ", item.t->data);
if(!isempty(s)){
item = pop(s);
item.state++;
}else{
break;
}
}
}else{
if(!isempty(s)){
item = pop(s);
item.state++;
}else{
break;
}
}
}
return;
}
// 建立二叉树
BinTree createtree(BinTree t, bool isroot){
ElementType data;
if(isroot){
printf("root is:");
}
fflush(stdin);
scanf("%c", &data);
fflush(stdin);
if(data != '#'){
isroot = false;
t = (BinTree )malloc(sizeof(struct TNode));
t->data = data;
t->left = NULL; t->right = NULL;
printf("%c s left child is : ", t->data);
t->left = createtree(t->left, isroot);
printf("%c s right child is : ", t->data);
t->right = createtree(t->right, isroot);
}
return t;
}
// 释放二叉树
void freetree(BinTree t){
if(!t){
freetree(t->left);
freetree(t->right);
free(t);
}
return;
}