1. 程式人生 > >二叉樹利用堆疊實現遍歷的非遞迴演算法

二叉樹利用堆疊實現遍歷的非遞迴演算法

二叉樹的遍歷有三種不同的遍歷方法,分別是前序遍歷、中序遍歷以及後序遍歷

遍歷的實現我們在上一篇部落格中已經用遞迴的方法實現了,那麼可不可以不用遞迴實現呢,答案是可以的

在這一篇部落格中我們會利用堆疊將遍歷改為非遞迴 

下面先附上實現的程式碼

#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##

執行的結果如下


我只有一個感受。。好厲害。。。