前言
二叉树的三种遍历的递归写法,只要理解思想,几行代码就可以完成。可是非递归写法却很不容易。这里特地总结下,透彻解析它们的非递归写法。其中,中序遍历的非递归写法最简单,后序遍历最难。
中序遍历的非递归写法
非递归算法,必然要用到栈(可参考完整代码中栈的实现)。这里着重讲下中序遍历的写法。
void InorderTraversal(BinTree BT)
{
BinTree T;
Stack TreeStack;
TreeStack = CreateStack();
T = BT;
while (T || !IsEmpty(TreeStack)){//注意循环结束的条件
while (T){ //将左子树一口气全部入栈
Push(TreeStack,T);
T = T->Left;
}
T = Pop(TreeStack); // 退出循环时,T为空,即再无左子树
printf("%d ", T->Data); //此时,打印该节点值
T = T->Right; //而后,转向右子树,若该节点为叶子节点,
//则T仍为空,下一次循环直接出栈,
//此处巧妙将叶子节点与常规节点的代码统一
}
}
后序遍历的非递归写法
后序遍历需要将父节点入栈两次,第二次出栈时才打印,因此需要做标记。代码在中序遍历基础上修改,理解了中序遍历,下面这段代码也不难理解。
void PostOrderTraversal(BinTree BT)
{
BinTree T;
Stack TreeStack;
TreeStack = CreateStack();
T = BT;
while (T || !IsEmpty(TreeStack)){
while (T){ //遍历左子树
Push(TreeStack,T);
T = T->Left;
}
T = Pop(TreeStack);
if (T->flag != 54321){ //54321魔术字,表示右子树已入栈
T->flag = 54321;
Push(TreeStack,T); //再次入栈,并遍历右子树
T = T->Right;
} else {
printf("%d ", T->Data);
T = NULL; //巧妙利用NULL在下一次循环时引向右子树
}
}
}
完整代码
/* 树的遍历 */
#include "stdio.h"
#include "stdbool.h"
#include <stdlib.h>
/* type define for Tree */
typedef struct TNode *Position;
typedef Position BinTree; /* 二叉树类型 */
struct TNode{ /* 树结点定义 */
int Data; /* 结点数据 */
BinTree Left; /* 指向左子树 */
BinTree Right; /* 指向右子树 */
int flag; /* 用于后序遍历,入栈标记 */
};
/* type define for stack */
typedef BinTree ElementType;
typedef struct SNode *PtrToSNode;
struct SNode {
ElementType Data;
PtrToSNode Next;
};
typedef PtrToSNode Stack;
Stack CreateStack( )
{ /* 构建一个堆栈的头结点,返回该结点指针 */
Stack S;
S = (Stack)malloc(sizeof(struct SNode));
S->Next = NULL;
return S;
}
bool IsEmpty ( Stack S )
{ /* 判断堆栈S是否为空,若是返回true;否则返回false */
return ( S->Next == NULL );
}
bool Push( Stack S, ElementType X )
{ /* 将元素X压入堆栈S */
PtrToSNode TmpCell;
TmpCell = (PtrToSNode)malloc(sizeof(struct SNode));
TmpCell->Data = X;
TmpCell->Next = S->Next;
S->Next = TmpCell;
return true;
}
ElementType Pop( Stack S )
{ /* 删除并返回堆栈S的栈顶元素 */
PtrToSNode FirstCell;
ElementType TopElem;
if( IsEmpty(S) ) {
printf("堆栈空");
return NULL;
}
else {
FirstCell = S->Next;
TopElem = FirstCell->Data;
S->Next = FirstCell->Next;
free(FirstCell);
return TopElem;
}
}
BinTree TreeCreat() //构建待验证的树
{
BinTree T,BT;
BT = (BinTree)malloc(sizeof(struct TNode));
/* A */
T = BT;
T->Data = 1;
T->Left = (BinTree)malloc(sizeof(struct TNode));
T->Right = (BinTree)malloc(sizeof(struct TNode));
/* B */
T = BT->Left;
T->Data = 2;
T->Left = (BinTree)malloc(sizeof(struct TNode));
T->Right = (BinTree)malloc(sizeof(struct TNode));
/* C */
T = BT->Right;
T->Data = 3;
T->Left = (BinTree)malloc(sizeof(struct TNode));
T->Right = (BinTree)malloc(sizeof(struct TNode));
/* D */
T = BT->Left->Left;
T->Data = 4;
T->Left = NULL;
T->Right = NULL;
/* E */
T = BT->Left->Right;
T->Data = 5;
T->Left = (BinTree)malloc(sizeof(struct TNode));
T->Right = NULL;
/* F */
T = BT->Right->Left;
T->Data = 6;
T->Left = NULL;
T->Right = (BinTree)malloc(sizeof(struct TNode));
/* G */
T = BT->Right->Right;
T->Data = 7;
T->Left = NULL;
T->Right = NULL;
/* H */
T = BT->Left->Right->Left;
T->Data = 8;
T->Left = NULL;
T->Right = NULL;
/* I */
T = BT->Right->Left->Right;
T->Data = 9;
T->Left = NULL;
T->Right = NULL;
return BT;
}
void InorderTraversal(BinTree BT)
{
BinTree T;
Stack TreeStack;
TreeStack = CreateStack();
T = BT;
while (T || !IsEmpty(TreeStack)){
while (T){
Push(TreeStack,T);
T = T->Left;
}
T = Pop(TreeStack);
printf("%d ", T->Data);
T = T->Right;
}
}
void PreOrderTraversal(BinTree BT)
{
BinTree T;
Stack TreeStack;
TreeStack = CreateStack();
T = BT;
while (T || !IsEmpty(TreeStack)){
while (T){
printf("%d ", T->Data);
Push(TreeStack,T);
T = T->Left;
}
T = Pop(TreeStack);
T = T->Right;
}
}
void PostOrderTraversal(BinTree BT)
{
BinTree T;
Stack TreeStack;
TreeStack = CreateStack();
T = BT;
while (T || !IsEmpty(TreeStack)){
while (T){ //遍历左子树
Push(TreeStack,T);
T = T->Left;
}
T = Pop(TreeStack);
if (T->flag != 54321){ //54321魔术字,表示右子树已入栈
T->flag = 54321;
Push(TreeStack,T); //再次入栈,并遍历右子树
T = T->Right;
} else {
printf("%d ", T->Data);
T = NULL; //巧妙利用NULL在下一次循环时引向右子树
}
}
}
void PreOrderTraversal_R(BinTree BT)
{
if(BT){
printf("%d ", BT->Data);
PreOrderTraversal(BT->Left);
PreOrderTraversal(BT->Right);
}
}
void InOrderTraversal_R(BinTree BT)
{
if(BT){
InOrderTraversal_R(BT->Left);
printf("%d ", BT->Data);
InOrderTraversal_R(BT->Right);
}
}
void PostOrderTraversal_R(BinTree BT)
{
if(BT){
PostOrderTraversal_R(BT->Left);
PostOrderTraversal_R(BT->Right);
printf("%d ", BT->Data);
}
}
int main()
{
BinTree BT = TreeCreat();
printf("PostOrderTraversal_R:");
PostOrderTraversal_R(BT);
printf("\r\n");
printf("PostOrderTraversal_L:");
PostOrderTraversal(BT);
printf("\r\n");
return 0;
}
代码中构造的树的结构
来源:CSDN
作者:NjustMEMS_ZJ
链接:https://blog.csdn.net/u013098336/article/details/104150559