二叉樹的建立以及遍歷C/C++

一、 二叉樹的定義
二叉樹(Binary Tree)是個有限元素的集合,該集合或者爲空,或者由一個稱爲根(root)的元素及兩個不相交的、分別被稱爲左子樹和右子樹的二叉樹組成。當集合爲空時,稱該二叉樹爲空二叉樹,在二叉樹中,一個元素也成爲一個節點。
這裏寫圖片描述
二、 二叉樹的數據結構
下面爲二叉樹鏈式存儲結構的定義:

 /*
 *定義二叉樹的數據結構
 */
typedef char datatype ;
typedef struct BiTNode
{
    datatype data ; //數據域
    struct BiTNode *lchild , *rchild ; //孩子的左右節點
} BiTNode , *BiTree ;

三、 二叉樹的遞歸遍歷
1、 二叉樹的前序遍歷
若二叉樹爲非空,則依次進行如下操作:
(1) 訪問根節點;
(2) 先序遍歷左子樹;
(3) 先序遍歷右子樹;
算法如下:

/*
 *進行二叉樹的先序遍歷
 */
void PreOrder(BiTree bt)
{
    if(bt == NULL) //遞歸的結束的條件
    {
        return ;
    }
    printf("%c " , bt->data) ;
    PreOrder(bt->lchild) ;
    PreOrder(bt->rchild) ;
}

2、 二叉樹的中序遍歷
若二叉樹爲非空,則依次進行如下操作:
(1)中序遍歷左子樹;
(2)訪問根節點;
(3)中序遍歷右子樹;
算法如下:

/*
 *中序遍歷二叉樹
 */
void InOrder(BiTree bt)
{
    if(bt == NULL) //遞歸的結束條件
    {
        return ;
    }
    InOrder(bt->lchild) ;
    printf("%c " , bt->data) ;
    InOrder(bt->rchild) ;
}

3、 二叉樹的後續遍歷
若二叉樹爲非空,則依次進行如下操作:
(1)後序遍歷左子樹;
(2)後序遍歷右子樹;
(3)訪問根節點;
算法如下:

/*
 *後序遍歷二叉樹
 */
void PostOrder(BiTree bt)
{
    if(bt == NULL) //遞歸的結束條件
    {
        return ;
    }
    PostOrder(bt->lchild) ;
    PostOrder(bt->rchild) ;
    printf("%c " , bt->data) ;
}

4、 二叉樹的層次遍歷
藉助隊列的數據結構進行層次遍歷
(1) 訪問當前隊頭節點;
(2) 若該元素所指節點的左、右孩子節點非空,則將該元素所指節點的左孩子指針和右孩子指針順序入隊;
(3) 此過程不斷進行,當隊列爲空時,二叉樹的層次遍歷結束;
算法如下:

/*
 *用隊列實現二叉樹的層次遍歷
 */
 void LevelOrder(BiTree bt)
 {
     BiTree quene[MAXSIZE] ;
     int front , rear ; //分別指向隊列的隊首語隊尾
     if(bt == NULL)
     {
         return ;
     }
     front = -1 ;
     rear = 0 ;
     quene[rear] = bt ;
     while(front != rear)
     {
         front++ ;
         printf("%c " , quene[front]->data) ;
         if(quene[front]->lchild != NULL) //將隊首的左孩子節點加入隊列
         {
             rear++;
             quene[rear] = quene[front]->lchild ;
         }
         if(quene[front]->rchild != NULL) //將隊首的右孩子節點加入隊列
         {
             rear++;
             quene[rear] = quene[front]->rchild ;
         }
     }
 }

四、 二叉樹的非遞歸遍歷
1、 二叉樹的非遞歸前序遍歷
藉助棧存儲當前訪問的節點,棧爲空時,訪問結束。
算法如下:

/*
  *進行二叉樹的非遞歸前序遍歷
  */
void  NRPreOrder(BiTree bt)
{
    BiTree stack[MAXSIZE] , p ;
    int i , top ;
    if(bt == NULL)
    {
        printf("二叉樹爲空!\n") ;
        return ;
    }
    top = 0 ;
    p = bt ;
    while(p != NULL || top != 0)
    {
        while(p != NULL)
        {
            printf("%c " , p->data) ; //範圍訪問當前元素
            if(top < MAXSIZE - 1)
            {
                stack[top] = p ; //將當前結點壓棧
                top++ ;
            }
            else
            {
                printf("棧溢出!\n") ;
                return ;
            }
            p = p->lchild ; //指針指向該節點的左孩子
        }
        if(top <= 0)
        {
            return ;
        }
        else
        {
            top-- ;
            p = stack[top] ; //從棧中彈出棧頂元素
            p = p->rchild ; //指針指向該節點的右孩子
        }
    }
}

