午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

B樹和B 樹的插入、刪除圖文詳解

 印度阿三17 2019-07-07

?

轉(zhuǎn)自?https://www.cnblogs.com/nullzx/p/8729425.html? ?

簡介:本文主要介紹了B樹和B 樹的插入、刪除操作。寫這篇博客的目的是發(fā)現(xiàn)沒有相關(guān)博客以舉例的方式詳細介紹B 樹的相關(guān)操作,由于自身對某些細節(jié)也感到很迷惑,通過查閱相關(guān)資料,對B 樹的操作有所頓悟,寫下這篇博客以做記錄。由于是自身對B 樹的理解,肯定有考慮不周的情況,或者理解錯誤的地方,請留言指出。

?


1. B樹

1. B樹的定義

B樹也稱B-樹,它是一顆多路平衡查找樹。我們描述一顆B樹時需要指定它的階數(shù),階數(shù)表示了一個結(jié)點最多有多少個孩子結(jié)點,一般用字母m表示階數(shù)。當(dāng)m取2時,就是我們常見的二叉搜索樹。

一顆m階的B樹定義如下:

1)每個結(jié)點最多有m-1個關(guān)鍵字。

2)根結(jié)點最少可以只有1個關(guān)鍵字。

3)非根結(jié)點至少有Math.ceil(m/2)-1個關(guān)鍵字。

4)每個結(jié)點中的關(guān)鍵字都按照從小到大的順序排列,每個關(guān)鍵字的左子樹中的所有關(guān)鍵字都小于它,而右子樹中的所有關(guān)鍵字都大于它。

5)所有葉子結(jié)點都位于同一層,或者說根結(jié)點到每個葉子結(jié)點的長度都相同。

clip_image002

上圖是一顆階數(shù)為4的B樹。在實際應(yīng)用中的B樹的階數(shù)m都非常大(通常大于100),所以即使存儲大量的數(shù)據(jù),B樹的高度仍然比較小。每個結(jié)點中存儲了關(guān)鍵字(key)和關(guān)鍵字對應(yīng)的數(shù)據(jù)(data),以及孩子結(jié)點的指針。我們將一個key和其對應(yīng)的data稱為一個記錄。但為了方便描述,除非特別說明,后續(xù)文中就用key來代替(key, value)鍵值對這個整體。在數(shù)據(jù)庫中我們將B樹(和B 樹)作為索引結(jié)構(gòu),可以加快查詢速速,此時B樹中的key就表示鍵,而data表示了這個鍵對應(yīng)的條目在硬盤上的邏輯地址。

?

1.2 B樹的插入操作

插入操作是指插入一條記錄,即(key, value)的鍵值對。如果B樹中已存在需要插入的鍵值對,則用需要插入的value替換舊的value。若B樹不存在這個key,則一定是在葉子結(jié)點中進行插入操作。

1)根據(jù)要插入的key的值,找到葉子結(jié)點并插入。

2)判斷當(dāng)前結(jié)點key的個數(shù)是否小于等于m-1,若滿足則結(jié)束,否則進行第3步。

3)以結(jié)點中間的key為中心分裂成左右兩部分,然后將這個中間的key插入到父結(jié)點中,這個key的左子樹指向分裂后的左半部分,這個key的右子支指向分裂后的右半部分,然后將當(dāng)前結(jié)點指向父結(jié)點,繼續(xù)進行第3步。

下面以5階B樹為例,介紹B樹的插入操作,在5階B樹中,結(jié)點最多有4個key,最少有2個key


a)在空樹中插入39

clip_image002[4]

此時根結(jié)點就一個key,此時根結(jié)點也是葉子結(jié)點


b)繼續(xù)插入22,97和41

clip_image004

根結(jié)點此時有4個key


c)繼續(xù)插入53

clip_image006

插入后超過了最大允許的關(guān)鍵字個數(shù)4,所以以key值為41為中心進行分裂,結(jié)果如下圖所示,分裂后當(dāng)前結(jié)點指針指向父結(jié)點,滿足B樹條件,插入操作結(jié)束。當(dāng)階數(shù)m為偶數(shù)時,需要分裂時就不存在排序恰好在中間的key,那么我們選擇中間位置的前一個key或中間位置的后一個key為中心進行分裂即可。

clip_image008


d)依次插入13,21,40,同樣會造成分裂,結(jié)果如下圖所示。

clip_image010


e)依次插入30,27, 33 ;36,35,34 ;24,29,結(jié)果如下圖所示。

clip_image012


f)插入key值為26的記錄,插入后的結(jié)果如下圖所示。

clip_image014

當(dāng)前結(jié)點需要以27為中心分裂,并向父結(jié)點進位27,然后當(dāng)前結(jié)點指向父結(jié)點,結(jié)果如下圖所示。

