1. 程式人生 > >二叉樹3種遍歷演算法遞迴與非遞迴實現詳解

二叉樹3種遍歷演算法遞迴與非遞迴實現詳解

一, 二叉樹先序遍歷的實現

  1.     遞迴實現
void PreOrderTraverse(BiTree T)
{


    if( T )
    {
        VisitF(T->data);//訪問根節點
        PreOrderTraverse(T->lchild);//遞迴左子樹
        PreOrderTraverse(T->rchild);//遞迴右子樹
    }
}

    2.   非遞迴實現

思路: 

  1. 判斷棧是否為空或子樹為空
  2. 若不為空,就訪問左孩子並將其入棧,直至左孩子為空
  3. 若左孩子為空,就出棧,然後訪問右孩子,入棧,就這樣不斷的迴圈。
void PreOrderTraverse_Nonrecursion(BiTree T)
{
    LiStack  S ;
    BiTree  p ;
    S = NULL ;
    p = T ;

    InitStack(S) ;

    if(NULL == p)
    {
        printf("樹為空!\n") ;
        return ;
    }

    while(p || !StackEmpty(S))
    {
        if(p)
        {
            Push(S, p) ;
            VisitF(p->data);
            p = p->lchild ;
        }
        else
        {
            Pop(S, p) ;
            p = p->rchild ;
        }
    }

    free(S) ;
}

二,  二叉樹中序遍歷的實現

  1.     遞迴實現
/*
    中序遍歷二叉樹
*/
void InOrderTraverse(BiTree T)
{

    if( T )
    {
        InOrderTraverse(T->lchild);
        VisitF(T->data);
        InOrderTraverse(T->rchild);
    }
}

      2.    非遞迴實現

思路:思路基本和先序差不多,只是輸出資料的時候不一樣

  1. 判斷棧和樹是否為空,

  2. 若不,則判斷樹是否為空,

  3. 不為繼續將左子樹進棧,若為空,則出棧,輸出資料,然後訪問右子樹。

void InOrderTraverse_Nonrecursion(BiTree T)
{
    LiStack  S ;
    BiTree  p ;
    S = NULL ;
    p = T ;

    InitStack(S) ;

    if(NULL == p)
    {
        printf("樹為空!\n") ;
        return ;
    }

    while(p || !StackEmpty(S))
    {
        if(p)
        {
            Push(S, p) ;

            p = p->lchild ;
        }
        else
        {
            Pop(S, p) ;
            VisitF(p->data);
            p = p->rchild ;
        }
    }

    free(S) ;
}

三,  二叉樹中序遍歷的實現

  1.  遞迴實現
/*
    後續遍歷二叉樹
*/
void PostOrderTraverse(BiTree T)
{

    if( T )
    {
        PostOrderTraverse(T->lchild);
        PostOrderTraverse(T->rchild);
        VisitF(T->data);
    }
}

 2. 非遞迴實現

思路 :實現有多多種方法,有兩個棧,或加標誌位實現,但是我覺得如下實現最容易懂

       要保證根結點在左孩子和右孩子訪問之後才能訪問,因此對於任一結點P,先將其入棧。如果P不存在左孩子和右孩子,則可以直接訪問它;或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被訪問過了,則同樣可以直接訪問該結點。若非上述兩種情況,則將P的右孩子和左孩子依次入棧,這樣就保證了每次取棧頂元素的時候,左孩子在右孩子前面被訪問,左孩子和右孩子都在根結點前面被訪問。

void PostOrderTraverse_Nonrecursion(BiTree T)
{
    LiStack  S ;
    BiTree  cur, pre ;
    S = NULL ;
    InitStack(S) ;
    if(NULL == T)
    {
        printf("樹為空!\n") ;
        return ;
    }

    pre = NULL ;
    cur = NULL ;
    Push(S,T) ;
    while(!StackEmpty(S))
    {
        cur = NULL ;
        GetTop(S,cur) ;
        if((cur->lchild == NULL && cur->rchild == NULL) || (pre != NULL && (pre == cur->lchild ||pre == cur->rchild)))
        {
            VisitF(cur->data);
            pre = cur ;
            Pop(S,cur) ;
        }
        else
        {
            if(cur->rchild != NULL)
            {
                Push(S,cur->rchild) ;
            }
            if(cur->lchild != NULL)
            {
                Push(S,cur->lchild) ;
            }
        }
    }
    free(S) ;
}

如下是完整程式碼:

