數據結構--二叉樹和二叉樹的遍歷

二叉樹我覺得真的很重要,算是寫的很清楚了,希望能幫到有需要的朋友。

首先:

二叉樹簡介

二叉樹是由n(n>=0)個結點組成的有序集合,集合或者爲空,或者是由一個根節點加上兩棵分別稱爲左子樹和右子樹的、互不相交的二叉樹組成。
二叉樹的五種形態:

詞彙:

度:二叉樹的度是指樹中所有結點的度數的最大值。二叉樹的度小於等於2,因爲二叉樹的定義要求二叉樹中任意結點的度數(結點的分支數)小於等於2

其他:

一、特殊的二叉樹及特點

1、斜樹

所有的結點都只有左子樹(左斜樹),或者只有右子樹(右斜樹)。這就是斜樹,應用較少

 

 

2、滿二叉樹

所有的分支結點都存在左子樹和右子樹,並且所有的葉子結點都在同一層上,這樣就是滿二叉樹。就是完美圓滿的意思,關鍵在於樹的平衡。

 

 

根據滿二叉樹的定義,得到其特點爲:

  1. 葉子只能出現在最下一層。
  2. 非葉子結點度一定是2.
  3. 在同樣深度的二叉樹中,滿二叉樹的結點個數最多,葉子樹最多。

3、完全二叉樹

對一棵具有n個結點的二叉樹按層序排號,如果編號爲i的結點與同樣深度的滿二叉樹編號爲i結點在二叉樹中位置完全相同,就是完全二叉樹。滿二叉樹必須是完全二叉樹,反過來不一定成立。

其中關鍵點是按層序編號,然後對應查找。

 

 

在上圖中,樹1,按層次編號5結點沒有左子樹,有右子樹,10結點缺失。樹2由於3結點沒有字數,是的6,7位置空擋了。樹3中結點5沒有子樹。

 

 

上圖就是一個完全二叉樹。

結合完全二叉樹定義得到其特點:

  1. 葉子結點只能出現在最下一層(滿二叉樹繼承而來)
  2. 最下層葉子結點一定集中在左 部連續位置。
  3. 倒數第二層,如有葉子節點,一定出現在右部連續位置。
  4. 同樣結點樹的二叉樹,完全二叉樹的深度最小(滿二叉樹也是對的)。

根據下圖加深理解,什麼時候是完全二叉樹。

(tips:他這個標號數字只是個數, 實際上是採用數組存儲時的位置

所以你看倒數第二個非完全二叉樹同一位置好像都是標7,其實位置是錯誤的所以是非完全二叉樹)

三、二叉樹性質

1、一般二叉樹性質

1、在非空二叉樹的i層上,至多有2i-1個節點(i>=1)。通過歸納法論證。

2、在深度爲K的二叉樹上最多有2k-1個結點(k>=1)。通過歸納法論證。

3、對於任何一棵非空的二叉樹,如果葉節點個數爲n0,度數爲2的節點個數爲n2,則有: n0 = n2 + 1

在一棵二叉樹中,除了葉子結點(度爲0)之外,就剩下度爲2(n2)和1(n1)的結點了。則樹的結點總數爲T = n0+n1+n2;在二叉樹中結點總數爲T,而連線數爲T-1.所以有:n0+n1+n2-1 = 2*n2 +n1;最後得到n0 = n2+1;

 

 

上圖中結點總數是10,n2爲4,n1爲1,n0爲5。

2、完全二叉樹性質

a、具有n的結點的完全二叉樹的深度爲log2n+1.

滿二叉樹是完全二叉樹,對於深度爲k的滿二叉樹中結點數量是2k-1 = n,完全二叉樹結點數量肯定最多2k-1,同時完全二叉樹倒數第二層肯定是滿的(倒數第一層有結點,那麼倒是第二層序號和滿二叉樹相同),所以完全二叉樹的結點數最少大於少一層的滿二叉樹,爲2k-1-1。

根據上面推斷得出: 2k-1-1< n=<2k-1,因爲結點數Nn爲整數那麼n<=2k-1可以推出n<=2k ,n>2k-1-1可以推出 n>=2k-1,所以2k-1<n<=2k 。即可得k-1<=log2n<k 而k作爲整數因此k=[log2n]+1。

b、如果有一顆有n個節點的完全二叉樹的節點按層次序編號,對任一層的節點i(1<=i<=n)有

1.如果i=1,則節點是二叉樹的根,無雙親,如果i>1,則其雙親節點爲[i/2],向下取整

2.如果2i>n那麼節點i沒有左孩子,否則其左孩子爲2i

3.如果2i+1>n那麼節點沒有右孩子,否則右孩子爲2i+1

 

 

在上圖中驗證

第一條:

當i=1時,爲根節點。當i>1時,比如結點爲7,他的雙親就是7/2= 3;結點9雙親爲4.

