二叉树遍历有递归,也有非递归。其实他们之前本质是一样的,非递归只是将递归的步骤一步步写出来,所以看了非递归代码之后回想递归代码也更好理解。

一.前序遍历

现在有一棵二叉树,如图(画的不是很好,好像有点歪)

二叉树遍历算法非递归 java 二叉树的遍历 非递归_c语言


如果是递归代码:就是输出,然后左递归,右递归就结束了。

其实递归就是栈的应用,在这里要引入栈。

假如根结点地址为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时,栈的情况

二叉树遍历算法非递归 java 二叉树的遍历 非递归_数据结构_02


1)

此时因为H没有左孩子,上面while(T)循环不成立。此时T == NULL。这样就应该去栈顶,并出栈。那么现在T指向的是K。

2)

因为现在T不为空,那么又进入上面的循环,输出并入栈,此时栈的情况:

二叉树遍历算法非递归 java 二叉树的遍历 非递归_二叉树_03


但是K的左孩子是没有的,所以退出上面的循环。

3)

这样的话又到了栈顶,取出的是K,然后去看看K是否有右孩子。

此时栈的情况

二叉树遍历算法非递归 java 二叉树的遍历 非递归_stack_04


4)

结果K没有右孩子,此时T为NULL。这样就只能进入外面大循环,栈不为空条件满足,又进入循环。但是T为空上面循环不能进,只能进判断栈是否为空,又取栈顶,然后出栈,此时栈的情况:

二叉树遍历算法非递归 java 二叉树的遍历 非递归_二叉树_05


正准备取出栈顶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,栈情况:

二叉树遍历算法非递归 java 二叉树的遍历 非递归_数据结构_02


1)

再接下来肯定是出栈,这样的话就是H出栈,但是不能输出H,因为还没遍历它的右孩子。所以只能再次入栈。栈一进一出和上面情况就一样了。

2)

现在T指向K这个叶子了,K不为空就入栈,然后遍历K的左右子树。

二叉树遍历算法非递归 java 二叉树的遍历 非递归_c语言_07


3)

当K左子树为空,进入下面判断时,因为count为1,所以再次入栈,遍历右孩子,但是还是为空。这样的话因为K的count为2,所以得输出K了。栈的情况:

二叉树遍历算法非递归 java 二叉树的遍历 非递归_二叉树遍历算法非递归 java_08


后面情况和之前也是类似。

注:输出之后一定要置空,不然的话,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;
 }