二叉樹遍歷的遞歸與非遞歸寫法_C語言

前言

二叉樹的三種遍歷的遞歸寫法,只要理解思想,幾行代碼就可以完成。可是非遞歸寫法卻很不容易。這裏特地總結下,透徹解析它們的非遞歸寫法。其中,中序遍歷的非遞歸寫法最簡單,後序遍歷最難。

中序遍歷的非遞歸寫法

非遞歸算法,必然要用到棧(可參考完整代碼中棧的實現)。這裏着重講下中序遍歷的寫法。

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;
}

代碼中構造的樹的結構
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章