1. 程式人生 > >二叉樹及二叉樹的應用

二叉樹及二叉樹的應用

1、基本概念

     葉子節點:葉子節點只有父節點沒有子節點;

     根節點:起始的節點叫做根節點,整棵樹只有一個根節點;

     父節點:除了根節點之外,每個節點都有且只有一個父節點;

     滿二叉樹:每個枝節點都有兩個子節點,則該二叉樹叫做滿二叉樹;

     完全二叉樹:二叉樹中除了最下面一層之外,每層節點個數均達到最大值,並且最下面一層的節點都連續集中在左側,則該二叉樹叫做完全二叉樹;

2、基本特徵

     二叉樹具有遞迴巢狀式的空間結構,也就是說對於一棵二叉樹來說,可以拆分為若干個小二叉樹組成,因此採用遞迴的方法處理二叉樹比較方便,處理方式如下:

   處理(二叉樹)

   {

     if(是空樹)  直接處理完畢;

     else

     {

         處理根節點;

         處理左子樹; => 遞迴

         處理右子樹; => 遞迴

     }

   }

3、二叉樹遍歷

     3.1 所謂遍歷(Traversal)是指沿著某條搜尋路線,依次對樹中每個結點均做一次且僅做一次訪問。訪問結點所做的操作依賴於具體的應用問 題。 

           遍歷是二叉樹上最重要的運算之一,是二叉樹上進行其它運算的基礎。

     3.2 二叉樹遍歷方式:先序遍歷、中序遍歷(投影)、後序遍歷

           

                             圖 3.2 二叉樹遍歷

 4、儲存結構

       4.1 線性(順序)儲存結構

             一般來說,從上到下,從左到右依次儲存節點,對於非完全二叉樹來說,採用虛節點來補成完全二叉樹

二叉樹的順序儲存,就是用一組連續的儲存單元存放二叉樹中的結點。因此,必須把二叉樹的所有結點安排成為一個恰當的序列,結點在這個序列中的相互位置能反映出結點之間的邏輯關係,用編號的方法從樹根起,自上層至下層,每層自左至右地給所有結點編號,缺點是有可能對儲存空間造成極大的浪費,在最壞的情況下,一個深度為k且只有k個結點的右單支樹需要2k-1個結點儲存空間。依據二叉樹的性質,完全二叉樹和滿二叉樹採用順序儲存比較合適,樹中結點的序號可以唯一地反映出結點之間的邏輯關係,這樣既能夠最大可能地節省儲存空間,又可以利用陣列元素的下標值確定結點在二叉樹中的位置,以及結點之間的關係。圖4.1.1(a)是一棵完全二叉樹,圖4.1.1(b)給出的圖4.1.1(a)所示的完全二叉樹的順序儲存結構。

         (a)  一棵完全二叉樹                           (b)    順序儲存結構

                                     圖 4.1.1  完全二叉樹的順序儲存示意圖

 對於一般的二叉樹,如果仍按從上至下和從左到右的順序將樹中的結點順序儲存在一維陣列中,則陣列元素下標之間的關係不能夠反映二叉樹中結點之間的邏輯關係,只有增添一些並不存在的空結點,使之成為一棵完全二叉樹的形式,然後再用一維陣列順序儲存。如圖4.1.2給出了一棵一般二叉樹改造後的完全二叉樹形態和其順序儲存狀態示意圖。顯然,這種儲存對於需增加許多空結點才能將一棵二叉樹改造成為一棵完全二叉樹的儲存時,會造成空間的大量浪費,不宜用順序儲存結構。最壞的情況是右單支樹,如圖4.1.2 所示,一棵深度為k的右單支樹,只有k個結點,卻需分配2k-1個儲存單元。

          (a) 一棵二叉樹                                  (b) 改造後的完全二叉樹

                                 (c) 改造後完全二叉樹順序儲存狀態

                                圖4.1.2 一般二叉樹及其順序儲存示意圖

 (a) 一棵右單支二叉樹                  (b) 改造後的右單支樹對應的完全二叉樹

                              (c) 單支樹改造後完全二叉樹的順序儲存狀態

                                圖 4.1.3 右單支二叉樹及其順序儲存示意圖

    結構5-1二叉樹的順序儲存

