資料結構與演算法(十二)
多路查詢樹
二叉樹與 B 樹
二叉樹存在的問題
二叉樹的操作效率較高,但是也存在問題,如下圖所示
當二叉樹的節點較少時,不會出現什麼問題。但是當節點過多時(海量,如 1 億),就會出現如下的問題:
-
構建二叉樹時,需要進行多次 I/O 操作
節點較多時,一般會儲存在檔案或則資料庫中,進行多次 I/O 獲取到所有的節點,速度有影響
-
會造成二叉樹的高度很大,降低操作速度
多叉樹
為了解決層數過多的問題,就出現了 多叉樹。
在二叉樹中,每個節點有資料項,最多有兩個子節點。如果允許每個節點可以有更多的資料項和更多的子節點,就是 多叉樹(multiway tree)。
多叉樹也有一定的規則的,比如後面講解的 2-3 樹、2-3-4 樹,就是多叉樹。
多叉樹通過重新組織節點,減少樹的高度,對二叉樹進行優化。
下圖則是一顆 2-3 的多叉樹:
2-3 的原因:如上圖按節點數量來定義的。有的只有 2 個子節點,有的有 3 個子節點。
B 樹的基本介紹
B 樹通過重新組織節點,降低樹的高度,並且減少 I/O 讀寫次數來提升效率。
上圖說明:
- 一個圓圈表示一個數據項
- 相連的資料項,整個表示一個節點
那麼它的有點如何理解呢?
-
降低樹的高度:
可以看到,一個節點中有很多資料項,就能大大減少節點數量,從而降低樹的高度
-
減少 I/O 讀寫次數
檔案系統及資料庫系統的設計者利用了 磁碟預讀原理,將一個節點的大小設為等於一個頁(通常大小為 4K)
這樣說,你可能沒有概念,舉個例子:將樹的度 M 設定為 1024 ,在 600 億個元素中最多隻需要 4 次 I/O 操作就可以讀取到想要的元素。
B 樹(B+ )廣泛應用於檔案儲存系統以及資料庫系統中。
什麼是 度?
- 節點的度:一個節點下的子樹節點個數就是 節點的度。
- 樹的度:指一顆樹中,節點的度最大的哪一個值。
B 樹其實就是前面所說的 多叉樹
樹
2-3 樹
2-3 樹是最簡單的 B 樹結構,具有如下特點:
-
所有 葉子節點 都在同一層
只要是 B 樹都滿足這個條件,就是滿樹。
-
有兩個子節點的節點叫 二節點
二節點要麼 沒有子節點,要麼 必須有兩個子節點
-
有三個子節點的節點叫 三節點
三節點要麼 沒有子節點,要麼 必須有三個子節點。
-
2-3 樹是由 二節點 和 三節點 構成的樹
2-3 樹構建圖解
對數列 {16, 24, 12, 32, 14, 26, 34, 10, 8, 28, 38, 20}
構建成一個 2-3 樹,那麼它構建的規則要滿足前面說的特點。下面進行圖解後,你就明白,上面的特點是如何限制的。
有幾個額外的注意事項:
- 一個節點中,最多隻允許放 2 個數據。
- 構建的樹必須是有序的,也就是按照二叉排序(BST)的要求構建有序的樹
下面是圖解步驟:
- 新增 16、24
新增 16 時,沒有資料,直接新建一個節點,放進去。
新增 24 時,發現有一個節點了,並且比 16 大,此時該節點中只有一個數據,則將 24 放在 16 的右邊。
- 新增 12
此時會發現,12 比 16 小,本來應該放在 16 的左邊,此時發現這個節點 已經有兩個資料了,那麼就只能放在 左子節點 。
如果直接將 12 放到 16,24
的左節點,就會破壞 2-3 樹的條件:2 節點,要麼沒有子節點,要麼有兩個。
那麼此時就只能將 16,24
這個節點進行拆分。如上圖:24 變成 16 的右節點,12 變成 16 的左節點。這時就滿足了 2-3 的特性。
-
新增 32
這個就簡單了,以現在的樹結構,可以直接新增到 24 的 右邊,變成
24,32
-
新增 14
這個也簡單,直接新增到 12 的右邊,變成
12,14
-
新增 26
此時應該新增到
24,32
的中間,由於一個節點只能新增兩個資料,那麼就需要拆分。
為了滿足 B 樹特點,發現上層的 16
只有一個數,那麼就補足它。組成 16,26
。
因為此時 24,32
這個節點,不滿足 BST 的排序了,24 是小於 26 的。只有 32 滿足。
拆完上層,再拆本層:由於 24 介於 16,26
之間,則將它安排在 3 節點中的中間節點,24,32
把 24 拆分出去了,只剩下 32
,此時完全滿足 B 樹的特點。
-
新增 34
此時就簡單了,新增到
32,34
中
-
新增 10
此時應該新增到
12,14
的左側。但是不滿足條件:一個節點最多隻能裝 2 個數據。放到
12,14
的左節點,也不滿足條件:所有葉子節點必須在同一層、也不滿足 2-3 節點的數量要求。那麼此時就需要拆分,先看他的上層
16,26
是滿的,如何做呢?看下圖:
左側的拆分圖,上面我們分析過了,不滿足 B 樹要求。那麼就需要拆分成右圖這樣:
-
將
12,14
中的 14 拆分成 右子節點,10 掛在 左節點。 -
此時不滿足 B 樹要求的,則將
16,26
中的 26 拆分成 右子節點。 -
24
這個節點由於上層被拆分了,不滿足在中間節點了。調整它的位置 -
原來的
32,34
節點調整為16
的右節點。 -
新增 8
此時很簡單,組成
8,10
即可
-
新增 28
-
新增 38
此時就簡單,直接組成
34,38
-
新增 20
這個也簡單,直接組成
20,24
2-3 樹新增規則總結
滿足如下特點:
-
所有 葉子節點 都在同一層
只要是 B 樹都滿足這個條件,就是滿樹。
-
有兩個子節點的節點叫 二節點
二節點要麼 沒有子節點,要麼 必須有兩個子節點。
-
有三個子節點的節點叫 三節點
三節點要麼 沒有子節點,要麼 必須有三個子節點。
-
2-3 樹是由 二節點 和 三節點 構成的樹
-
構建的樹,要滿足二叉排序樹(BST) 的順序
-
一個節點中,最多隻允許放 2 個數據。
-
只有一個數據的節點,下面只允許 最多有 2 個節點,要麼沒有
-
有 2 個數據的節點,下面只允許 最多有 3 個節點,要麼沒有
234 樹
除了 2-3 樹,還有 2-3-4 樹,他的特點是在 2-3 樹的基礎上,還多了一個 4 節點,同樣,一個節點最多可以裝 3 個數據,要麼有 4 個節點,要麼沒有
B樹、B+樹、B*樹
B樹
B-tree
樹即 B 樹,B 是 Balanced
平衡的意思。B-
樹,這個也是 B 樹,只是翻譯的文字容易產生誤解。
上圖就是一個 B 樹,說明如下:
-
B 樹的階:節點的最多 子節點 個數
如:2-3 樹的階是 3,2-3-4 樹的階是 4
-
B 樹的搜尋
從 根節點開始,對節點內的關鍵字(有序)序列進行二分查詢,如果命中則結束,否則進入查詢關鍵字所屬範圍的 兒子節點。
然後重複,直到所對應的兒子節點指標為空,或則已經是葉子節點。
-
關鍵字集合分佈在整棵樹中
即:葉子節點和非葉子節點都存放資料
-
搜尋有可能在非葉子節點結束
-
其搜尋效能等價於在關鍵字全集內做一次二分查詢
B + 樹
在 MySQL 中,有些索引就是用 B 樹或則 B+ 樹實現的。B+ 樹是 B 樹的變體,也是一種多路搜尋樹。
B + 樹說明:
-
B+ 樹的搜尋與 B 樹基本相同,區別是 B+ 樹只有到達葉子節點才命中(B 樹可以在非葉子節點命中),其效能也等價於在關鍵字全集做一次二分查詢
-
所有 關鍵字都出現在葉子節點的連結串列中
即:資料只能在葉子節點,也叫 稠密索引,且連結串列中的關鍵字(資料)恰好是有序的。
-
不可能在非葉子節點命中
-
非葉子節點相當於是葉子節點的索引,也叫 稀疏索引,葉子節點相當於是儲存(關鍵字)資料的資料層
-
更適合檔案索引系統
-
B 樹和 B+ 樹有各自的應用場景,不能說 B+ 樹完全比 B 樹好。
B+ 樹的這種設計,應該是類似分段思想,比如:5,28,65
,下面存放三個節點:
5-28
的段,為一個節點28-65
的段,為一個節點65
以上的段,為一個節點
比如查詢 30 ,直接找到在第二個節點中,然後往下一個目錄索引找,就很快能定位到資料。
B*
樹
B*
樹是 B+ 樹的變體,在 B+ 樹的非根和非葉子節點再增加指向兄弟的指標
說明:
-
B*
樹定義了 非葉子節點 關鍵字個數至少為(2/3)*M
,即塊的最低使用率為2/3
,而 B+ 樹的塊的最低使用率為 B+ 樹的1/2
M 是指樹的度,也就是層。
-
從第 1 個特點,可以看出
B*
樹分配新節點的概率比 B+ 樹要低,空間使用率更高。