第四章:樹與二叉樹(二叉樹的存儲結構)
1.二叉樹的順序存儲
二叉樹的順序存儲
用一組連續的存儲單元依次自上而下、自左至右存儲完全二叉樹
上的結點元素。
思考爲啥是存儲完全二叉樹?
這裏正常情況存儲的時數據,我們這裏理解就存儲編號了。但是如果使用上圖存儲,我們如何表示二叉樹的邏輯關係
呢?
二叉樹的邏輯關係
:1 是 2 和 3的雙親結點,2 3 是 1 的孩子結點。
這樣的邏輯關機該如何維護呢?
我們在學習線性表的時候,我們知道線性表的地址是連續的,也就是線性表的下一個結點就是它下一個存儲單元存放的元素,但是如果按照上圖存儲,一個節點的孩子結點一定是它接下來存放的元素嗎?
二叉樹邏輯關係的表示方法:
我們知道:在完全二叉樹
中依次編號,對於結點 i :若存在左孩子,則編號爲 2i;若存在右孩子,則編號爲 2i+1 。
所以我們使用這樣的性質來實現二叉樹邏輯關係。
在這裏數組下標和結點的標號是一致的,這樣我們就能使用下標來找到孩子結點下標了。這裏爲了更方便的對應完全二叉樹
性質,所以數組的第一個位置我們沒有存儲結點,當然其實也是可以存儲的只不過找孩子結點的方式需要改變:左孩子 2i+1,右孩子2i+2 。其實我們在進行實際應用的是偶,0這個位置是會存儲節點的個數的。
注意上面都是說的是
完全二叉樹
例如上圖,是非完全二叉樹
,我們按照數組第一個位置空出來然後從上到下,從左到右,將結點依次填入數組,如上圖。此時我們按如果按照上面的性質找3結點的左孩子爲 2x3=6,按理說應該是存儲在下標爲6的地方,可以是實際上存儲到下標爲5的地方,這樣就無法通過之前的方法來表示邏輯關係
了。
那麼該採用什麼方法呢?
其實只需要對方法改進一下就行了。我們將這顆非完全二叉樹
補 成 完全二叉樹
,即將 2 號結點補一個右孩子即可,然後進行存放。因爲添加了一個不存在的空結點,所以在數組中用 0
表示
此時就表示了邏輯關係。雖然我們這樣完成了二叉樹的順序存儲的而且表示了邏輯關係,但是這樣的存儲方法是有一個 弊端 的。
如上圖,我們如果將上面的二叉樹使用順序存儲,則需要將其補成完全二叉樹,這樣我們就浪費了很多的存儲空間來進行存放。所以:
順序存儲最壞情況會非常浪費存儲空間,比較適合完全二叉樹
。
因此我們在存儲二叉樹的時候往往使用鏈式存儲。
2.二叉樹的鏈式存儲
二叉樹的鏈式存儲:用鏈表來存放一棵二叉樹,二叉樹中每個結點用鏈表的一個鏈結點來存儲。
因爲是二叉樹,所以每個結點都可能有一個左孩子和右孩子,我們使用鏈表存放,所以可以每個結點可以定義一個數據域和兩個指針域,兩個指針域用來分別存儲左結點和右結點。
我們舉一個例子來看看具體是如何存放的。
因爲某些結點沒有左孩子或者右孩子,所以會出現空的指針域的情況,關於空指針域的個數我們有如下規律:
含有n個結點的二叉鏈表中,有 n+1 個空鏈域。
上面的結論是通過:2n-(n-1)
這個式子得到。式子的解釋:
2n
表示每一個結點都有兩個指針域,那麼共n個結點,則總共 2n個指針域。我們要想的到空鏈域,則需要減去指針非空指針域。而非空指針域的個數其實就是孩子結點,有一個孩子結點,則需要一個指針域指向,而總共多少個孩子結點呢?總共爲 n-1
個,因爲 n 個結點中除了第一個結點是二叉樹根節點外,其餘都是孩子結點。故得到:2n-(n-1)=n+1
3.總結
本次學習了二叉樹的順序存儲和鏈式存儲,在實際應用中,對於順序存儲我們可能直接在數組的下標爲1的位置開始存儲二叉樹,下標爲0的位置存儲二叉樹的信息。
鏈式存儲中,我們也可能需要三個指針域,除了指向左右孩子結點的指針域,還需要一個指向雙親結點的指針域。
關於數據結構的知識持續更新中,下次將會講解:二叉樹的遍歷和線索二叉樹,歡迎大家的關注,也可以關注同名公衆號 理木客