B+树和B*树详解
B+樹和B*樹詳解
文章目錄
- B+樹和B*樹詳解
- 一、B+樹
- 1.B+樹的定義
- 2.性質(zhì)
- 3. B+樹的插入操作
- 4.B+樹的刪除操作
- 二、B*樹
- 1.概念
- 2.性質(zhì)
- 3.總結(jié)
- 1.B-/B樹:
- 2.B+樹:
- 3.B*樹:
一、B+樹
1.B+樹的定義
2.性質(zhì)
B+樹是B樹的變體,也是一種多路搜索樹,除了:
- 1)B+樹包含2種類型的結(jié)點:內(nèi)部結(jié)點(也稱索引結(jié)點)和葉子結(jié)點。根結(jié)點本身即可以是內(nèi)部結(jié)點,也可以是葉子結(jié)點。根結(jié)點的關(guān)鍵字個數(shù)最少可以只有1個。
- 2)B+樹與B樹最大的不同是內(nèi)部結(jié)點不保存數(shù)據(jù),只用于索引,所有數(shù)據(jù)(或者說記錄)都保存在葉子結(jié)點中。
- 3) m階B+樹表示了內(nèi)部結(jié)點最多有m-1個關(guān)鍵字(或者說內(nèi)部結(jié)點最多有m個子樹),階數(shù)m同時限制了葉子結(jié)點最多存儲m-1個記錄。
- 4)內(nèi)部結(jié)點中的key都按照從小到大的順序排列,對于內(nèi)部結(jié)點中的一個key,左樹中的所有key都小于它,右子樹中的key都大于等于它。葉子結(jié)點中的記錄也按照key的大小排列。
- 5)每個葉子結(jié)點都存有相鄰葉子結(jié)點的指針,葉子結(jié)點本身依關(guān)鍵字的大小自小而大順序鏈接。
3. B+樹的插入操作
-
1)若為空樹,創(chuàng)建一個葉子結(jié)點,然后將記錄插入其中,此時這個葉子結(jié)點也是根結(jié)點,插入操作結(jié)束。
-
2)針對葉子類型結(jié)點:根據(jù)key值找到葉子結(jié)點,向這個葉子結(jié)點插入記錄。插入后,若當(dāng)前結(jié)點key的個數(shù)小于等于m-1,則插入結(jié)束。
-
否則將這個葉子結(jié)點分裂成左右兩個葉子結(jié)點,左葉子結(jié)點包含前m/2個記錄,右結(jié)點包含剩下的記錄,將第m/2+1個記錄的key進位到父結(jié)點中(父結(jié)點一定是索引類型結(jié)點),進位到父結(jié)點的key左孩子指針向左結(jié)點,右孩子指針向右結(jié)點。將當(dāng)前結(jié)點的指針指向父結(jié)點,然后執(zhí)行第3步。
-
3)針對索引類型結(jié)點:若當(dāng)前結(jié)點key的個數(shù)小于等于m-1,則插入結(jié)束。
-
否則,將這個索引類型結(jié)點分裂成兩個索引結(jié)點,左索引結(jié)點包含前(m-1)/2個key,右結(jié)點包含m-(m-1)/2個key,將第m/2個key進位到父結(jié)點中,進位到父結(jié)點的key左孩子指向左結(jié)點, 進位到父結(jié)點的key右孩子指向右結(jié)點。將當(dāng)前結(jié)點的指針指向父結(jié)點,然后重復(fù)第3步。
-
下面是一顆5階B樹的插入過程,5階B數(shù)的結(jié)點最少2個key,最多4個key。
-
a)空樹中插入5
-
b)依次插入8,10,15
-
c)插入16
-
插入16后超過了關(guān)鍵字的個數(shù)限制,所以要進行分裂。在葉子結(jié)點分裂時,分裂出來的左結(jié)點2個記錄,右邊3個記錄,中間key成為索引結(jié)點中的key,分裂后當(dāng)前結(jié)點指向了父結(jié)點(根結(jié)點)。結(jié)果如下圖所示。
當(dāng)然我們還有另一種分裂方式,給左結(jié)點3個記錄,右結(jié)點2個記錄,此時索引結(jié)點中的key就變?yōu)?5。 -
d)插入17
-
e)插入18,插入后如下圖所示
-
當(dāng)前結(jié)點的關(guān)鍵字個數(shù)大于5,進行分裂。分裂成兩個結(jié)點,左結(jié)點2個記錄,右結(jié)點3個記錄,關(guān)鍵字16進位到父結(jié)點(索引類型)中,將當(dāng)前結(jié)點的指針指向父結(jié)點。
當(dāng)前結(jié)點的關(guān)鍵字個數(shù)滿足條件,插入結(jié)束。 -
f)插入若干數(shù)據(jù)后
-
g)在上圖中插入7,結(jié)果如下圖所示
-
當(dāng)前結(jié)點的關(guān)鍵字個數(shù)超過4,需要分裂。左結(jié)點2個記錄,右結(jié)點3個記錄。分裂后關(guān)鍵字7進入到父結(jié)點中,將當(dāng)前結(jié)點的指針指向父結(jié)點,結(jié)果如下圖所示。
-
當(dāng)前結(jié)點的關(guān)鍵字個數(shù)超過4,需要繼續(xù)分裂。左結(jié)點2個關(guān)鍵字,右結(jié)點2個關(guān)鍵字,關(guān)鍵字16進入到父結(jié)點中,將當(dāng)前結(jié)點指向父結(jié)點,結(jié)果如下圖所示。
當(dāng)前結(jié)點的關(guān)鍵字個數(shù)滿足條件,插入結(jié)束。
4.B+樹的刪除操作
- 如果葉子結(jié)點中沒有相應(yīng)的key,則刪除失敗。否則執(zhí)行下面的步驟
- 1)刪除葉子結(jié)點中對應(yīng)的key。刪除后若結(jié)點的key的個數(shù)大于等于Math.ceil(m-1)/2 – 1,刪除操作結(jié)束,否則執(zhí)行第2步。
- 2)若兄弟結(jié)點key有富余(大于Math.ceil(m-1)/2 – 1),向兄弟結(jié)點借一個記錄,同時用借到的key替換父結(jié)(指當(dāng)前結(jié)點和兄弟結(jié)點共同的父結(jié)點)點中的key,刪除結(jié)束。否則執(zhí)行第3步。
- 3)若兄弟結(jié)點中沒有富余的key,則當(dāng)前結(jié)點和兄弟結(jié)點合并成一個新的葉子結(jié)點,并刪除父結(jié)點中的key(父結(jié)點中的這個key兩邊的孩子指針就變成了一個指針,正好指向這個新的葉子結(jié)點),將當(dāng)前結(jié)點指向父結(jié)點(必為索引結(jié)點),執(zhí)行第4步(第4步以后的操作和B樹就完全一樣了,主要是為了更新索引結(jié)點)。
- 4)若索引結(jié)點的key的個數(shù)大于等于Math.ceil(m-1)/2 – 1,則刪除操作結(jié)束。否則執(zhí)行第5步
- 5)若兄弟結(jié)點有富余,父結(jié)點key下移,兄弟結(jié)點key上移,刪除結(jié)束。否則執(zhí)行第6步
- 6)當(dāng)前結(jié)點和兄弟結(jié)點及父結(jié)點下移key合并成一個新的結(jié)點。將當(dāng)前結(jié)點指向父結(jié)點,重復(fù)第4步。
注意,通過B+樹的刪除操作后,索引結(jié)點中存在的key,不一定在葉子結(jié)點中存在對應(yīng)的記錄。
- 下面是一顆5階B樹的刪除過程,5階B數(shù)的結(jié)點最少2個key,最多4個key。
- a)初始狀態(tài)
- b)刪除22,刪除后結(jié)果如下圖
刪除后葉子結(jié)點中key的個數(shù)大于等于2,刪除結(jié)束 - c)刪除15,刪除后的結(jié)果如下圖所示
- 刪除后當(dāng)前結(jié)點只有一個key,不滿足條件,而兄弟結(jié)點有三個key,可以從兄弟結(jié)點借一個關(guān)鍵字為9的記錄,同時更新將父結(jié)點中的關(guān)鍵字由10也變?yōu)?,刪除結(jié)束。
- d)刪除7,刪除后的結(jié)果如下圖所示
- 當(dāng)前結(jié)點關(guān)鍵字個數(shù)小于2,(左)兄弟結(jié)點中的也沒有富余的關(guān)鍵字(當(dāng)前結(jié)點還有個右兄弟,不過選擇任意一個進行分析就可以了,這里我們選擇了左邊的),所以當(dāng)前結(jié)點和兄弟結(jié)點合并,并刪除父結(jié)點中的key,當(dāng)前結(jié)點指向父結(jié)點。
- 此時當(dāng)前結(jié)點的關(guān)鍵字個數(shù)小于2,兄弟結(jié)點的關(guān)鍵字也沒有富余,所以父結(jié)點中的關(guān)鍵字下移,和兩個孩子結(jié)點合并,結(jié)果如下圖所示。
二、B*樹
1.概念
是B+樹的變體,在B+樹的非根和非葉子結(jié)點再增加指向兄弟的指針;
2.性質(zhì)
- B*樹定義了非葉子結(jié)點關(guān)鍵字個數(shù)至少為(2/3)*M,即塊的最低使用率為2/3(代替B+樹的1/2);
- B+樹的分裂:當(dāng)一個結(jié)點滿時,分配一個新的結(jié)點,并將原結(jié)點中1/2的數(shù)據(jù)復(fù)制到新結(jié)點,最后在父結(jié)點中增加新結(jié)點的指針;
- B+樹的分裂只影響原結(jié)點和父結(jié)點,而不會影響兄弟結(jié)點,所以它不需要指向兄弟的指針;
- B*樹的分裂:當(dāng)一個結(jié)點滿時,如果它的下一個兄弟結(jié)點未滿,那么將一部分?jǐn)?shù)據(jù)移到兄弟結(jié)點中,再在原結(jié)點插入關(guān)鍵字,最后修改父結(jié)點中兄弟結(jié)點的關(guān)鍵字(因為兄弟結(jié)點的關(guān)鍵字范圍改變了);
- 如果兄弟也滿了,則在原結(jié)點與兄弟結(jié)點之間增加新結(jié)點,并各復(fù)制1/3的數(shù)據(jù)到新結(jié)點,最后在父結(jié)點增加新結(jié)點的指針;
- 所以,B*樹分配新結(jié)點的概率比B+樹要低,空間使用率更高;
3.總結(jié)
1.B-/B樹:
關(guān)鍵字的數(shù)量比孩子的數(shù)量少一,M階的B-/B樹最多有M個孩子,M- 1個關(guān)鍵字。分裂的方式把關(guān)鍵字已經(jīng)滿的節(jié)點中的數(shù)據(jù)移動1/2到另一個節(jié)點
2.B+樹:
B+樹中關(guān)鍵字的數(shù)量和孩子的數(shù)量相等,在B-樹基礎(chǔ)上,為葉子結(jié)點增加鏈表指針,所有關(guān)鍵字都在葉子結(jié)點中出現(xiàn),非葉子結(jié)點作為葉子結(jié)點的索引,遍歷葉子節(jié)點就可以得到所有的數(shù)據(jù);B+樹總是到葉子結(jié)點才命中。M階的B+樹一個節(jié)點最少有M/ 2個關(guān)鍵字。分裂的方式把關(guān)鍵字已經(jīng)滿的節(jié)點中的數(shù)據(jù)拷貝1/2到另一個新節(jié)點
3.B*樹:
在B+樹基礎(chǔ)上,為非葉子結(jié)點也增加鏈表指針,M階的B樹一個節(jié)點最少有M 2/3 個關(guān)鍵字,將結(jié)點空間的最低利用率從1/2提高到2/3。分裂的方式是:如果它的下一個兄弟節(jié)點的關(guān)鍵字沒滿,就把關(guān)鍵字已經(jīng)滿的節(jié)點中的數(shù)據(jù)移動到兄弟節(jié)點當(dāng)中;如果兄弟節(jié)點也滿了,就在二者之間增加新節(jié)點,各復(fù)制1/3的數(shù)據(jù)到新節(jié)點當(dāng)中
總結(jié)