1. 程式人生 > >一本正經的聊資料結構(4):樹

一本正經的聊資料結構(4):樹

![](https://cdn.geekdigging.com/DataStructure/head.png) 前文傳送門: [「一本正經的聊資料結構(1):時間複雜度」](https://www.geekdigging.com/2020/03/28/6072951828/) [「一本正經的聊資料結構(2):陣列與向量」](https://www.geekdigging.com/2020/04/14/3143023839/) [「一本正經的聊資料結構(3):棧和佇列」](https://www.geekdigging.com/2020/04/25/5497775819/) ## 引言 在前面的文章中,我們已經陸陸續續的介紹了一些資料結構。 根據這些資料結構的實現方式,大體上可以分成兩類:基於陣列的實現和基於連結串列的實現。 這兩種實現方式各有優缺點,說不上誰一定好誰一定不好,需要根據具體的使用場景進行選型。 基於陣列的實現方式,這種方式允許我們通過下標在常數的時間內找到目標物件,但是如果需要對這種結構進行修改,無論是插入還是刪除,都需要耗費線性的時間。 基於連結串列的實現方式,這種實現方式允許我們藉助位置物件,在常數的時間內插入或者刪除元素,但是如果想要找到某個元素,那麼不得不耗費線性的時間。 基於上面這兩點,我們可以知道,如果當前的場景是修改遠大於查詢,那麼選擇連結串列的資料結構會比較好。 反過來如果是查詢遠大於修改,那麼選擇陣列的資料結構會比較好。 上面這段沒看懂的,可以翻翻前面的文章然後去面壁思過了。 ## 樹 前面這些資料結構,元素之間都有一個自然的線型的關係,所以他們都都被稱為線型結構。 而我們從本篇開始介紹的樹就不一樣了,樹的元素之間並不會有直接的直接前驅或者直接後繼這種關係,但是,只要是加上某種約束條件,也是可以在樹的元素之間確定某種線型次序,所以樹這種結構被稱為半線型結構。 先來看下樹結構長啥樣: ![](https://cdn.geekdigging.com/DataStructure/shu.png) 樹這種結構非常像一個樹倒過來,所以因此而得名。 一些基礎概念: * 結點:使用樹結構儲存的每一個數據元素都被稱為「結點」,如節點 A ,節點 B ,節點 C 。 * 父結點(雙親結點)、子結點和兄弟結點:對於上圖的結點 A、B、C、D 來說,A 是 B、C、D 結點的父結點(也稱為「雙親結點」),而 B、C、D 都是 A 結點的子結點(也稱「孩子結點」)。對於 B、C、D 來說,它們都有相同的父結點,所以它們互為兄弟結點。 * 樹根結點(簡稱「根結點」):每一個非空樹都有且只有一個被稱為根的結點。上圖中,結點 A 就是整棵樹的根結點。樹根的判斷依據為如果一個結點沒有父結點,那麼這個結點就是整棵樹的根結點。 * 葉子結點:如果結點沒有任何子結點,那麼此結點稱為葉子結點(葉結點)。如圖中的結點 K、L、F、G、M、I、J 都是這棵樹的葉子結點。 * 結點的度(Degree):對於一個結點,擁有的子樹數(結點有多少分支)。如上圖中,根結點 A 下分出了 3 個子樹,所以,結點 A 的度為 3。 * 結點的層次:從一棵樹的樹根開始,樹根所在層為第一層,根的孩子結點所在的層為第二層,依次類推。所以在上面這張圖中,A 結點在第一層,B、C、D 為第二層,E、F、G、H、I、J 在第三層,K、L、M 在第四層。 * 有序樹和無序樹:如果樹中結點的子樹從左到右看,誰在左邊,誰在右邊,是有規定的,這棵樹稱為有序樹;反之稱為無序樹。在有序樹中,一個結點最左邊的子樹稱為"第一個孩子",最右邊的稱為"最後一個孩子"。在上圖中,如果是其本身是一棵有序樹,則以結點 B 為根結點的子樹為整棵樹的第一個孩子,以結點 D 為根結點的子樹為整棵樹的最後一個孩子。 ## 二叉樹 二叉樹是樹結構的一種樹,也是我們接觸最多使用最為廣泛的一種樹結構。 簡單地理解,滿足以下兩個條件的樹就是二叉樹: * 本身是有序樹。 * 樹中包含的各個節點的度不能超過 2,即只能是 0、1 或者 2 。 結果就是長這樣的: ![](https://cdn.geekdigging.com/DataStructure/erchahsu.gif) 簡單來講就是每個節點下面最多隻能有兩個分叉,超過兩個就不叫二叉樹了,比如右邊這個或許可以叫三叉樹(這個沒人定義過啊,我就這麼一瞎說)? 二叉樹的幾個特性: * 在二叉樹中,第 i 層最多有 2^(i-1) 個結點。 * 如果二叉樹的深度為 K,那麼此二叉樹最多有 2^K-1 個結點。 這兩個特性的推導過程就不拆開講了,基本上有初中數學基礎的應該都能看得懂。 ## 滿二叉樹 二叉樹還可以接著分類,進而衍生出了滿二叉樹和完全二叉樹。 滿二叉樹就是除了葉子結點,每個結點的度都為 2 。 簡單來講就是所有的節點都插滿了,比如下面這樣的: ![](https://cdn.geekdigging.com/DataStructure/manerchahsu.gif) 滿二叉樹除了具有二叉樹的特性外,還有一些單獨的特性: * 滿二叉樹中第 i 層的節點數為 2^(n-1) 個。 * 深度為 k 的滿二叉樹必有 2^k-1 個節點 ,葉子數為 2^(k-1)。 * 滿二叉樹中不存在度為 1 的節點,每一個分支點中都兩棵深度相同的子樹,且葉子節點都在最底層。 * 具有 n 個節點的滿二叉樹的深度為 log2(n+1)。 ## 完全二叉樹 如果二叉樹中除去最後一層節點為滿二叉樹,且最後一層的結點依次從左到右分佈,則此二叉樹被稱為完全二叉樹。 這個意思就是完全二叉樹是滿二叉樹的不完全體,只要最後一層滿足了從左至右排布以及其餘層次都是滿二叉樹,那麼這個就叫做完全二叉樹,比如下面這樣的: ![](https://cdn.geekdigging.com/DataStructure/wanquanerchahsu.gif) 圖 b 不是完全二叉樹的原因就是因為它的最後一層並不是從左至右排布的,這個要清楚。 完全二叉樹也有一些自己獨特的性質,如: * n 個結點的完全二叉樹的深度為 `⌊log2n⌋+1` 。 * 當 `i>1` 時,父親結點為結點 `[i/2]` 。(`i=1` 時,表示的是根結點,無父親結點) * 如果 `2*i>n`(總結點的個數) ,則結點 i 肯定沒有左孩子(為葉子結點);否則其左孩子是結點 `2*i` 。 * 如果 `2*i+1>n` ,則結點 i 肯定沒有右孩子;否則右孩子是結點 `2*i+1` 。 ## 小結 本篇的內容就先到這裡了,通過本篇的內容,應該對數和二叉樹有一個初步的認知,能夠清楚的瞭解樹和二叉樹的結構以及一些二叉樹的基礎的特性。 從下篇內容開始,我們介紹二叉樹的一個關鍵知識點:實現與