2、 二叉樹的非遞歸中序遍歷
只需將訪問節點的代碼移動到p = stack[top] 和 p = p->rchild 之間即可。
算法如下:

/*
 *進行非遞歸的中序遍歷
 */
void NRInOrder(BiTree bt)
{
   BiTree stack[MAXSIZE] , p ;
    int i , top ;
    if(bt == NULL)
    {
        printf("二叉樹爲空!\n") ;
        return ;
    }
    top = 0 ;
    p = bt ;
    while(p != NULL || top != 0)
    {
        while(p != NULL)
        {
            if(top < MAXSIZE - 1)
            {
                stack[top] = p ;
                top++ ;
            }
            else
            {
                printf("棧溢出!\n") ;
                return ;
            }
            p = p->lchild ;
        }
        if(top <= 0)
        {
            return ;
        }
        else
        {
            top-- ;
            p = stack[top] ;
            printf("%c " , p->data) ; //範圍訪問當前元素
            p = p->rchild ;
        }
    }
}

3、 二叉樹的後序遍歷
在後序遍歷過程中,節點在第一次出棧後,還需再次入棧,也就是說節點要入兩次棧,出兩次棧。而訪問節點是在第二次出棧是進行的。因此爲了區別節點出棧的次數,定義數據結構:

/*
 *爲二叉樹的後續遍歷建立數據結構
 */
typedef struct
{
    BiTree bt ;
    int flag ;
} stacktype ;
算法如下:
/*
 *進行二叉樹的後序遍歷
 */
void NRPostOrder(BiTree bt)
{
    stacktype stack[MAXSIZE] ;
    int top , sign ;
    BiTree p ;
    if(bt == NULL)
    {
        return ;
    }
    top = -1 ;
    p = bt ;
    while(p != NULL || top != -1)
    {
        if(p != NULL)
        {
            top++ ;
            stack[top].bt = p ;
            stack[top].flag = 1;
            p = p->lchild ;
        }
        else
        {
            p = stack[top].bt ;
            sign = stack[top].flag ;
            top-- ;
            if(sign == 1)
            {
                //進行二次壓棧
                top++ ;
                stack[top].bt = p ;
                stack[top].flag = 2 ;
                p = p->rchild ;
            }
            else
            {
                printf("%c " , p->data) ; //進行二叉樹的訪問
                p = NULL ;
            }
        }
    }
}

五、 二叉樹的建立
由二叉樹的性質可知,二叉樹可有先序序列和中序序列唯一確定,而後序序列與中序序列無法確定唯一二叉樹。
算法思想是:運用遞歸求解二叉樹,先根據先序序列的第一個元素建立根節點;然後在中序序列中找到該元素,確定根節點的左、右子樹的中序序列;再在先序序列中確定左、右子樹的先序序列;最後由左子樹的先序序列與中序序列建立左子樹,由右子樹的先序序列與中序序列建立右子樹。
算法如下:

void PreInO(char preOrder[] , char inOrder[] , int i , int j , int k , int h , BiTree *bt)
{
    int m ;
    if(!((*bt) = (BiTree)malloc(sizeof(BiTNode))))
    {
        return ;
    }
    else
    {
       (*bt)->data = preOrder[i] ;
        m = k ;
        while(preOrder[i] != inOrder[m])
        {
            m++ ;
        }
        if(m == k)
        {
            (*bt)->lchild = NULL ;
        }
        else
        {
            PreInO(preOrder , inOrder , i + 1 , m - k + i , k , m - 1 , &((*bt)->lchild)) ; //進行左子樹的建立
        }
        if(m == h)
        {
            (*bt)->rchild = NULL ;
        }
        else
        {
            PreInO(preOrder , inOrder , m - k + i + 1 , j , m + 1 , h , &((*bt)->rchild)) ; //進行右子樹的建立
        }
    }
}
/*
 *根據二叉樹的前序遍歷序列和中序遍歷確定唯一二叉樹
 *根據二叉樹的中序遍歷和後續遍歷不能確定唯一二叉樹
 */
void ReBiTree(char preOrder[] , char inOrder[] , BiTree *bt)
{
    int len ;
    len = strlen(preOrder) ;
    if(len <= 0)
    {
        return ;
    }
    else
    {
        PreInO(preOrder , inOrder , 0 , len - 1 , 0 , len - 1 , bt) ;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章