前言
二叉樹的三種遍歷的遞歸寫法,只要理解思想,幾行代碼就可以完成。可是非遞歸寫法卻很不容易。這裏特地總結下,透徹解析它們的非遞歸寫法。其中,中序遍歷的非遞歸寫法最簡單,後序遍歷最難。
中序遍歷的非遞歸寫法
非遞歸算法,必然要用到棧(可參考完整代碼中棧的實現)。這裏着重講下中序遍歷的寫法。
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;
}
代碼中構造的樹的結構