B樹(shù)、B+樹(shù)、B*樹(shù)

說(shuō)起數(shù)據(jù)庫(kù),避免不了的要講索引。要真正理解索引,首先就得清楚B+樹(shù)的結(jié)構(gòu)等

B樹(shù)

B樹(shù)即B-樹(shù),而不是兩種樹(shù)。

概念:一棵m階B樹(shù)是一棵平衡的m路搜索樹(shù)。
特點(diǎn):

  • m即所有節(jié)點(diǎn)中孩子節(jié)點(diǎn)個(gè)數(shù)的最大值
  • 每個(gè)非根節(jié)點(diǎn)所包含的關(guān)鍵字個(gè)數(shù)j滿(mǎn)足:ceil(m/2) - 1 <= j <= m - 1(ceil為向上取整,即大于該數(shù)的最小整數(shù))
  • 節(jié)點(diǎn)的子節(jié)點(diǎn)數(shù)會(huì)比關(guān)鍵字個(gè)數(shù)加1
  • 根據(jù)以上兩條可以得出,每個(gè)節(jié)點(diǎn)最多有m個(gè)分支,非根非葉節(jié)點(diǎn)至少有ceil(m/2)個(gè)分支

B樹(shù)的查找

B樹(shù)的查找還是很簡(jiǎn)單的,不再贅述。

其最低搜索性能:

B樹(shù)的插入

例:用1,2,6,7,11,4,8,13,10,5,17,9,16,20,3,12,14,18,19,15構(gòu)建5階B樹(shù)

因?yàn)闃?gòu)建5階的B樹(shù),所以每個(gè)節(jié)點(diǎn)的關(guān)鍵字個(gè)數(shù)范圍為[2,4]

插入11時(shí),該節(jié)點(diǎn)的關(guān)鍵字個(gè)數(shù)超出范圍,進(jìn)行分裂

之后直接插入4,8,13

當(dāng)插入10時(shí),節(jié)點(diǎn)關(guān)鍵字個(gè)數(shù)再次超出范圍

將子節(jié)點(diǎn)分裂

直接插入5,17,9,16,插入20

關(guān)鍵字個(gè)數(shù)超出范圍,進(jìn)行分裂

繼續(xù)插入3

關(guān)鍵字個(gè)數(shù)超出范圍,進(jìn)行分裂

繼續(xù)插入15

關(guān)鍵個(gè)數(shù)超出范圍,進(jìn)行分裂

這時(shí)候根節(jié)點(diǎn)關(guān)鍵字個(gè)數(shù)也超出范圍,繼續(xù)分裂

B樹(shù)的刪除

對(duì)于B-樹(shù)關(guān)鍵字的刪除,需要找到待刪除的關(guān)鍵字,在結(jié)點(diǎn)中刪除關(guān)鍵字的過(guò)程也有可能破壞B-樹(shù)的特性,如舊關(guān)鍵字的刪除可能使得結(jié)點(diǎn)中關(guān)鍵字的個(gè)數(shù)少于規(guī)定個(gè)數(shù),這是可能需要向其兄弟結(jié)點(diǎn)借關(guān)鍵字或者和其孩子結(jié)點(diǎn)進(jìn)行關(guān)鍵字的交換,也可能需要進(jìn)行結(jié)點(diǎn)的合并,其中,和當(dāng)前結(jié)點(diǎn)的孩子進(jìn)行關(guān)鍵字交換的操作可以保證刪除操作總是發(fā)生在終端結(jié)點(diǎn)上。

從上面已經(jīng)構(gòu)建好的B樹(shù)中依次刪除8,16,15,4

刪除8:關(guān)鍵字8在葉子節(jié)點(diǎn)上,并且刪除后其所在結(jié)點(diǎn)中關(guān)鍵字的個(gè)數(shù)不會(huì)少于2,因此可以直接刪除。


刪除16:關(guān)鍵字16不在終端結(jié)點(diǎn)上,但是可以用17來(lái)覆蓋16,然后將原來(lái)的17刪除掉


