本文很多內容均來源於網絡,經過修改,因來源眾多,不一一指出
當查找的文件較大,且存放在磁盤等直接存取設備中時,為了減少查找過程中對磁盤的讀寫次數,提高查找效率,基於直接存取設備的讀寫操作以"頁"為單位的特征。
1972年R.Bayer和E.M.McCreight提出了一種稱之為B-樹的多路平衡查找樹。它適合在磁盤等直接存取設備上組織動態的查找表。
1、定義與特性
B-樹是一種平衡的多路查找樹,在文件系統中有所應用。主要用作文件的索引。
B-樹結構特性:
一棵m階B-樹,或為空樹,或為滿足下列特性的m叉樹:(m≥3)
(1)根結點只有1個,關鍵字字數的范圍[1,m-1],分支數量范圍[2,m];
(2)除根以外的非葉結點,每個結點包含分支數范圍[[m/2],m],即關鍵字字數的范圍是[[m/2]-1,m-1],其中[m/2]表示取大於m/2的最小整數;
(3)非葉結點是由葉結點分裂而來的,所以葉結點關鍵字個數也滿足[[m/2]-1,m-1];
(4)所有的非終端結點包含信息:(n,P0,K1,P1,K2,P2,……,Kn,Pn),
其中Ki為關鍵字,Pi為指向子樹根結點的指針,並且Pi-1所指子樹中的關鍵字均小於Ki,而Pi所指的關鍵字均大於Ki(i=1,2,……,n),n+1表示B-樹的階,n表示關鍵字個數,即[ceil(m / 2)-1]<= n <= m-1;
(5)所有葉子結點都在同一層,並且指針域為空,具有如下性質:
根據B-樹定義,第一層為根有一個結點,至少兩個分支,第二層至少2個結點,i≥3時,每一層至少有2乘以([m/2])的i-2次方個結點([m/2]表示取大於m/2的最小整數)。若m階樹中共有N個結點,那么可以推導出N必然滿足N≥2*(([m/2])的h-1次方)-1 (h≥1),因此若查找成功,則高度h≤1+log[m/2](N+1)/2,h也是磁盤訪問次數(h≥1),保證了查找算法的高效率。
從以上的定義特性可總結出如下結論:對於m階B-樹
2)除根結點和葉子結點外,其它每個結點至少有[ceil(m / 2)]個孩子(其中ceil(x)是一個取上限的函數);
3)若根結點不是葉子結點,則至少有2個孩子(特殊情況:沒有孩子的根結點,即根結點為葉子結點,整棵樹只有一個根節點);
4)所有葉子結點都出現在同一層,葉子結點不包含任何關鍵字信息(葉子節點只是沒有孩子和指向孩子的指針,這些節點也存在,也有元素)。
5)每個非終端結點中包含有n個關鍵字信息: (n,P0,K1,P1,K2,P2,......,Kn,Pn)。其中:
a) Ki (i=1...n)為關鍵字,且關鍵字按順序升序排序K(i-1)< Ki。
b) Pi為指向子樹根的接點,且指針P(i-1)指向子樹種所有結點的關鍵字均小於Ki,但都大於K(i-1)。
c) 關鍵字的個數n必須滿足: [ceil(m / 2)-1]<= n <= m-1。
6)每個結點能包含的關鍵字的個數有一個上界和下界。這些界可以稱為B-樹的相應結點的最小度數(內結點中結點最小孩子數目,即前面提到指針P的個數)的固定整數t>=2來表示
a).每個非根結點必須至少有t-1個關鍵字,每個非根的內結點至少有t個子女,即。如果樹是非空的,則根結點至少包含一個關鍵字。
b).每個結點可包含至多2t-1個關鍵字,每個非根的內結點至多可有2t個子女。如果一個結點是滿的,則它有2t-1個關鍵字.
c).綜上根節點關鍵字的個數范圍: [1, 2*t - 1],非根節點關鍵字的個數范圍: [t-1, 2*t - 1]
下圖給出了典型的3階B-樹