第二條:

結點6,6*2 = 12>10,所以結點6無左孩子,是葉子結點。結點5,5*2 = 10,左孩子是10,結點4,爲8.

第三條:

結點5,2*5+1>10,沒有右孩子,結點4,則有右孩子。

四、二叉樹遍歷

二叉樹遍歷:從樹的根節點出發,按照某種次序依次訪問二叉樹中所有的結點,使得每個結點被訪問僅且一次。

這裏有兩個關鍵詞:訪問和次序。

 

二叉樹遍歷分爲三種:前序、中序、後序,其中序遍歷最爲重要。爲啥叫這個名字?是根據根節點的順序命名的。

 

比如上圖正常的一個滿節點,A:根節點、B:左節點、C:右節點

前序順序是ABC(根節點=》同級先左後右);中序順序是BAC(左==》根==》右);後序順序是BCA(先左後右最後根)。

比如上圖二叉樹遍歷結果

 

前序遍歷:ABCDEFGHK

 

中序遍歷:BDCAEHGKF

 

後序遍歷:DCBHKGFEA

理解如下:

 

 

更詳細的解釋如下:

 

 

 

 

前序遍歷

 

 

遞歸方式實現前序遍歷

具體過程:
  1. 先訪問根節點
  2. 再序遍歷左子樹
  3. 最後序遍歷右子樹

非遞歸方式實現前序遍歷

具體過程:
  1. 首先申請一個新的棧,記爲stack;
  2. 將頭結點head壓入stack中;
  3. 每次從stack中彈出棧頂節點,記爲cur,然後打印cur值,如果cur右孩子不爲空,則將右孩子壓入棧中;如果cur的左孩子不爲空,將其壓入stack中;
  4. 重複步驟3,直到stack爲空.

過程模擬:

 

 

執行結果:

 

中序遍歷

 

 

遞歸方式實現中序遍歷

具體過程:
  1. 先中序遍歷左子樹
  2. 再訪問根節點
  3. 最後中序遍歷右子樹

非遞歸方式實現中序遍歷

具體過程:
  1. 申請一個新棧,記爲stack,申請一個變量cur,初始時令cur爲頭節點;
  2. 先把cur節點壓入棧中,對以cur節點爲頭的整棵子樹來說,依次把整棵樹的左子樹壓入棧中,即不斷令cur=cur.left,然後重複步驟2;
  3. 不斷重複步驟2,直到發現cur爲空,此時從stack中彈出一個節點記爲node,打印node的值,並讓cur = node.right,然後繼續重複步驟2;
  4. 當stack爲空並且cur爲空時結束。

過程模擬:

 

 

執行結果:

 

後序遍歷

 

 

遞歸方式實現後序遍歷

  1. 先後序遍歷左子樹
  2. 再後序遍歷右子樹
  3. 最後訪問根節點

非遞歸方式實現後序遍歷一

具體過程:
使用兩個棧實現
  1. 申請兩個棧stack1,stack2,然後將頭結點壓入stack1中;
  2. 從stack1中彈出的節點記爲cur,然後先把cur的左孩子壓入stack1中,再把cur的右孩子壓入stack1中;
  3. 在整個過程中,每一個從stack1中彈出的節點都放在第二個棧stack2中;
  4. 不斷重複步驟2和步驟3,直到stack1爲空,過程停止;
  5. 從stack2中依次彈出節點並打印,打印的順序就是後序遍歷的順序;

過程模擬:

 

 

執行結果:

 

非遞歸方式實現後序遍歷二

具體過程:
使用一個棧實現
  1. 申請一個棧stack,將頭節點壓入stack,同時設置兩個變量 h 和 c,在整個流程中,h代表最近一次彈出並打印的節點,c代表當前stack的棧頂節點,初始時令h爲頭節點,,c爲null;
  2. 每次令c等於當前stack的棧頂節點,但是不從stack中彈出節點,此時分一下三種情況:

(1)如果c的左孩子不爲空,並且h不等於c的左孩子,也不等於c的右孩子,則吧c的左孩子壓入stack中
(2)如果情況1不成立,並且c的右孩子不爲空,並且h不等於c的右孩子,則把c的右孩子壓入stack中;
(3)如果情況1和2不成立,則從stack中彈出c並打印,然後令h等於c;

  1. 一直重複步驟2,直到stack爲空.

過程模擬:

 

 

執行結果:

 

層序遍歷

 

 

具體過程:
  1. 首先申請一個新的隊列,記爲queue;
  2. 將頭結點head壓入queue中;
  3. 每次從queue中出隊,記爲node,然後打印node值,如果node左孩子不爲空,則將左孩子入隊;如果node的右孩子不爲空,則將右孩子入隊;
  4. 重複步驟3,直到queue爲空。

 

執行結果:

 

參考:《大話數據結構》

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