1. 程式人生 > >二叉樹先序遍歷、中序遍歷、後序遍歷的遞迴演算法與非遞迴演算法

二叉樹先序遍歷、中序遍歷、後序遍歷的遞迴演算法與非遞迴演算法

首先是二叉樹資料結構的定義:

typedef struct TNode *Position;
typedef Position BinTree; /* 二叉樹型別 */
struct TNode{ /* 樹結點定義 */
    int Data; /* 結點資料 */
    BinTree Left;     /* 指向左子樹 */
    BinTree Right;    /* 指向右子樹 */
};

 遞迴演算法

/*****************遞迴演算法******************/ 
/*****先序遍歷*****/ 
void PreOrderTraversal(BinTree BT)
{
	if( BT ){
		printf("%d ",BT->Data);       //先訪問根節點 
		PreOrderTraversal(BT->Left);  //再訪問左子樹 
		PreOrderTraversal(BT->Right); //最後訪問右子樹 
	}
}

/*****中序遍歷*****/ 
void InOrderTraversal(BinTree BT)
{
	if( BT ){
		InOrderTraversal(BT->Left);
		printf("%d ",BT->Data);
		InOrderTraversal(BT->Right);
	}
}

/*****後序遍歷*****/ 
void PostOrderTraversal(BinTree BT)
{
	if( BT ){
		PostOrderTraversal(BT->Left);
		PostOrderTraversal(BT->Right);
		printf("%d ",BT->Data);
	}
}

非遞迴演算法


/*****************非遞迴演算法******************/ 
/*****先序遍歷*****/ 
void PreOrderTraversal_(BinTree BT)
{
	BinTree T = BT;
	Stack S = CreatStack(MaxSize); /*建立並初始化堆疊S*/ 
	while( T || !IsEmpty(S) ){
		while( T ){  /*一直向左並將沿途結點壓入堆疊,直到左兒子不存在*/ 
			printf("%5d ",T->Data);  /*訪問(列印)結點*/
			Push(S,T);
			T = T->Left; 
		}
		
		if( !IsEmpty(S) ){
			T = Pop(S);   /*結點彈出堆疊*/ 
			T = T->Right;  /*轉向右子樹*/ 
		}
	}
 } 
 
/*****中序遍歷*****/ 
void InOrderTraversal_(BinTree BT)
{
	BinTree T = BT;
	Stack S = CreatStack(MaxSize); /*建立並初始化堆疊S*/ 
	while( T || !IsEmpty(S) ){
		while( T ){  /*一直向左並將沿途結點壓入堆疊,直到左兒子不存在*/ 
			Push(S,T);
			T = T->Left; 
		}
		
		if( !IsEmpty(S) ){
			T = Pop(S);   /*結點彈出堆疊*/
			printf("%5d ",T->Data);  /*訪問(列印)結點*/ 
			T = T->Right;  /*轉向右子樹*/ 
		}
	}
}

/*****後序遍歷*****/ 
/*1
給數的結點增加一個訪問次數(visit)屬性
遍歷左子樹,依次入棧
到底後出棧一個元素,判斷訪問次數是否為2
若不是,則訪問次數為1,訪問次數+1,再次入棧,T指向右子樹(訪問右子樹),進入下次迴圈
若是,則輸出,T指向空(左右子樹都訪問了),進入下次迴圈
*/
 void PostOrderTraversal_1(BinTree BT)
{
    BinTree T,BT;
    Stack S = CreatStack(Maxsize);
    while( T || !IsEmpty(s)) {
        while(T){
            T->visit++;//visit初值為0
            Push(S,T);
            T = T->Left;
        }
        
        if( !isEmpty(S) ){
            T = Pop(S);//出棧判斷
            if(T->visit==2){
                printf("%5d",T->data);
                T = NULL;
            }
            else{
                T->visit++;
                Push(S,T);//訪問次數不等於2,二次入棧
                T = T->Right;
            }
        }
    }
}

/*2
先序的訪問順序是root, left, right 假設將先序左右對調,
則順序變成root, right, left,暫定稱之為“反序”。
後序遍歷的訪問順序為left, right,root ,
剛好是“反序”結果的逆向輸出.
*/
void PostOrderTraversal_2( BinTree BT )
{
   BinTree T,BT;
   Stack S = CreatStack( MaxSize ); /*建立並初始化堆疊S*/
   Stack Q = CreatStack( MaxSize ); /*建立並初始化堆疊Q,用於輸出反向*/
   while( T || !IsEmpty(S) ){
       while(T){ /*一直向右並將沿途結點壓入堆疊*/
           Push(S,T);
           Push(Q,T);/*將先序遍歷到的結點壓棧,用於反向*/
           T = T->Right; /*轉向右子樹*/
       }
       
       if(!IsEmpty(S)){
       T = Pop(S); 
       T = T->Left; /*轉向左子樹*/
       }
   }
    
   while( !IsEmpty(Q) ){
       T = Pop(Q);
       printf("%5d ", T->Data); 
   }
}

/*3
後序遍歷是先訪問左,再訪問右,最後訪問根
當且僅當右子樹為空或者右子樹被訪問過後,
才會訪問根節點,因此使用輔助指標r來記錄最近訪問過的節點
*/
void PostOrderTraversal_3(BinTree BT){
    BinTree T = BT;
    BinTree r = NULL; 
    Stack S = CreatStack(MaxSize);
    while( T || !isEmpty(S) ){
        if( T ){          //遍歷到最左邊 
            Push(S, T);
            T = T->left;
        }
        else{
            GetTop(S,T);  //讀取棧頂節點
            if(T->right && T->right != r)
                T = T->right;
            else{
                T = Pop(S);
                printf("%5d ", T->data);
                r = T;      //記錄最近訪問的節點 
                T = NULL;   //節點訪問完後重置T指標 
            }
        }
    }
}