B-樹中的每個結點根據實際情況可以包含大量的關鍵字信息和分支(當然是不能超過磁盤塊的大小,根據磁盤驅動(disk drives)的不同,一般塊的大小在1k~4k左右);這樣樹的深度降低了,這就意味着查找一個元素只要很少結點從外存磁盤中讀入內存,很快訪問到要查找的數據
以上定義特性均為網上資料綜合而來,下面給出對於分支關鍵字個數以及度數的范圍簡要總結:
一個m階B-樹:
1).對於根節點,子樹(孩子或者稱為分支)個數取值范圍[2,m],關鍵字個數范圍[1,m-1]
2).對於內結點,分支數范圍[ceil(m/2),m],關鍵字個數的范圍是ceil(m/2)-1,m-1]
3).對於最小度數為t>=2的結點,根節點關鍵字的個數范圍: [1, 2*t - 1],非根節點關鍵字的個數范圍: [t-1, 2*t - 1],分支的個數范圍:[t, 2*t]
PS 關於最小度數的理解:個人理解為對於m階B-樹t=ceil(m/2)
B-樹定義的結點
#define MAXM 10 /*定義B-樹的最大的階數*/ typedef int KeyType; /*KeyType為關鍵字類型*/ typedef struct BTNode /*B-樹結點類型定義*/ { int keynum; /*結點當前擁有的關鍵字的個數*/ KeyType key[MAXM]; /*key[1..keynum]存放關鍵字,key[0]不用*/
struct BTNode *parent; /*雙親結點指針*/
struct BTNode *ptr[MAXM]; /*孩子結點指針數組ptr[0..keynum]*/ }BTTree;
2.B-樹復雜度與高度
它的高度是
(這個是網上給的結果,與后面推導的結果有異議),而不是其它幾種樹的H=log2n,其中T為度數(每個節點包含的元素個數),即所謂的階數,n為總元素個數或總關鍵字數。
上面B樹高度的公式也可以進行推導得出,將每一層級的的元素個數加起來,比如度為T的節點,根為1個節點,第二層至少為2個節點,第三層至少為2t個節點,第四層至少為2t*t個節點。將所有最小節點相加,推導過程:n>=1+2t+2t*t+2t3+.....+2th-1=1+2t(1+t+t*t+t3+....+th-2)=1+2t*(th-1-1)/(t-1)>=1+2(t-1)*(th-1-1)/(t-1) |最后一個不等式推出的原因:t>=2
最后推出結果h<=logt((n+1)/2)+1
網上給的公式是
但是個人感覺推導並不嚴密,而且中間似乎有錯誤,結果我也沒推出來和他們一樣的 ,不知道什么緣故 如果筆者推算錯誤 希望指出
關於時間復雜度借用網上給出的過程不過都沒有給出解釋,其中M為設定的非葉子結點最多子樹個數,N為關鍵字總數;所以B-樹的性能總是等價於二分查找(與M值無關),也就沒有B樹平衡的問題;

2.基本操作
這里只給出插入刪除操作,查找操作相對簡單的多 這里不做解釋
1)B-樹的插入操作(重點判斷是否滿足n<=m-1)
a.利用前述的B-樹的查找算法查找關鍵字的插入位置。若找到,則說明該關鍵字已經存在,直接返回。否則查找操作必失敗於某個最低層的非終端結點上。
b.判斷該結點是否還有空位置。即判斷該結點的關鍵字總數是否滿足n<=m-1。若滿足,則說明該結點還有空位置,直接把關鍵字k插入到該結點的合適位置上。若不滿足,說明該結點己沒有空位置,需要把結點分裂成兩個。
分裂的方法是:生成一新結點。把原結點上的關鍵字和k按升序排序后,從中間位置把關鍵字(不包括中間位置的關鍵字)分成兩部分。左部分所含關鍵字放在舊結點中,右部分所含關鍵字放在新結點中,中間位置的關鍵字連同新結點的存儲位置插入到父結點中。如果父結點的關鍵字個數也超過(m-1),則要再分裂,再往上插。直至這個過程傳到根結點為止。