clip_image016

進位后導(dǎo)致當(dāng)前結(jié)點(即根結(jié)點)也需要分裂,分裂的結(jié)果如下圖所示。

clip_image018

分裂后當(dāng)前結(jié)點指向新的根,此時無需調(diào)整。


g)最后再依次插入key為17,28,29,31,32的記錄,結(jié)果如下圖所示。

clip_image020


在實現(xiàn)B樹的代碼中,為了使代碼編寫更加容易,我們可以將結(jié)點中存儲記錄的數(shù)組長度定義為m而非m-1,這樣方便底層的結(jié)點由于分裂向上層插入一個記錄時,上層有多余的位置存儲這個記錄。同時,每個結(jié)點還可以存儲它的父結(jié)點的引用,這樣就不必編寫遞歸程序。

一般來說,對于確定的m和確定類型的記錄,結(jié)點大小是固定的,無論它實際存儲了多少個記錄。但是分配固定結(jié)點大小的方法會存在浪費的情況,比如key為28,29所在的結(jié)點,還有2個key的位置沒有使用,但是已經(jīng)不可能繼續(xù)在插入任何值了,因為這個結(jié)點的前序key是27,后繼key是30,所有整數(shù)值都用完了。所以如果記錄先按key的大小排好序,再插入到B樹中,結(jié)點的使用率就會很低,最差情況下使用率僅為50%。

?

1.3 B樹的刪除操作

刪除操作是指,根據(jù)key刪除記錄,如果B樹中的記錄中不存對應(yīng)key的記錄,則刪除失敗。

1)如果當(dāng)前需要刪除的key位于非葉子結(jié)點上,則用后繼key(這里的后繼key均指后繼記錄的意思)覆蓋要刪除的key,然后在后繼key所在的子支中刪除該后繼key。此時后繼key一定位于葉子結(jié)點上,這個過程和二叉搜索樹刪除結(jié)點的方式類似。刪除這個記錄后執(zhí)行第2步

2)該結(jié)點key個數(shù)大于等于Math.ceil(m/2)-1,結(jié)束刪除操作,否則執(zhí)行第3步。

3)如果兄弟結(jié)點key個數(shù)大于Math.ceil(m/2)-1,則父結(jié)點中的key下移到該結(jié)點,兄弟結(jié)點中的一個key上移,刪除操作結(jié)束。

否則,將父結(jié)點中的key下移與當(dāng)前結(jié)點及它的兄弟結(jié)點中的key合并,形成一個新的結(jié)點。原父結(jié)點中的key的兩個孩子指針就變成了一個孩子指針,指向這個新結(jié)點。然后當(dāng)前結(jié)點的指針指向父結(jié)點,重復(fù)上第2步。

有些結(jié)點它可能即有左兄弟,又有右兄弟,那么我們?nèi)我膺x擇一個兄弟結(jié)點進行操作即可。

下面以5階B樹為例,介紹B樹的刪除操作,5階B樹中,結(jié)點最多有4個key,最少有2個key


a)原始狀態(tài)

clip_image021


b)在上面的B樹中刪除21,刪除后結(jié)點中的關(guān)鍵字個數(shù)仍然大于等2,所以刪除結(jié)束。

clip_image023


c)在上述情況下接著刪除27。從上圖可知27位于非葉子結(jié)點中,所以用27的后繼替換它。從圖中可以看出,27的后繼為28,我們用28替換27,然后在28(原27)的右孩子結(jié)點中刪除28。刪除后的結(jié)果如下圖所示。

clip_image025

刪除后發(fā)現(xiàn),當(dāng)前葉子結(jié)點的記錄的個數(shù)小于2,而它的兄弟結(jié)點中有3個記錄(當(dāng)前結(jié)點還有一個右兄弟,選擇右兄弟就會出現(xiàn)合并結(jié)點的情況,不論選哪一個都行,只是最后B樹的形態(tài)會不一樣而已),我們可以從兄弟結(jié)點中借取一個key。所以父結(jié)點中的28下移,兄弟結(jié)點中的26上移,刪除結(jié)束。結(jié)果如下圖所示。

clip_image027


d)在上述情況下接著32,結(jié)果如下圖。

clip_image029

當(dāng)刪除后,當(dāng)前結(jié)點中只key,而兄弟結(jié)點中也僅有2個key。所以只能讓父結(jié)點中的30下移和這個兩個孩子結(jié)點中的key合并,成為一個新的結(jié)點,當(dāng)前結(jié)點的指針指向父結(jié)點。結(jié)果如下圖所示。

clip_image031

當(dāng)前結(jié)點key的個數(shù)滿足條件,故刪除結(jié)束。