刪除15:15雖然也在終端結(jié)點(diǎn)上,但是不能直接刪除,因?yàn)閯h除后當(dāng)前結(jié)點(diǎn)中關(guān)鍵字的個(gè)數(shù)小于2。這時(shí)需要向其兄弟結(jié)點(diǎn)借關(guān)鍵字,顯然應(yīng)該向其右兄弟來(lái)借關(guān)鍵字,因?yàn)樽笮值艿年P(guān)鍵字個(gè)數(shù)已經(jīng)是下限2.借關(guān)鍵字不能直接將18移到15所在的結(jié)點(diǎn)上,因?yàn)檫@樣會(huì)使得15所在的結(jié)點(diǎn)上出現(xiàn)比17大的關(guān)鍵字,所以正確的借法應(yīng)該是先用17覆蓋15,在用18覆蓋原來(lái)的17,最后刪除原來(lái)的18


刪除4:4在葉子節(jié)點(diǎn)上,但是此時(shí)4所在的節(jié)點(diǎn)的關(guān)鍵字個(gè)數(shù)已經(jīng)到下限,需要借關(guān)鍵字,不過(guò)可以看到其左右兄弟節(jié)點(diǎn)已經(jīng)沒(méi)有多余的關(guān)鍵字可借。所以就需要進(jìn)行關(guān)鍵字的合并??梢韵葘㈥P(guān)鍵字4刪除,然后將關(guān)鍵字5、6、7、9進(jìn)行合并作為一個(gè)節(jié)點(diǎn)鏈接在關(guān)鍵字3右邊的指針上,也可以將關(guān)鍵字1、2、3、5合并作為一個(gè)節(jié)點(diǎn)鏈接在關(guān)鍵字6左邊的指針上

顯然上述兩種情況下都不滿(mǎn)足B-樹(shù)的規(guī)定,即出現(xiàn)了非根的雙分支節(jié)點(diǎn),需要繼續(xù)進(jìn)行合并

B+樹(shù)