2).B-樹的刪除操作(重點判斷刪除所在結點及其兄弟結點,父結點中n>ceil(m/2)-1,n=ceil(m/2)-1,n<ceil(m/2)-1)
在B-樹上刪除關鍵字K的過程也可以分為兩步完成
a.利用前述的B-樹的查找算法找出該關鍵字所在的結點。然后根據 k所在結點是否為葉子結點有不同的處理方法。
b.若該結點為非葉結點,且被刪關鍵字為該結點中第i個關鍵字key[i],則可從指針son[i]所指的子樹中找出最小關鍵字Y,代替key[i]的位置,然后在葉結點中刪去Y。因此,把在非葉結點刪除關鍵字k的問題就變成了刪除葉子結點中的關鍵字的問題了。
在B-樹葉結點上刪除一個關鍵字的方法是
首先將要刪除的關鍵字 k直接從該葉子結點中刪除。然后根據不同情況分別作相應的處理,共有三種可能情況:
a.如果被刪關鍵字所在結點的原關鍵字個數n>=ceil(m/2),說明刪去該關鍵字后該結點仍滿足B-樹的定義。這種情況最為簡單,只需從該結點中直接刪去關鍵字即可。
b.如果被刪關鍵字所在結點的關鍵字個數n等於ceil(m/2)-1,說明刪去該關鍵字后該結點將不滿足B-樹的定義,需要調整。
調整過程為:如果其左右兄弟結點中有“多余”的關鍵字,即與該結點相鄰的右(左)兄弟結點中的關鍵字數目大於ceil(m/2)-1。則可將右(左)兄弟結點中最小(大)關鍵字上移至雙親結點。而將雙親結點中小(大)於該上移關鍵字的關鍵字下移至被刪關鍵字所在結點中。
c.如果左右兄弟結點中沒有“多余”的關鍵字,即與該結點相鄰的右(左)兄弟結點中的關鍵字數目均等於ceil(m/2)-1。這種情況比較復雜。需把要刪除關鍵字的結點與其左(或右)兄弟結點以及雙親結點中分割二者的關鍵字合並成一個結點,即在刪除關鍵字后,該結點中剩余的關鍵字加指針,加上雙親結點中的關鍵字Ki一起,合並到Ai(即雙親結點指向該刪除關鍵字結點的左(右)兄弟結點的指針)所指的兄弟結點中去。如果因此使雙親結點中關鍵字個數小於ceil(m/2)-1,則對此雙親結點做同樣處理。以致於可能直到對根結點做這樣的處理而使整個樹減少一層。
總之,設所刪關鍵字為非終端結點中的Ki,則可以指針Ai所指子樹中的最小關鍵字Y代替Ki,然后在相應結點中刪除Y。對任意關鍵字的刪除都可以轉化為對最下層關鍵字的刪除。

如圖示:
a、被刪關鍵字Ki所在結點的關鍵字數目不小於ceil(m/2),則只需從結點中刪除Ki和相應指針Ai,樹的其它部分不變。

b、被刪關鍵字Ki所在結點的關鍵字數目等於ceil(m/2)-1,則需調整。調整過程如上面所述。

c、被刪關鍵字Ki所在結點和其相鄰兄弟結點中的的關鍵字數目均等於ceil(m/2)-1,假設該結點有右兄弟,且其右兄弟結點地址由其雙親結點指針Ai所指。則在刪除關鍵字之后,它所在結點的剩余關鍵字和指針,加上雙親結點中的關鍵字Ki一起,合並到Ai所指兄弟結點中(若無右兄弟,則合並到左兄弟結點中)。如果因此使雙親結點中的關鍵字數目少於ceil(m/2)-1,則依次類推.


