二叉樹利用堆疊實現遍歷的非遞迴演算法
阿新 • • 發佈:2019-02-04
二叉樹的遍歷有三種不同的遍歷方法,分別是前序遍歷、中序遍歷以及後序遍歷
遍歷的實現我們在上一篇部落格中已經用遞迴的方法實現了,那麼可不可以不用遞迴實現呢,答案是可以的
在這一篇部落格中我們會利用堆疊將遍歷改為非遞迴
下面先附上實現的程式碼
其中棧的後序非遞迴遍歷參考了一篇網上的部落格,用了兩種方法實現了後序遍歷#include "stdio.h" #include "stdlib.h" typedef struct tree { char data; struct tree *lchild; struct tree *rchild; }*Ptree; typedef Ptree ElementType; typedef struct SNode *Stack; struct SNode{ ElementType Data; struct SNode *Next; }; Stack CreateStack(); //判斷是否空 int IsEmpty(Stack S); //Push操作 void Push(ElementType item,Stack S); //Pop操作 ElementType Pop(Stack S); //樹的建立 Ptree createTree() ; //先序遍歷 void preOrder(Ptree t); //中序遍歷 void intOrder(Ptree t); //後序遍歷 void postOrder(Ptree t); //利用棧先序遍歷二叉樹 void PreOderTraversal(Ptree BT); //利用棧中序遍歷二叉樹 void InOderTraversal(Ptree BT); //利用棧後序遍歷 void PostOderTraversal(Ptree BT); //利用雙棧法後序遍歷 void PostOderTraversal2(Ptree BT); void main() { Ptree t; printf("先序建立二叉樹,用空格代表虛結點:\n"); t=createTree(); printf("前序遍歷:"); preOrder(t) ; printf("\n"); printf("利用堆疊前序遍歷:"); PreOderTraversal(t); printf("\n"); printf("\n"); printf("中序遍歷:"); intOrder(t) ; printf("\n"); printf("利用堆疊中序遍歷:"); InOderTraversal(t); printf("\n"); printf("\n"); printf("後序遍歷:"); postOrder(t) ; printf("\n"); printf("利用堆疊後序遍歷:"); PostOderTraversal(t); printf("\n"); printf("利用雙棧法後序遍歷:"); PostOderTraversal2(t); system("pause"); } //堆疊的建立 Stack CreateStack(){ Stack S; S=(Stack)malloc(sizeof(struct SNode)); S->Next=NULL; return S; } //判斷是否空 int IsEmpty(Stack S){ return(S->Next==NULL); } //Push操作 void Push(ElementType item,Stack S){ struct SNode *TmpCell; TmpCell=(struct SNode *)malloc(sizeof(struct SNode)); TmpCell->Data=item; TmpCell->Next=S->Next; S->Next=TmpCell; } //Pop操作 ElementType Pop(Stack S){ struct SNode *FirstCell; ElementType TopElem; if(IsEmpty(S)){ printf("堆疊空\n"); return NULL; }else{ FirstCell=S->Next; S->Next=FirstCell->Next; TopElem=FirstCell->Data; free(FirstCell); return TopElem; } } Ptree createTree() //樹的建立 { char ch; Ptree t; ch=getchar(); //輸入二叉樹資料 if(ch==' ') //判斷二叉樹是否為空 t=NULL; else { t=(Ptree)malloc(sizeof(Ptree)); //二叉樹的生成 t->data=ch; t->lchild=createTree(); t->rchild=createTree(); } return t; } void preOrder(Ptree t) //先序遍歷 { if(t) { printf("%c",t->data); preOrder(t->lchild); preOrder(t->rchild); } } void intOrder(Ptree t) //中序遍歷 { if(t) { intOrder(t->lchild); printf("%c",t->data); intOrder(t->rchild); } } void postOrder(Ptree t) //後序遍歷 { if(t) { postOrder(t->lchild); postOrder(t->rchild); printf("%c",t->data); } } //利用棧先序遍歷 void PreOderTraversal(Ptree BT){ Ptree T=BT; Stack S=CreateStack(); while(T||!IsEmpty(S)){ while(T){ printf("%c",T->data); Push(T,S); T=T->lchild; } T=Pop(S); T=T->rchild; } }; //利用棧中序遍歷 void InOderTraversal(Ptree BT){ Ptree T=BT; Stack S=CreateStack(); while(T||!IsEmpty(S)){ while(T){ Push(T,S); T=T->lchild; } T=Pop(S); printf("%c",T->data); T=T->rchild; } }; //利用棧後序遍歷 void PostOderTraversal(Ptree BT){ Ptree T=BT; Ptree TempT=NULL;//Temp記錄被檢查的節點的右兒子 Stack S=CreateStack(); while(T||!IsEmpty(S)){ while(T){ Push(T,S); T=T->lchild; } T=Pop(S);Push(T,S);//相當於返回了棧頂元素 // 當前節點的右孩子如果為空或者已經被訪問,則訪問當前節點 if(T->rchild==NULL||T->rchild==TempT){ printf("%c",T->data); TempT=T; Pop(S); T=NULL; } // 否則訪問右孩子 else T=T->rchild; } }; //利用雙棧法後序遍歷 void PostOderTraversal2(Ptree BT) // 後序遍歷的非遞迴 雙棧法 { Ptree T=BT; // 指向當前要檢查的節點 Stack S1=CreateStack(); Stack S2=CreateStack(); Push(T,S1); while(!IsEmpty(S1)) // 棧空時結束 { T = Pop(S1); Push(T,S2); if(T->lchild) Push(T->lchild,S1); if(T->rchild) Push(T->rchild,S1); } while(!IsEmpty(S2)) { printf("%c", Pop(S2)->data); } }
下面是一個具體實現的例子
樹是這樣的,如下
A
B C
D F G I
E H
前序輸入的時候是
ABD##FE###CG#H##I##
執行的結果如下
我只有一個感受。。好厲害。。。