複製程式碼
#define Maxsize 100     //假設一維陣列最多存放100個元素
typedef char Datatype;  //假設二叉樹元素的資料型別為字元
typedef struct
{ Datatype bt[Maxsize];
    int btnum;
  }Btseq;

       4.2 鏈式儲存結構

二叉樹的鏈式儲存結構是指,用連結串列來表示一棵二叉樹,即用鏈來指示元素的邏輯關係。

通常的方法是連結串列中每個結點由三個域組成,資料域和左右指標域,左右指標分別用來給出該結點左孩子和右孩子所在的鏈結點的儲存地址。其結點結構為:

 其中,data域存放某結點的資料資訊;lchild與rchild分別存放指向左孩子和右孩子的指標,當左孩子或右孩子不存在時,相應指標域值為空(用符號∧或NULL表示)。利用這樣的結點結構表示的二叉樹的鏈式儲存結構被稱為二叉連結串列,如圖4.2.1所示。  

(a) 一棵二叉樹                                          (b) 二叉連結串列儲存結構

                  圖 4.2.1   二叉樹的二叉連結串列表示示意圖

    為了方便訪問某結點的雙親,還可以給連結串列結點增加一個雙親欄位parent,用來指向其雙親結點。每個結點由四個域組成,其結點結構為:

 這種儲存結構既便於查詢孩子結點,又便於查詢雙親結點;但是,相對於二叉連結串列儲存結構而言,它增加了空間開銷。利用這樣的結點結構表示的二叉樹的鏈式儲存結構被稱為三叉連結串列。

    圖4.2.2 給出了圖4.2.1 (a)所示的一棵二叉樹的三叉連結串列表示。

                                          圖4.2.2 二叉樹的三叉連結串列表示示意圖

    儘管在二叉連結串列中無法由結點直接找到其雙親,但由於二叉連結串列結構靈活,操作方便,對於一般情況的二叉樹,甚至比順序儲存結構還節省空間。因此,二叉連結串列是最常用的二叉樹儲存方式。

結構4.2二叉樹的鏈式儲存

#define datatype char  //定義二叉樹元素的資料型別為字元
typedef struct  node   //定義結點由資料域,左右指標組成
{ Datatype data;
  struct node *lchild,*rchild;
 }Bitree;
      

        一般來說,每個節點中除了儲存資料元素本身之外,還需要兩個指標,分別記錄左右子節點的地址

如:

  typedef struct Node

   {

      int data;//資料內容

      struct Node* left;//記錄左子樹的地址

      struct Node* right;//記錄右子樹的地址

   }Node;

 5、有序二叉樹

當左子樹不為空時,則左子樹的元素值小於等於根節點;

      當右子樹不為空時,則右子樹的元素值大於等於根節點,左右子樹也分別有序,滿足上述特徵的二叉樹,叫做有序二叉樹

50 70 20 60 40 30 10 90 80

   要求以元素50作為根節點,將上述元素組成一棵有序二叉樹,並且使用三種方法進行遍歷

   解析:

         50           80

      /        \

     20         70

    / \            /   \

  10  40    60  90

        /       /

     30      80

先序遍歷:50 20 10 40 30 70 60 90 80

中序遍歷:10 20 30 40 50 60 70 80 90 (掌握)

後序遍歷:10 30 40 20 60 80 90 70 50

6、實際應用

      主要用於搜尋和查詢資料的程式中,查詢速度比較快,也比較方便,叫做二叉查詢樹。

7、二叉樹考點

      7.1 二叉樹深度:

深度為m的滿二叉樹有2^m-1個結點;

具有n個結點的完全二叉樹的深度為[log2n]+1.(log2n是以2為底n的對數);

7.2某二叉樹共有七個結點,其中葉子結點只有一個,則該二叉樹的深度為——

因為葉子節點為1個,按二叉樹理論得出(任意一棵二叉樹中度為0的節點總是比度為2的節點多一個),故得出此二叉樹度為2的節點為0個;

7(總節點)-1(度為0)- 0(度為2)=6(度為1)。故證明此二叉樹每層只有1個節點,總共7層。