#include<stdio.h>
#include<stdlib.h>

#define OK 1
#define ERROR -1

typedef char TElemType;

typedef int Status;

typedef struct BiTNode
{

    TElemType data;
    struct BiTNode *lchild,*rchild;

} BiTNode,*BiTree;


typedef BiTNode * StackElemType;

typedef struct LinkNode    //棧的節點
{
    StackElemType data ;
    LinkNode * next ;
} LinkNode,*LiStack;

typedef BiTNode * QueueElemType ;     //定義佇列包含的資料型別

typedef struct QNode     //定義佇列節點
{
    QueueElemType  data ;
    struct QNode * next ;
} QNode,*QueuePtr;

typedef struct
{
    QueuePtr fronts;
    QueuePtr rears;
} LinkQueue;



Status creatBiTree(BiTree &T);

void Visit(char ch,int level);

void PreOrderTraverse(BiTree T,int level);

void InOrderTraverse(BiTree T,int level);

void PostOrderTraverse(BiTree T,int level);

Status  InitStack(LiStack &S);

void Push(LiStack &S, StackElemType data);

void Pop(LiStack & S, StackElemType &data);

int StackEmpty(LiStack  &S);

int GetTop(LiStack &S, StackElemType & data);

Status InitQueue(LinkQueue &Q);

Status EnQueue(LinkQueue &Q, QueueElemType data);

Status DeQueue(LinkQueue &Q, QueueElemType & data);

int QueueEmpty(LinkQueue Q);

void PreOrderTraverse_Nonrecursion(BiTree T);

void InOrderTraverse_Nonrecursion(BiTree T);

void PostOrderTraverse_Nonrecursion(BiTree T);



/*********************************************************************/
/*****************************棧的方法********************************/
//棧的函式定義
Status  InitStack(LiStack &S)
{
    S = (LinkNode *)malloc(sizeof(LinkNode)) ;
    if(NULL == S)
    {
        printf("記憶體不足,不能分配棧!\n") ;
        exit(0) ;
    }

    S->next = NULL ;
}

void Push(LiStack &S, StackElemType data)
{
    LiStack q ;
    q = (LinkNode *)malloc(sizeof(LinkNode)) ;
    if(NULL == q)
    {
        printf("記憶體不足,不能分配棧!\n") ;
        exit(0) ;
    }

    /*
        插入順序相當於頭插法.
    */
    q->data = data ;
    q->next = S->next ;
    S->next = q ;
}

void Pop(LiStack & S, StackElemType &data)
{
    LiStack  q;
    if(NULL == S->next)
    {
        printf("棧為空,無返回值!\n") ;
    }

    q = S->next ;
    data = q->data ;
    S->next = q->next ;
    free(q) ;
}


int StackEmpty(LiStack  &S)
{
    if(NULL == S->next)
    {
        return(1) ;
    }

    return(0) ;
}

int GetTop(LiStack &S, StackElemType & data)
{
    if(NULL != S->next)
    {
        data = S->next->data ;
        return(1) ;
    }
    else
    {
        //data = NULL ;
        return(0) ;
    }
}

/*********************************************************************/




/*****************************佇列的方法******************************/


//佇列函式的定義
Status InitQueue(LinkQueue &Q)
{
    Q.fronts = Q.rears = (QNode *)malloc(sizeof(QNode)) ;
    if(NULL == Q.fronts)
    {
        printf("記憶體不足!\n") ;
        return ERROR;
    }

    Q.fronts->next = NULL;

}

Status EnQueue(LinkQueue &Q, QueueElemType data)
{
    QueuePtr q ;
    q = (QNode*)malloc(sizeof(QNode));

    if(NULL == q)
    {
        printf("記憶體不足!\n") ;
        return ERROR;
    }

    //構造q
    q->data = data ;
    q->next = NULL;


    q->next = Q.rears->next ;
    Q.rears = q ;

    return OK;
}

Status DeQueue(LinkQueue &Q, QueueElemType & data)
{
    QueuePtr  p ;
    if(Q.fronts == Q.rears)
    {
        printf("佇列為空!\n") ;
        return ERROR ;
    }


    p = Q.fronts->next ;
    data = p->data ;


    Q.fronts->next = p->next ;
    if(Q.rears == p)
        Q.rears = Q.fronts ;

    free(p);

    return OK;
}

int QueueEmpty(LinkQueue Q)
{
    if(Q.fronts == Q.rears)
        return(1) ;
    else
        return(0) ;
}

