二叉樹的遍歷可以分爲遞歸遍歷、非遞歸遍歷和層序遍歷。其本質是如何把二維結構變成一維線性結構的過程。
遞歸遍歷
在遞歸遍歷中又可以分爲三種:先序遍歷、中序遍歷和後序遍歷。
先序遍歷
先序遍歷的遍歷過程爲:
- 訪問根節點;
- 先序遍歷其左子樹;
- 先序遍歷其右子樹。
void PreOrderTraversal ( BinTree BT )
{
if(BT){ // 判斷節點是否爲空
printf ("%d'”,BT->Data) ;
PreOrderTraversal ( BT->Left ) ;
PreOrderTraversal ( BT->Right );
}
}
對於下圖中的樹,其先序遍歷結果爲:A B D F E C G H I。
中序遍歷
中序遍歷的遍歷過程爲:
- 中序遍歷其左子樹;
- 訪問根結點;
- 中序遍歷其右子樹。
void PreOrderTraversal ( BinTree BT )
{
if(BT){ // 判斷節點是否爲空
PreOrderTraversal ( BT->Left ) ;
printf ("%d'”,BT->Data) ;
PreOrderTraversal ( BT->Right );
}
}
對於下圖中的樹,其先序遍歷結果爲:D B E F A G H C I。
後序遍歷
後序遍歷的遍歷過程爲:
- 後序遍歷其左子樹;
- 後序遍歷其右子樹;
- 訪問根結點。.
void PreOrderTraversal ( BinTree BT )
{
if(BT){ // 判斷節點是否爲空
PreOrderTraversal ( BT-> Left ) ;
PreOrderTraversal ( BT-> Right );
printf ("%d'”,BT->Data) ;
}
}
對於下圖中的樹,其先序遍歷結果爲:D E F B H G I C A。
先序、中序和後序遍歷過程:遍歷過程中經過結點的路線一樣,只是訪問各結點的時機不同。
下圖中在從入口到出口的曲線上用×號
、星號
和三角
三種符號分別標記出了先序、中序和後序訪問各結點的時刻:
非遞歸遍歷
上述方法是使用遞歸的算法對其進行求解,我們知道遞歸的方法算法空間複雜度較高,如果採用非遞歸的方法,我們可以使用堆棧的方法。
中序遍歷非遞歸遍歷算法
中序遍歷非遞歸遍歷算法主要可以分爲以下三步:
- 遇到一個結點,就把它壓棧,並去遍歷它的左子樹;
- 當左子樹遍歷結束後,從棧頂彈出這個結點並訪問它;
- 然後按其右指針再去中序遍歷該結點的右子樹。
其程序如下:
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
T = Pop(s); /*結點彈出堆棧*/
printf ("%5d", T->Data); /* (訪問)打印結點*/
T = T->Right; /*轉向右子樹*/
}
}
}
若想要把其改爲先序遍歷的非遞歸算法,只需把printf
語句放到while(T)
下面這一行:
void InOrderTraversal ( 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
T = Pop(s); /*結點彈出堆棧*/
T = T->Right; /*轉向右子樹*/
}
}
}
層序遍歷
二叉樹遍歷的核心問題就是:二維結構的線性化。其實我們只需要一個存儲結構來保存暫時不訪問的結點就可以了,因此除了堆棧,我們還可以用隊列的方式對其進行存儲。
隊列實現:遍歷從根結點開始,首先將根結點入隊,然後開始執行循環:結點出隊、訪問該結點、其左右兒子入隊。
層序遍歷基本過程:先根結點入隊,然後:
- 從隊列中取出一個元素;
- 訪問該元素所指結點;
- 若該元素所指結點的左、右孩子結點非空,則將其左、右孩子的指針順序入隊。
void Leve lOrderTraversal ( BinTree BT )
{ Queue Q ; BinTree T ;
if ( !BT ) return; /* 若是空樹則直接返回*/
Q =CreatQueue( Maxsize ); /*創建並初始化隊列0*/
AddQ(Q,BT);
while(!IsEmptyQ(Q)){
T=DeleteQ(Q);
printf ("&d\n", T->Data) ; /*訪 問取出隊列的結點*/
if ( T->Left ) AddQ( Q,T->Left ) ;
if ( T->Right ) AddQ( Q,T->Right ) ;
}
}
應用
- 輸出二叉樹中的葉子結點
遍歷二叉樹的應用:輸出二叉樹中的葉子結點。在二叉樹的遍歷算法中增加檢測結點的“左右子樹是否都爲空”。
void PreOrderPrintLeaves( BinTree BT )
{
if(BT) {
if ( !BT-Left && !BT- >Right )
printf ("8d",BT- >Data ) ;
PreOrderPrintLeaves ( BT- >Left ) ;
PreOrderPrintLeaves ( BT- >Right ) ;
}
}
- 求二叉樹的高度:
int PostorderGetHeight( BinTree BT )
{ int HL, HR,MaxH;
if(BT){
Hi = PostorderGetHeight (BT->Ieft) ; /*求左子樹的深度*/
HR = PostorderGetHeight (BT->Right) ; /*求右子樹的深度*/
MaxH = (HI > HR) ? HL : HR; /*取左右子樹較大的深度*/
return ( MaxH + 1 ); /*返回樹的深度*/
}
else return 0; /*空樹深度爲0 */
}
如果想要由兩種遍歷序列確定二叉樹,必須要有中序遍歷才行。