B+ 樹的簡單認識

程式設計師翔仔發表於2022-06-12

B+ 樹的概念

基本概念

B+ 樹是 B 樹的一種變體,從某個程度上看,B+ 樹可以認定是 B 樹的升級版。

在 B+ 樹中,關鍵字只儲存在葉子結點,非葉子結點儲存的是葉子結點所儲存關鍵字的部分拷貝,所有的葉子結點也都在相同的高度,葉子結點本身按關鍵字大小從小到大連結。

因此,相對於 B 樹而言,B+ 樹更充分地利用了結點的空間,讓查詢速度更加穩定,其速度完全接近於二分查詢。

B+ 樹結構

特性

B+ 樹擁有 B 樹的大部分特性,但也具有獨特的、與 B 樹不同的特性,不同的地方有以下兩點:

  • B+ 樹的非葉子結點不直接儲存資料的指標,所有資料的指標都儲存在葉子結點
  • B+ 樹葉子結點儲存的資料從小到大有序排列,且相鄰葉子結點之間具有連結

與 B 樹的區別

與 B 樹相比較,B+ 樹具有以下特點:

  • B+ 樹的非葉子結點不直接儲存資料,儲存的索引更多,樹的層級更少,查詢的速度更快
  • B+ 樹所有資料的指標都儲存在葉子結點,因此每次查詢到資料的次數都相同,查詢速度更穩定
  • B+ 樹所有的葉子結點之間具有連結,構成了一個有序連結串列,查詢範圍區間的資料更方便
  • B+ 樹遍歷所有資料時只需要遍歷所有葉子結點即可,相對 B 樹遍歷更快

為什麼使用 B+ 樹作為索引結構?

索引的本質是一種用於快速查詢記錄的資料結構,常見有二叉查詢樹、平衡二叉樹、雜湊表、B 樹和 B+ 樹等索引儲存結構。

每一種索引結構都有其對應的應用場景,易用性也是選擇的標準之一,這裡討論一下為什麼選用 B+ 樹作為索引儲存結構。

為什麼不採用二叉查詢樹?

二叉查詢樹索引

使用普通的二叉樹查詢作為索引結構具有一個致命的問題:當一直插入資料的時候,有可能會退化成連結串列結構,時間複雜度也會從 \(O(\log n)\) 退化到 \(O(n)\)

因此,普通的二叉查詢樹比較適合資料基本沒有變動的情況,這樣查詢效率不會發生較大的變化。

為什麼不採用平衡二叉樹?

平衡二叉樹索引

為了解決普通二叉查詢樹有可能退化成連結串列的問題,可以使用自平衡的二叉查詢樹代替,如 AVL 樹、紅黑樹等。

紅黑樹常見的一種自平衡二叉查詢樹,但是也有一個問題:紅黑樹是一個近似平衡的二叉樹,當資料量較大的時候,會出現樹層級較大的情況。

當資料量非常大時,索引佔用的空間也會非常大,索引還是得儲存在磁碟上,如果樹的層級較大,則進行磁碟 IO 的次數就會越多,效能就會越差。

因此,紅黑樹不適合作為儲存在磁碟上的索引結構。

為什麼不採用雜湊表?

雜湊表是一個支援快速查詢的資料結構,其查詢的時間複雜度是 \(O(1)\),其也是最常見的索引儲存結構之一。

但是雜湊表也有其缺點,就是隻儲存鍵值對應關係的雜湊表不支援範圍查詢,如果要做範圍查詢,需要做全量的資料掃描才行。

當然,如果是具有排序功能的雜湊表,會非常適合作為儲存在記憶體中的索引結果,如 Java 中的 TreeMap 物件。

為什麼不採用 B 樹?

使用 B 樹可以解決紅黑樹層級較大的問題,通過一個結點可以儲存多個元素,樹變得更加矮胖,使得樹的層級變得可控。

而且,通過給一個結點儲存一頁的資料量,最大化地優化作業系統和磁碟的互動,解決了多次磁碟 IO 的問題。

但是對應 B+ 樹而言,B 樹的層級仍然會比 B+ 樹的高,且範圍查詢沒有 B+ 樹方便,這是捨棄 B 樹而選擇 B+ 樹的主要原因。

當然,也有使用 B 樹作為索引結構的資料庫,如 MongoDB 等。

相關文章