二叉树遍历有递归,也有非递归。其实他们之前本质是一样的,非递归只是将递归的步骤一步步写出来,所以看了非递归代码之后回想递归代码也更好理解。
一.前序遍历
现在有一棵二叉树,如图(画的不是很好,好像有点歪)
如果是递归代码:就是输出,然后左递归,右递归就结束了。
其实递归就是栈的应用,在这里要引入栈。
假如根结点地址为T,思路就是遍历左孩子入栈,并输出。当左孩子输出完,取栈顶,找右孩子。再遍历右孩子的左孩子右孩子,然后结束。
现在有两个判断条件,一个是往下遍历的指针不为空,一个是栈不为空。只要有一个条件成立,就还在遍历。先上代码:
Status PreOrderTraverse_Recursion(BiTree T,Stack *s)
{
while(T || s->top)
{
while(T)
{
printf("%5d",T->data);
Push(s,T);
T = T->lchild;
}
if(s->top)
{
T = Poll(s,T);
T = T->rchild;
}
}
}
遍历左孩子的条件就是T不为空。先输出,然后入栈,再到他的左孩子。当到H时,栈的情况
1)
此时因为H没有左孩子,上面while(T)循环不成立。此时T == NULL。这样就应该去栈顶,并出栈。那么现在T指向的是K。
2)
因为现在T不为空,那么又进入上面的循环,输出并入栈,此时栈的情况:
但是K的左孩子是没有的,所以退出上面的循环。
3)
这样的话又到了栈顶,取出的是K,然后去看看K是否有右孩子。
此时栈的情况
4)
结果K没有右孩子,此时T为NULL。这样就只能进入外面大循环,栈不为空条件满足,又进入循环。但是T为空上面循环不能进,只能进判断栈是否为空,又取栈顶,然后出栈,此时栈的情况:
正准备取出栈顶D,然后去看看D是否有右孩子。再继续的话就和之前的步骤是一样的。
二.中序遍历
中序遍历和前序差不多,只是输出的位置不一样。先把所有左孩子入栈,都入栈之后,取栈顶然后输出,然后遍历右孩子。
代码:
Status InOrderTraverse_Recursion(BiTree T,Stack *s)
{
while(T || s->top)
{
while(T)
{
Push(s,T);
T =T->lchild;
}
if(s->top)
{
T = Poll(s,T);
printf("%5d",T->data);
T = T->rchild;
}
}
}
三.后序遍历
后序遍历和前面有些不同。因为前面两个遍历,根结点都在右之前输出,所以根结点输出之后就没事。
但是后序遍历还要先去遍历右孩子,才能回到根结点,相当于两次,所以根结点有两次入栈的情况。
先上代码:
Status PostOrderTraverse_Recursion(BiTree T,Stack *s)
{
while(T || s->top)
{
while(T)
{
T->count = 1;
Push(s,T);
T = T->lchild;
}
if(s->top)
{
T = Poll(s,T);
if(T->count == 1)
{
T->count = 2;
Push(s,T);
T = T->rchild;
}
else if(T->count == 2)
{
printf("%5d",T->data);
T = NULL;
}
}
}
}
刚开始情况和上面都一样,都是遍历左孩子,就是每次入栈时候,次数都为1,栈情况:
1)
再接下来肯定是出栈,这样的话就是H出栈,但是不能输出H,因为还没遍历它的右孩子。所以只能再次入栈。栈一进一出和上面情况就一样了。
2)
现在T指向K这个叶子了,K不为空就入栈,然后遍历K的左右子树。
3)
当K左子树为空,进入下面判断时,因为count为1,所以再次入栈,遍历右孩子,但是还是为空。这样的话因为K的count为2,所以得输出K了。栈的情况:
后面情况和之前也是类似。
注:输出之后一定要置空,不然的话,K输出以后不置为NULL。又会进入while(T)循环里面,那就是死循环了。
总的代码:
#include<stdio.h>
#include<stdlib.h>
int OVERFLOW = -1;
#define MAXSIZE 50
typedef int Status;
typedef int BElemtype;
typedef int SElemtype;
typedef struct BTree{
BElemtype data;
struct BTree *lchild,*rchild;
int count;
}BTree,*BiTree;
typedef struct{
BiTree data[MAXSIZE];
int top;
}Stack;
Status InitTree(BiTree *BT)
{
BElemtype num;
scanf("%d",&num);
if(num == 0)
*BT = NULL;
else{
*BT = (BiTree)malloc(sizeof(BTree));
(*BT)->data = num;
InitTree(&(*BT)->lchild);
InitTree(&(*BT)->rchild);
}
}
Status Push(Stack *s,BiTree t)
{
s->data[s->top++] = t;
}
BiTree Poll(Stack *s,BiTree t)
{
return s->data[--s->top];
}
Status PreOrderTraverse_Recursion(BiTree T,Stack *s)
{
while(T || s->top)
{
while(T)
{
printf("%5d",T->data);
Push(s,T);
T = T->lchild;
}
if(s->top)
{
T = Poll(s,T);
T = T->rchild;
}
}
}
Status InOrderTraverse_Recursion(BiTree T,Stack *s)
{
while(T || s->top)
{
while(T)
{
Push(s,T);
T =T->lchild;
}
if(s->top)
{
T = Poll(s,T);
printf("%5d",T->data);
T = T->rchild;
}
}
printf("\n");
}
Status PostOrderTraverse_Recursion(BiTree T,Stack *s)
{
while(T || s->top)
{
while(T)
{
T->count = 1;
Push(s,T);
T = T->lchild;
}
if(s->top)
{
T = Poll(s,T);
if(T->count == 1)
{
T->count = 2;
Push(s,T);
T = T->rchild;
}
else if(T->count == 2)
{
printf("%5d",T->data);
T = NULL;
}
}
}
}
int main(void)
{
BiTree T;
Stack s;
s.top = 0;
InitTree(&T);
PostOrderTraverse_Recursion(T,&s);
return 0;
}