你好,我是B樹

WindWant發表於2021-07-21

一、什麼是B樹?

B樹是一棵是具備以下特點的有根樹

1、節點屬性

a)x.n:為節點中儲存的關鍵字個數

b)x.key:為節點中儲存的關鍵字。x.key1、x.key2 ... x.keyx.n 非降序順序排列,滿足 x.key<= x.key2 ... <= x.keyx.n。

c)x.leaf:為當前節點是否為葉子節點(true | false)

d)x.c:為指向子節點的指標,內部節點包含指標個數為 x.n + 1,葉子節點沒有子節點,所以沒有此屬性。

2、分割

關鍵字 x.key 對儲存在子樹中的關鍵字進行分割。某個子節點的所有關鍵字值範圍總是在節點 x 的某兩個關鍵字之間。這個值可能是任何可排序的表示,比如:

3、深度

每個葉子節點具有相同的深度,即樹的高度(由根節點到葉子節點的路徑長度)。

4、度數

每個節點包含的關鍵字個數有上下界限制。基本表示單位為B樹的最小度數 t(滿足 t >= 2):

a)除了根節點外(空樹沒有關鍵字,非空樹根節點至少包含一個關鍵字),每個節點至少有 t - 1 個關鍵字,進而可以推導,每個內部節點至少有 t 個子節點【1.d】。

b)每個節點至多包含 2t - 1 個關鍵字(此時稱之為【滿】 狀態),進而可以推導,每個內部節點至多有 2t 個子節點【1.d】。

二、B數的高度

首先樹的根節點至少包含 1 個關鍵字,其它節點至少包含 t - 1 個關鍵字,至少有 t 個子節點【一.4.a】。

我們知道 B 樹的度數 t >= 2,所以:

深度為 1 的位置上至少有 2 個節點。

深度為 2 的位置至少有 2 * t 個 節點。

深度為 3 的位置至少有 2 * t * t 個 節點。

... ...

深度為 h 的位置至少有 2 * t * ... * t 個 節點。

圖示:

【1】所以所有非根節點個數至少為:2 + 2 * t +  2 * t * t  + 2 * t * ... * t = 2 * t0 + 2 * t1+  2 * t2  + 2 * th-1,標識為 sum(node)

【2】相應的非根節點關鍵字個數至少為:(t - 1) * sum(node)

【3】那麼總的關鍵字個數至少為: 1 + (t - 1) * sum(node)

【4】我們用 n 表示關鍵字個數,所以存在  n >= 1 + (t - 1) * sum(node),代入【1】中的求和,最終經過一系列的變換,可以得出B樹的高度滿足:h <= logt(n+1)/2

三、B樹的搜尋

假定我們要查詢的關鍵字為 k,入口節點 x:

a)需要找到 k 在 x 所有關鍵字中的位置,臨界關鍵字 keyi 滿足 k <= keyi

b)如果存在 k == keyi 那麼查詢結束,否則繼續。

c)如果 x 為葉子節點,則查詢結束,否則繼續

d)由 keyi 臨界關鍵字,我們可以得到相應指向子節點的指標 ci

然後,繼續由 ci 指向的子節點作為入口節點,繼續上述過程。

四、B樹的插入

B樹插入新關鍵字後,必須仍然是一顆合法的B樹。

由【一.4.b】我們直到 B 樹節點存在一種狀態【滿】,即當前節點關鍵字個數為 2t -1。【滿】狀態的節點插入新節點必須經過特定的前置處理:分裂

所謂分裂,即將節點由中間關鍵字作為分割點,分割為兩個節點,每個節點包含 t - 1 個關鍵字,中間節點 x.kt 則上升到父節點中,作為兩棵子樹的劃分點,參見【一.2】。

此處需要注意的是,如果父節點同樣為【滿】節點,那麼在分割點上升之前,同樣需要對父節點執行【分裂】操作。

滿節點的分裂行為會沿著樹向上傳播直到不再需要分裂為止

上面我們描述的過程,是一個自下而上的【滿】狀態分裂傳播行為。

我們知道,要實現節點的插入,首先需要經過一個B樹的搜尋查詢的過程,搜尋過程自上而下

顯然,兩個過程,有些重複,我們需要的是單向查詢插入。

鑑於此,在執行查詢的過程中,遇到路徑上的滿節點,則執行分裂操作,直到找到位置插入節點,這樣就避免了自下而上的【分裂】傳播行為。

五、B樹的刪除

B樹刪除特定關鍵字後,必須仍然是一顆合法的B樹。

B樹的插入是一個對節點最大關鍵字數量的約束滿足過程,相應的,B樹的刪除是一個對節點最小關鍵字數量的約束滿足過程

保障沿途節點關鍵字數量至少為度數 t,一遍自根而下執行刪除。

 

相關文章