一棵m階B+樹(shù)是一棵平衡的m路搜索樹(shù)

  • 有k個(gè)子樹(shù)的中間節(jié)點(diǎn)包含有k個(gè)元素(B樹(shù)中是k-1個(gè)元素),每個(gè)元素不保存數(shù)據(jù),只用來(lái)索引,所有數(shù)據(jù)都保存在葉子節(jié)點(diǎn)。
  • ceil(m/2) <= j <= m
  • 所有的葉子節(jié)點(diǎn)中包含了全部元素的信息,及指向含這些元素記錄的指針,且葉子結(jié)點(diǎn)本身依關(guān)鍵字的大小自小而大順序鏈接(葉子節(jié)點(diǎn)之間增加了橫向的指針)。
  • 所有的中間節(jié)點(diǎn)元素都同時(shí)存在于子節(jié)點(diǎn),在子節(jié)點(diǎn)元素中是最大(或最?。┰亍!驹谶@一點(diǎn)上有一些不同的說(shuō)法,其中一種說(shuō)法為,非葉子結(jié)點(diǎn)的子樹(shù)指針與關(guān)鍵字個(gè)數(shù)相同,非葉子結(jié)點(diǎn)的子樹(shù)指針P[i],指向關(guān)鍵字值屬于[K[i], K[i+1])的子樹(shù)(B-樹(shù)是開(kāi)區(qū)間)】

按不同的說(shuō)法,以上兩種形式的B+樹(shù)應(yīng)該都對(duì)

B+的搜索與B-樹(shù)也基本相同,區(qū)別是B+樹(shù)只有達(dá)到葉子結(jié)點(diǎn)才命中(B-樹(shù)可以在非葉子結(jié)點(diǎn)命中),其性能也等價(jià)于在關(guān)鍵字全集做一次二分查找;

B+樹(shù)的查詢(xún)

B+樹(shù)的好處就體現(xiàn)在查詢(xún)性能上:

  • 在單元素查詢(xún)的時(shí)候,B+樹(shù)會(huì)自頂向下逐層查找節(jié)點(diǎn),最終找到匹配的葉子節(jié)點(diǎn)。比如拿上面的B+樹(shù)來(lái)進(jìn)行查詢(xún):

現(xiàn)在要查找3:
第一次磁盤(pán)IO:

第二次磁盤(pán)IO:

第三次磁盤(pán)IO:

看到這里,可能會(huì)覺(jué)得查詢(xún)流程和B-樹(shù)差不多呀。
不,有兩點(diǎn)不同。首先,B+樹(shù)的中間節(jié)點(diǎn)沒(méi)有數(shù)據(jù),只存儲(chǔ)索引,所以同樣大小的磁盤(pán)頁(yè)可以容納更大的節(jié)點(diǎn)元素。這就意味著,數(shù)據(jù)量相同的情況下,B+樹(shù)比B-樹(shù)更加“矮胖”,因此查詢(xún)時(shí)IO次數(shù)也更少。
其次,B+樹(shù)的查詢(xún)必須最終查詢(xún)到葉子節(jié)點(diǎn),而B(niǎo)-樹(shù)只要找到匹配元素即可,無(wú)論匹配元素在葉子節(jié)點(diǎn)還是在中間節(jié)點(diǎn)。因此,B-樹(shù)的查找性能并不穩(wěn)定(最好的情況只查找根節(jié)點(diǎn),最壞的情況查找到葉子節(jié)點(diǎn))。而B(niǎo)+樹(shù)的每一次查找都是穩(wěn)定的。

B+樹(shù)查詢(xún)的優(yōu)勢(shì)更多的體現(xiàn)在范圍查詢(xún)上。比如現(xiàn)在要查詢(xún)3-11的元素。
B-樹(shù)的查找過(guò)程:
自頂向下查找到范圍的下限3:

中序遍歷到元素6:

中序遍歷到元素8:

中序遍歷到元素9:

中序遍歷到11,遍歷結(jié)束:

B-樹(shù)的范圍查詢(xún)是不是很繁瑣呢?
再來(lái)看看B+樹(shù)的范圍查詢(xún)。
自頂向下查找到范圍的下限3:

通過(guò)鏈表指針,遍歷到元素6,8:

通過(guò)鏈表指針,遍歷到元素9,11,遍歷結(jié)束:


總結(jié)一下B+樹(shù)的特征和優(yōu)勢(shì)

B+樹(shù)的特征:
1、有k個(gè)子樹(shù)的中間節(jié)點(diǎn)包含有k個(gè)元素(B樹(shù)中是k-1個(gè)元素),每個(gè)元素不保存數(shù)據(jù),只用來(lái)索引,所有元素都保存在葉子節(jié)點(diǎn)。
2、所有的葉子節(jié)點(diǎn)中保存了全部元素的信息,及指向含這些元素記錄的指針,且葉子節(jié)點(diǎn)本身依關(guān)鍵字的大小自小而大順序鏈接。
3、所有的中間節(jié)點(diǎn)元素都同時(shí)存在于子節(jié)點(diǎn),在子節(jié)點(diǎn)元素節(jié)點(diǎn)中是最大(或最?。┰?。

B+樹(shù)的優(yōu)勢(shì):
1、單一節(jié)點(diǎn)存儲(chǔ)更多的元素,使得查詢(xún)的IO次數(shù)更少。
在數(shù)據(jù)庫(kù)檢索來(lái)說(shuō),對(duì)于磁盤(pán)IO掃描時(shí)最消耗時(shí)間的,因?yàn)榇疟P(pán)掃描涉及很多物理特性,這些是相當(dāng)消耗時(shí)間的。所以B+樹(shù)設(shè)計(jì)的初衷就是最大限度的減少對(duì)于磁盤(pán)的掃描次數(shù)。如果一個(gè)表或索引沒(méi)有使用B+樹(shù)(對(duì)于沒(méi)有聚集索引的表是用堆heap存儲(chǔ)),那么查找一個(gè)數(shù)據(jù),需要在整個(gè)表包含的數(shù)據(jù)庫(kù)頁(yè)中全盤(pán)掃描。這無(wú)疑會(huì)大大加重IO負(fù)擔(dān),而使用B+樹(shù)進(jìn)行存儲(chǔ),則僅僅需要將B+樹(shù)的根節(jié)點(diǎn)存入內(nèi)存中,經(jīng)過(guò)幾次查找后就可以找到存放需要數(shù)據(jù)的被葉子結(jié)點(diǎn)包含的頁(yè),進(jìn)而避免了全盤(pán)掃描從而提高了性能。
2、所有查詢(xún)都要查詢(xún)到葉子節(jié)點(diǎn),查詢(xún)性能更穩(wěn)定。
3、所有葉子節(jié)點(diǎn)形成有序鏈表,便于范圍查詢(xún)。

B+樹(shù)的插入

1)若為空樹(shù),創(chuàng)建一個(gè)葉子結(jié)點(diǎn),然后將記錄插入其中,此時(shí)這個(gè)葉子結(jié)點(diǎn)也是根結(jié)點(diǎn),插入操作結(jié)束。
2)針對(duì)葉子類(lèi)型結(jié)點(diǎn):根據(jù)key值找到葉子結(jié)點(diǎn),向這個(gè)葉子結(jié)點(diǎn)插入記錄。插入后,若當(dāng)前結(jié)點(diǎn)key的個(gè)數(shù)小于等于m-1,則插入結(jié)束。否則將這個(gè)葉子結(jié)點(diǎn)分裂成左右兩個(gè)葉子結(jié)點(diǎn),左葉子結(jié)點(diǎn)包含前m/2+1個(gè)記錄,右結(jié)點(diǎn)包含剩下的記錄,將第m/2+1個(gè)記錄的key進(jìn)位到父結(jié)點(diǎn)中(父結(jié)點(diǎn)一定是索引類(lèi)型結(jié)點(diǎn)),進(jìn)位到父結(jié)點(diǎn)的key左孩子指針向左結(jié)點(diǎn),右孩子指針向右結(jié)點(diǎn)。將當(dāng)前結(jié)點(diǎn)的指針指向父結(jié)點(diǎn),然后執(zhí)行第3步。
3)針對(duì)索引類(lèi)型結(jié)點(diǎn):若當(dāng)前結(jié)點(diǎn)key的個(gè)數(shù)小于等于m-1,則插入結(jié)束。否則,將這個(gè)索引類(lèi)型結(jié)點(diǎn)分裂成兩個(gè)索引結(jié)點(diǎn),左索引結(jié)點(diǎn)包含前(m-1)/2個(gè)key,右結(jié)點(diǎn)包含m-(m-1)/2個(gè)key,將第m/2個(gè)key進(jìn)位到父結(jié)點(diǎn)中,進(jìn)位到父結(jié)點(diǎn)的key左孩子指向左結(jié)點(diǎn), 進(jìn)位到父結(jié)點(diǎn)的key右孩子指向右結(jié)點(diǎn)。將當(dāng)前結(jié)點(diǎn)的指針指向父結(jié)點(diǎn),然后重復(fù)第3步。

