樹結構學習:B樹、B+樹

平衡二叉樹的查找效率是非常高的,並可以通過降低樹的深度來提高查找的效率。但是當數據量非常大,樹的存儲的元素數量是有限的,這樣會導致二叉查找樹結構由於樹的深度過大而造成磁盤 I/O 讀寫過於頻繁,進而導致查詢效率低下。

而 B 樹的出現是爲了解決這個問題,其可以一次性讀入許多數據。一個節點不再只是存儲一個數值,而是存儲一個分片的數據。這樣就可以避免頻繁去讀取磁盤數據,造成頻繁的 IO 訪問,造成查找速度瓶頸。

B樹

B-Tree 其實就是 B 樹,很多人都會說成 B 減樹,其實是錯的,要注意。

B 樹不要和二叉樹混淆,B 樹不是二叉樹,而是一種自平衡樹數據結構。 它維護有序數據並允許以對數時間進行搜索,順序訪問,插入和刪除。B 樹是二叉搜索樹的一般化,因爲 B 樹的節點可以有兩個以上的子節點。

與其他自平衡二進制搜索樹不同,B 樹非常適合讀取和寫入相對較大的數據塊(如光盤)的存儲系統。它通常用於數據庫和文件系統,例如 mysql 的 InnoDB 引擎使用的數據結構就是 B 樹的變形 B+ 樹。

B 樹是一種平衡的多分樹,通常我們說 m 階的 B 樹,它必須滿足如下條件:

  • 每個節點最多隻有 m 個子節點。
  • 每個非葉子節點(除了根)具有至少 ⌈m/2⌉ 子節點。
  • 如果根不是葉節點,則根至少有兩個子節點。
  • 具有 k 個子節點的非葉節點包含 k -1 個鍵。
  • 所有葉子都出現在同一水平,沒有任何信息(高度一致)。

B 樹的階,指的是 B 樹中節點的子節點數目的最大值。例如在上圖的書中,「13,16,19」擁有的子節點數目最多,一共有四個子節點(灰色節點)。所以該 B 樹的階爲 4,該樹稱爲 4 階 B 樹。在實際應用中,B 樹應用於 MongoDb 的索引。

B+樹

B+ 樹是應文件系統所需而產生的 B 樹的變形樹。B+ 樹的特徵:

  • 有 m 個子樹的中間節點包含有 m 個元素(B 樹中是 k-1 個元素),每個元素不保存數據,只用來索引。
  • 所有的葉子結點中包含了全部關鍵字的信息,及指向含有這些關鍵字記錄的指針,且葉子結點本身依關鍵字的大小自小而大的順序鏈接。而 B 樹的葉子節點並沒有包括全部需要查找的信息。
  • 所有的非終端結點可以看成是索引部分,結點中僅含有其子樹根結點中最大(或最小)關鍵字。而 B 樹的非終節點也包含需要查找的有效信息。例如下圖中的根節點 8 是左子樹中最大的元素,15 是右子樹中最大的元素。

與 B 樹相比,B+ 樹有着如下的好處:

  1. B+ 樹的磁盤讀寫代價更低

B+ 樹的內部結點並沒有指向關鍵字具體信息的指針,所以其內部結點相對 B 樹更小。如果把所有同一內部結點的關鍵字存放在同一盤塊中,那麼盤塊所能容納的關鍵字數量也越多,所以一次性讀入內存中的需要查找的關鍵字也就越多。相對來說 IO 讀寫次數也就降低了,查找速度就更快了。

  1. B+ 樹查詢效率更加穩定

由於非終結點並不是最終指向文件內容的結點,而只是葉子結點中關鍵字的索引。所以 B+ 樹中任何關鍵字的查找必須走一條從根結點到葉子結點的路。所有關鍵字查詢的路徑長度相同,導致每一個數據的查詢效率相當。而對於 B 樹來說,因爲其每個節點都存具體的數據,因此其查詢速度可能更快,但是卻並不穩定。

  1. B+ 樹便於範圍查詢(最重要的原因,範圍查找是數據庫的常態)

B 樹在提高了 IO 性能的同時,並沒有解決元素遍歷效率低下的問題。爲了解決這個問題,B+ 樹應用而生。B+ 樹只需要去遍歷葉子節點就可以實現整棵樹的遍歷。在數據庫中基於範圍的查詢是非常頻繁的,因此 MySQL 的 Innodb 引擎就使用了 B+ 樹作爲其索引的數據結構。

總結

B 樹是爲了解決大數據量的查找問題而誕生的,其實二叉搜索樹的一般化。通過每個節點存儲更多的數據,使得 B 樹比起二叉搜索樹更加扁平化,從而減少 IO 讀取頻次,提高搜索速度。

B+ 樹比起 B 樹,最大的差異是非葉子節點不再存儲具體數據,以及葉子節點是鏈表結構。非葉子節點不再存儲具體數據,這使得 B+ 樹更加扁平化,查找效率更高。葉子節點是鏈表結構,這使得 B+ 樹更適合用在範圍查找的場景中。

學到這裏,我們的樹結構大道基本上學完了,來整體溫習一下吧。

參考資料

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