/*********************************************************************/








/*
   先序建立二叉樹
*/
Status creatBiTree(BiTree &T)
{
    char ch;

    scanf("%c",&ch);

    if('@' == ch)
    {
        T = NULL;
    }
    else
    {

        //申請失敗
        if(!(T = (BiTNode*)malloc(sizeof(BiTNode))))
            return ERROR;

        T->data = ch;

        creatBiTree(T->lchild);
        creatBiTree(T->rchild);
    }



    return OK;
}

void VisitF(char ch)
{
    printf("%c  ",ch);
}

void Visit(char ch,int level)
{

    printf("%c 位於第 %d 層 \n",ch,level);

}


/*
    先序遍歷二叉樹
*/
void PreOrderTraverse(BiTree T,int level)
{



    if( T )
    {
        VisitF(T->data);
        PreOrderTraverse(T->lchild,++level);
        PreOrderTraverse(T->rchild,++level);
    }
}

void PreOrderTraverse_Nonrecursion(BiTree T)
{
    LiStack  S ;
    BiTree  p ;
    S = NULL ;
    p = T ;

    InitStack(S) ;

    if(NULL == p)
    {
        printf("樹為空!\n") ;
        return ;
    }

    while(p || !StackEmpty(S))
    {
        if(p)
        {
            Push(S, p) ;
            VisitF(p->data);
            p = p->lchild ;
        }
        else
        {
            Pop(S, p) ;
            p = p->rchild ;
        }
    }

    free(S) ;
}


/*
    中序遍歷二叉樹
*/
void InOrderTraverse(BiTree T)
{

    if( T )
    {
        InOrderTraverse(T->lchild);
        VisitF(T->data);
        InOrderTraverse(T->rchild);
    }
}

void InOrderTraverse_Nonrecursion(BiTree T)
{
    LiStack  S ;
    BiTree  p ;
    S = NULL ;
    p = T ;

    InitStack(S) ;

    if(NULL == p)
    {
        printf("樹為空!\n") ;
        return ;
    }

    while(p || !StackEmpty(S))
    {
        if(p)
        {
            Push(S, p) ;

            p = p->lchild ;
        }
        else
        {
            Pop(S, p) ;
            VisitF(p->data);
            p = p->rchild ;
        }
    }

    free(S) ;
}


/*
    後續遍歷二叉樹
*/
void PostOrderTraverse(BiTree T)
{

    if( T )
    {
        PostOrderTraverse(T->lchild);
        PostOrderTraverse(T->rchild);
        VisitF(T->data);
    }
}

void PostOrderTraverse_Nonrecursion(BiTree T)
{
    LiStack  S ;
    BiTree  cur, pre ;
    S = NULL ;
    InitStack(S) ;
    if(NULL == T)
    {
        printf("樹為空!\n") ;
        return ;
    }

    pre = NULL ;
    cur = NULL ;
    Push(S,T) ;
    while(!StackEmpty(S))
    {
        cur = NULL ;
        GetTop(S,cur) ;
        if((cur->lchild == NULL && cur->rchild == NULL) || (pre != NULL && (pre == cur->lchild ||pre == cur->rchild)))
        {
            VisitF(cur->data);
            pre = cur ;
            Pop(S,cur) ;
        }
        else
        {
            if(cur->rchild != NULL)
            {
                Push(S,cur->rchild) ;
            }
            if(cur->lchild != NULL)
            {
                Push(S,cur->lchild) ;
            }
        }
    }
    free(S) ;
}

int main()
{
    int level = 1;
    BiTree T = NULL;

    creatBiTree(T);

    printf("先序遍歷二叉樹,每個結點在第幾行\n");
    PreOrderTraverse(T,level);

    printf("\n\n");
    printf("先序遍歷二叉樹,非遞迴演算法\n");

    PreOrderTraverse_Nonrecursion(T);
    printf("\n\n\n");

    /***************************************************/


    printf("中序遍歷二叉樹\n");
    InOrderTraverse(T);

    printf("\n\n");
    printf("中序遍歷二叉樹,非遞迴演算法\n");

    InOrderTraverse_Nonrecursion(T);
    printf("\n\n\n");

    /***************************************************/

    printf("後序遍歷二叉樹\n");
    PostOrderTraverse(T);

    printf("\n\n");
    printf("後序遍歷二叉樹,非遞迴演算法\n");

    PostOrderTraverse_Nonrecursion(T);
    printf("\n\n\n");

    return 0;
}