往下圖的3階B+樹(shù)中插入9

首先查找9應(yīng)插入的葉節(jié)點(diǎn),插入發(fā)現(xiàn)沒(méi)有破壞B+樹(shù)的性質(zhì),插入完畢。


往下圖的3階B+樹(shù)中插入20

首先查找20應(yīng)插入的葉節(jié)點(diǎn),插入:

發(fā)現(xiàn)第二個(gè)葉子節(jié)點(diǎn)已經(jīng)破壞了B+樹(shù)的性質(zhì),則分解成[20,21],[37,44]兩個(gè),并把21往父節(jié)點(diǎn)移。

發(fā)現(xiàn)父節(jié)點(diǎn)也破壞了B+樹(shù)的性質(zhì),則把父節(jié)點(diǎn)再分解成[15,21],[44,59],并把21往父節(jié)點(diǎn)移。


往下圖的3階B+樹(shù)插入100

首先查找100應(yīng)插入的節(jié)點(diǎn),插入

修改其所有父節(jié)點(diǎn)的的鍵值為100(只有插入比當(dāng)前樹(shù)的最大數(shù)大的數(shù)時(shí)要做此步驟)

拆分節(jié)點(diǎn)

B+樹(shù)的刪除

刪除下圖3階B+樹(shù)的關(guān)鍵字91