e)上述情況下,我們接著刪除key為40的記錄,刪除后結(jié)果如下圖所示。

clip_image033

同理,當(dāng)前結(jié)點的記錄數(shù)小于2,兄弟結(jié)點中沒有多余key,所以父結(jié)點中的key下移,和兄弟(這里我們選擇左兄弟,選擇右兄弟也可以)結(jié)點合并,合并后的指向當(dāng)前結(jié)點的指針就指向了父結(jié)點。

clip_image035

同理,對于當(dāng)前結(jié)點而言只能繼續(xù)合并了,最后結(jié)果如下所示。

clip_image037

合并后結(jié)點當(dāng)前結(jié)點滿足條件,刪除結(jié)束。

?

2.B 樹

2.1 B 樹的定義

clip_image039

各種資料上B 樹的定義各有不同,一種定義方式是關(guān)鍵字個數(shù)和孩子結(jié)點個數(shù)相同。這里我們采取維基百科上所定義的方式,即關(guān)鍵字個數(shù)比孩子結(jié)點個數(shù)小1,這種方式是和B樹基本等價的。上圖就是一顆階數(shù)為4的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)鍵字的大小自小而大順序鏈接。

?

2.2 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

clip_image041


b)依次插入8,10,15

clip_image043


c)插入16

clip_image045

插入16后超過了關(guān)鍵字的個數(shù)限制,所以要進行分裂。在葉子結(jié)點分裂時,分裂出來的左結(jié)點2個記錄,右邊3個記錄,中間key成為索引結(jié)點中的key,分裂后當(dāng)前結(jié)點指向了父結(jié)點(根結(jié)點)。結(jié)果如下圖所示。

clip_image047

當(dāng)然我們還有另一種分裂方式,給左結(jié)點3個記錄,右結(jié)點2個記錄,此時索引結(jié)點中的key就變?yōu)?5。


d)插入17

clip_image049


e)插入18,插入后如下圖所示

clip_image051

當(dāng)前結(jié)點的關(guān)鍵字個數(shù)大于5,進行分裂。分裂成兩個結(jié)點,左結(jié)點2個記錄,右結(jié)點3個記錄,關(guān)鍵字16進位到父結(jié)點(索引類型)中,將當(dāng)前結(jié)點的指針指向父結(jié)點。

clip_image053

當(dāng)前結(jié)點的關(guān)鍵字個數(shù)滿足條件,插入結(jié)束。


f)插入若干數(shù)據(jù)后

clip_image055


g)在上圖中插入7,結(jié)果如下圖所示

clip_image057

當(dāng)前結(jié)點的關(guān)鍵字個數(shù)超過4,需要分裂。左結(jié)點2個記錄,右結(jié)點3個記錄。分裂后關(guān)鍵字7進入到父結(jié)點中,將當(dāng)前結(jié)點的指針指向父結(jié)點,結(jié)果如下圖所示。

clip_image059

當(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é)果如下圖所示。

clip_image061

當(dāng)前結(jié)點的關(guān)鍵字個數(shù)滿足條件,插入結(jié)束。

?

2.3 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)

clip_image063


b)刪除22,刪除后結(jié)果如下圖

clip_image065

刪除后葉子結(jié)點中key的個數(shù)大于等于2,刪除結(jié)束


c)刪除15,刪除后的結(jié)果如下圖所示

clip_image067

刪除后當(dāng)前結(jié)點只有一個key,不滿足條件,而兄弟結(jié)點有三個key,可以從兄弟結(jié)點借一個關(guān)鍵字為9的記錄,同時更新將父結(jié)點中的關(guān)鍵字由10也變?yōu)?,刪除結(jié)束。

clip_image069


d)刪除7,刪除后的結(jié)果如下圖所示

clip_image071

當(dāng)前結(jié)點關(guān)鍵字個數(shù)小于2,(左)兄弟結(jié)點中的也沒有富余的關(guān)鍵字(當(dāng)前結(jié)點還有個右兄弟,不過選擇任意一個進行分析就可以了,這里我們選擇了左邊的),所以當(dāng)前結(jié)點和兄弟結(jié)點合并,并刪除父結(jié)點中的key,當(dāng)前結(jié)點指向父結(jié)點。

clip_image073

此時當(dāng)前結(jié)點的關(guān)鍵字個數(shù)小于2,兄弟結(jié)點的關(guān)鍵字也沒有富余,所以父結(jié)點中的關(guān)鍵字下移,和兩個孩子結(jié)點合并,結(jié)果如下圖所示。

clip_image075

?

3.參考內(nèi)容

[1]?B 樹介紹

[2]?從MySQL Bug#67718淺談B 樹索引的分裂優(yōu)化

[3]?B 樹的幾點總結(jié)

來源:https://www./content-4-306151.html

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多