二叉樹的遞歸遍歷


hello,大家好,明天就是"double eleven了,不知道大家准備好沒有,我們還是加班加點的把二叉樹來看一下。

在講遍歷之前,我們首先應該了解一下二叉樹是怎么建立的   

    3
   / \
  9  20
    /  \
   15   7

你可能會看到這樣的一顆二叉樹,那么這顆二叉樹的根節點就是 3 ,而它的兩個孩子結點就是 9 和 20 ,在我們建立一顆二叉樹的時候,
就算它只有一個或者沒有孩子,我們也要把另外一個或兩個孩子補上去,可以是空格,也可以是其他你自己定義的特殊字符。(但是補了字符的兩個孩子就不用管了。)

看了上面,相信你對二叉樹已經有了一個印象了,讓我們開始吧。

一、結構體

typedef struct node{
  elemtype data;                                    //注意這里的 elemtype 前面要設置成 char 類型(也就是字符串),

                                                                   //因為我們的二叉樹可能會是字母什么的
  struct node*lchild,*rchild;                    //然后構造它的兩個孩子指針,跟之前的 next 差不多,就是一個

                                                                   //指向左邊的 next 和一個指向右邊的 next
}node,*btnode;                                           //常規定義 node 數組名和 btnode 指針類型名

 

 二、建立二叉樹

    3
   / \
  9  20
    /  \
   15   7

關於方法,上面有提到,這里再提兩點:

1,在構造數的過程中,因為用到的是遞歸,所以當我們構造了 3 之后,再構造 9 時,就又可以把它看成是一個新的跟結點,這就是我們遞歸的原理。

2,就是我們的二叉樹的輸入問題了,因為存在着某些孩子結點不存在的情況,所以在輸入的時候就要注意了,如上圖,我們的輸入就應該是:

(我們的表空字符設為 * )

  39**2015**7***

是的,元素之間沒有空格,我們的輸入按照的是前序遍歷的輸入(當初滿二叉樹的前序),在沒有的地方補上表空字符 * 就好了

大家會不會問為什么 15 后面有兩個 * 呢,我們前面提到的就算沒有但是也要補上去就是這個了,9 后面構造了兩個,然后構造的節點后面就不用管啦

#注意最后一個節點必須多輸入一個 *   ,這樣計算機才知道已經輸入完了

 

Status creat_btree(btnode *T){
  elemtype ch;                                                                      //定義一下我們即將輸入的元素
  scanf("%c",&ch);                                                                //直接一次性輸入所有元素,計算機會一個

                                                                                                  //一個讀取
  if(ch == ' ')   (*T) = NULL;                                                   //這里的空格就是我們的表空字符,當這個

                                                                                                  //孩子不存在的時候,就可以把它的指針

                                                                                                  //定位 NULL 了

    else{

    if(!((*T) = (btnode)malloc(sizeof(node)))) exit(ERROR);
    (*T)->data=ch;                                                            //空間分配成功,就可以給我們的結點賦值了。
    creat_btree(&(*T)->lchild);                                          //賦完值之后,利用遞歸,就可以先構造它的

                                                                                                  //左邊(左子樹)
    creat_btree(&(*T)->rchild);                                          //構造右子樹

  }
  return OK;                                                                          //大家可以試着想一下,先是跟結點,然后是它

                                                                                                  //的孩子,當其中一個孩子的孩子的孩子......就算

                                                                                                  //沒有的也構造完了,這個孩子就完成了,就

                                                                                                  //通過return 返回,

                                                                                                  //進行下一個遞歸,最后一個 return(也就是我們

                                                                                                  //多寫的那個 * )

                                                                                                  //返回之后,就代表結束啦。
}

 

 

在遍歷之前,我需要先設置一個 printf 函數

Status print(elemtype e){
  printf("%c ",e);
  return OK;
}

三、前序遍歷

前序遍歷首先訪問根節點,然后遍歷左子樹,最后遍歷右子樹。(如下圖)

Status preorder(btnode T,Status (* print)(elemtype e)){                    //大家是不是對這里的參數感到奇怪,

                                                                                                          //通過后面的參數。我們就可以在子函數

                                                                                                          //里面調用我們定義了的其他子函數了
  if(T){                                                                                           //先判斷根節點是否為空
    if (print(T->data))                                                                 //非空的話就可以輸出它所代表的元素了
      if(preorder(T->lchild,print))                                           //然后再對左邊進行遍歷,注意一下 preorder 

                                                                                                          //的函數調用方式
        if(preorder(T->rchild,print))                                   //接着是右邊
          return OK;                                                     //這個 OK 跟我們創建二叉樹的原理是一樣的

                                                                                                          //(其實遞歸的原理都差不多)
    else return ERROR;
  }
  else return OK;
}

 四、中序遍歷

中序遍歷是先遍歷左子樹,然后訪問根節點,然后遍歷右子樹。

 

Status inorder(btnode T,Status (* print)(elemtype e)){
  if(T){
    if(inorder(T->lchild,print))
      if (print(T->data))
        if(inorder(T->rchild,print))
          return OK;
      else return ERROR;                                              //別的就不多說了,提一下這里

                                                                                                    //的 return ERROR ,這個必須是跟

                                                                                                    //print(T->data)的 if 對齊的,為了防止

                                                                                                    //輸入或者輸出的時候有誤,

                                                                                                    //用來退出錯誤項的。
  }
  else return OK;
}

 

五、后序遍歷

后序遍歷是先遍歷左子樹,然后遍歷右子樹,最后訪問樹的根節點。

Status postorder(btnode T,Status (* print)(elemtype e)){
  if(T){
    if(postorder(T->lchild,print))
      if(postorder(T->rchild,print))
        if (print(T->data))
          return OK;}
        else return ERROR;
  else return OK;
}

差不多就不多說了。

附:main函數

void main()
{
  node t;btnode T = &t;                                            //這里記住要指一下。
  creat_btree(&T);
  printf("前序遍歷為:");preorder(T,print); 
  printf("\n中序遍歷為:");inorder(T,print);
  printf("\n后序遍歷為:");postorder(T,print);
  system("pause");
}

所有圖片來自LeetCode


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM