理論基礎 —— 索引 —— B 樹、B+ 樹與 B* 樹

【B 樹】

B 樹(B-Tree)也寫作 B-樹,其是一種平衡的多路查找樹,主要面向於動態查找,常用於文件系統中。

B 樹中,結點最大的孩子數目稱爲 B 樹的階,2-3 樹是 B 樹的特例,其是 3 階 B 樹。

B 樹的查找、插入、刪除操作與 2-3 樹相似。 

一棵 m 階的 B 樹或爲空樹,或爲滿足以下性質的 m 叉樹:

  • 所有的葉結點都出現在同一層,且不帶信息
  • 樹中每個結點最多有 m 棵子樹
  • 葉結點的父結點稱爲終端結點,若根結點不是終端結點,則至少有兩棵子樹
  • 除根結點外的所有非終端結點至少有 \left \lceil \frac{m}{2} \right \rceil 棵子樹
  • 所有的非終端結點都包括數據:\{n,A_0,K_1,A_1,K_2,...,K_n,A_n\},其中 n 爲關鍵碼個數,Ki 爲關鍵碼,Ai 爲指向子樹根結點的指針,且指針 Ai 所指子樹中所有結點的關鍵碼均小於 K_{i+1} 大於 Ki

一般情況下,B 樹的葉結點可以看做外部結點,即查找失敗的點,實際上這些結點並不存在,指向這些結點的指針爲空。

因此,B 樹的葉結點可以不畫出來,由於葉子都出現在一層上行,所以 B 樹也是樹高平衡的,此外,B 樹中每個結點中關鍵碼的個數爲子樹個數 -1

如下圖,是一個 3 階 B 樹。

在實際應用中,常使得 B 樹的階數與磁盤存儲的頁面大小匹配。

例如一棵 B 樹的階爲 1001,即 1 個結點包含 1000 個關鍵字,高度爲 2,其可以存儲超過 10 億個關鍵字,只要讓根結點持久地保留在內存中,那麼在這棵樹上,尋找某一關鍵字至多需要兩次硬盤的讀取。

通過這種方式,在有限內存的情況下,每一次磁盤訪問都可以獲取大量的數據,這極大的減少了內存外存交換數據次數的頻率,提高了時間效率,可以說,B 樹的數據結構就是爲了內外存交換而準備的。

【B+ 樹】

B+ 樹是 B 樹的變形樹,嚴格意義上來講,其已經不是一棵樹了。

在 B 樹中,每一元素在該樹中只出現一次,有可能在葉結點上,也有可能在分支結點上,而在 B+ 樹中,出現在分支結點中的元素會被當作他們在該分支結點位置的中序後繼者中再次列出,此外,每一葉結點都會保存一個指向後一葉結點的指針

一棵 m 階的 B+ 樹與一棵 m 階的 B 樹差異在於:

  • 在 n 棵子樹中包含有 n 個關鍵字
  • 所有分支結點可看作是索引,結點中僅含有其子樹中最大/最小的關鍵字
  • 所有葉結點包含全部關鍵字信息,以及指向這些關鍵字記錄的指針,葉結點本身依關鍵字的大小自大到小順序連接

如下圖,是一個 3 階 B+ 樹。

B+ 樹的數據結構好處在於,只要是隨機查找,就從根結點出發進行查找,只不過在分支結點找到了待查找的關鍵字,其也只是用於索引的,不能提供實際記錄的訪問,仍需到達包含此關鍵字的終端結點。此外,B+ 樹的結構特別適合帶有範圍的查找。

B+ 樹的插入、刪除過程與 B 樹類似,不過插入、刪除的元素都在葉結點上進行。

【B* 樹】

B* 樹是 B+ 樹的變形樹,其也非嚴格意義上的樹。

B*  樹在 B+ 樹的基礎上進行了改進,在 B+ 樹的非根和非葉子結點上行增加了指向兄弟的指針,且規定非葉結點關鍵字個數至少爲 \frac{2}{3} m,即塊的最低使用率爲 2/3(B+ 樹只有 1/2),可以看出,B* 樹分配結點的概率要比 B+ 樹低,空間利用率更高。