首先找到91所在的節(jié)點(diǎn),刪除,沒(méi)有破壞B+樹(shù)的性質(zhì),完畢


刪除下圖3階B+樹(shù)的關(guān)鍵字97

首先找到97所在的葉子節(jié)點(diǎn),刪除,然后修改該節(jié)點(diǎn)的所有父節(jié)點(diǎn)的關(guān)鍵字為91(只有刪除樹(shù)中最大的關(guān)鍵字需要做此步驟)


刪除下圖3階B+樹(shù)的關(guān)鍵字51

首先找到51所在的葉子節(jié)點(diǎn),刪除

破壞了B+樹(shù)的性質(zhì),向該節(jié)點(diǎn)的兄弟節(jié)點(diǎn)(左節(jié)點(diǎn)或右節(jié)點(diǎn))借節(jié)點(diǎn)44,并修改相應(yīng)鍵值。


刪除下圖3階B+樹(shù)的關(guān)鍵字59

首先找到59所在的葉子節(jié)點(diǎn)

破壞B+樹(shù)的性質(zhì),嘗試借節(jié)點(diǎn),無(wú)效(因?yàn)樽笮值芄?jié)點(diǎn)被借也會(huì)破壞B+樹(shù)的性質(zhì)),合并第二、第三葉節(jié)點(diǎn),并調(diào)整鍵值


刪除下圖3階B+樹(shù)的關(guān)鍵字63

首先找到63所在的葉節(jié)點(diǎn),刪除

合并第四、第五節(jié)點(diǎn)并調(diào)整鍵值

第二層的第二個(gè)節(jié)點(diǎn)不滿(mǎn)足B+樹(shù)的性質(zhì),從第二層的第一個(gè)節(jié)點(diǎn)借59并調(diào)整鍵值

B*樹(shù)

B*樹(shù)是B+樹(shù)的變體,在B+樹(shù)的非根非葉子節(jié)點(diǎn)中再增加指向兄弟節(jié)點(diǎn)的指針。B*樹(shù)定義了非葉子結(jié)點(diǎn)關(guān)鍵字個(gè)數(shù)至少為(2/3)*M,即塊的最低使用率為2/3(代替B+樹(shù)的1/2)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • B樹(shù)的定義 一棵m階的B樹(shù)滿(mǎn)足下列條件: 樹(shù)中每個(gè)結(jié)點(diǎn)至多有m個(gè)孩子。 除根結(jié)點(diǎn)和葉子結(jié)點(diǎn)外,其它每個(gè)結(jié)點(diǎn)至少有m...
    文檔隨手記閱讀 13,355評(píng)論 0 25
  • B-樹(shù),就是B樹(shù),B樹(shù)的原英文名是B-tree,所以很多翻譯為B-樹(shù),就會(huì)很多人誤以為B-樹(shù)是一種樹(shù)、B樹(shù)是另外一...
    xx1994閱讀 23,895評(píng)論 1 17
  • B樹(shù) 1.前言: 動(dòng)態(tài)查找樹(shù)主要有:二叉查找樹(shù)(Binary Search Tree),平衡二叉查找樹(shù)(Balan...
    鐵甲依然在_978f閱讀 1,466評(píng)論 0 4
  • 在CSS2.1里,background屬性的簡(jiǎn)寫(xiě)方式包含五種屬性值,從CSS3開(kāi)始,又增加了3個(gè)新的屬性值,加起來(lái)...
    水玲瓏_44a9閱讀 11,518評(píng)論 0 2
  • 合法行政,合理行政,誠(chéng)實(shí)守信原則,程序正當(dāng)選擇,高效便民原則,權(quán)責(zé)正當(dāng)原則
    010ed0d5a362閱讀 332評(píng)論 0 0