1. 程式人生 > >B-Tree 、B+樹、B*樹

B-Tree 、B+樹、B*樹

大規模資料儲存中,實現索引查詢這樣一個實際背景下,樹節點儲存的元素數量是有限的(如果元素數量非常多的話,查詢就退化成節點內部的線性查找了),這樣導致二叉查詢樹結構由於樹的深度過大而造成磁碟I/O讀寫過於頻繁,進而導致查詢效率低下。

1.      B-Tree

B 樹是為了磁碟或其它儲存裝置而設計的一種多叉平衡查詢樹。許多資料庫系統都一般使用B樹或者B樹的各種變形結構,如下文即將要介紹的B+樹,B*樹來儲存資訊。

B樹與紅黑樹最大的不同在於,B樹的結點可以有許多子女,從幾個到幾千個。與紅黑樹的相同之處在於,一棵含n個結點的B樹的高度也為O(lgn),但可能比一棵紅黑樹的高度小許多,應為它的分支因子比較大。所以,B樹可以在O(logn)時間內,實現各種如插入(insert),刪除(delete)等動態集合操作。

如下圖所示,即是一棵B樹,一棵關鍵字為英語中子音字母的B樹,現在要從樹種查詢字母R(包含n[x]個關鍵字的內結點x,x有n[x]+1個子女(也就是說,一個內結點x若含有n[x]個關鍵字,那麼x將含有n[x]+1個子女)。所有的葉結點都處於相同的深度,帶陰影的結點為查詢字母R時要檢查的結點):

  B 樹又叫平衡多路查詢樹。一棵m階的B樹的特性如下

I.      樹中每個結點最多含有m個孩子(m>=2);

II.     除根結點和葉子結點外,其它每個結點至少有[ceil(m / 2)]個孩子(其中ceil(x)是一個取上限的函式);

III.   若根結點不是葉子結點,則至少有2個孩子(特殊情況:沒有孩子的根結點,即根結點為葉子結點,整棵樹只有一個根節點);

IV.   所有葉子結點都出現在同一層,葉子結點不包含任何關鍵字資訊(可以看做是外部接點或查詢失敗的接點,實際上這些結點不存在,指向這些結點的指標都為null);

V.    每個非終端結點中包含有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。

B-Tree 資料結構:

template<class T> struct BTreeNode

{

/*實際關鍵字的個數, keyNum<m*/

int keyNum;

/*指向父節點的指標*/

BTreeNode *parent;

/*指向孩子節點的指標陣列:pChild[0],...,pChild[keyNum -1]*/

BTreeNode **pChilds;

T *key;

};

B-Tree的度:

B-Tree中每個節點能包含的關鍵字的數量有一個上界和下界。下界稱為B-Tree的最小度數。

B-Tree的高度:

a)       從B-Tree的最小度來計算

B樹上大部分操作所需的磁碟存取次數與B樹的高度成正比。下面分析B樹的最壞高度情況。如果n>=1, 則對任意一棵包含n個關鍵字、高度為h(從0開始)、最小度數t>=2的B樹有: h = logt((n+1)/2);

證明:

         如果一棵B-Tree的高度為h,其根節點至少包括一個關鍵字,而其他節點至少t-1個關鍵字。深度為1的節點至少有兩個,深度為2的節點至少有2t個,深度為3的節點至少為2t2,…..,深度為h 的節點至少為2th-1,因此,

         所以:h = logt((n+1)/2);

b)      從B-Tree的階數計算

若B樹某一非葉子節點包含N個關鍵字,則此非葉子節點含有N+1個孩子結點,而所有的葉子結點都在第I層,我們可以得出:

1.    因為根至少有兩個孩子,因此第2層至少有兩個結點。

2.    除根和葉子外,其它結點至少有┌m/2┐個孩子,

3.    因此在第3層至少有2*┌m/2┐個結點,

4.    在第4層至少有2*(┌m/2┐^2)個結點,

5.    在第 I層至少有2*(┌m/2┐^(l-2) )個結點,於是有: N+1 ≥ 2*┌m/2┐I-2;

6.    考慮第L層的結點個數為N+1,那麼2*(┌m/2┐^(l-2))≤N+1,也就是L層的最少結點數剛好達到N+1個,即: I≤ log┌m/2┐((N+1)/2 )+2;

  所以

·        當B樹包含N個關鍵字時,B樹的最大高度為l-1(因為計算B樹高度時,葉結點所在層不計算在內),即:l - 1 = log┌m/2┐((N+1)/2 )+1

2.      B+樹

B+樹是B-樹的變體,也是一種多路搜尋樹:

       其定義基本與B-樹同,除了:

      1.非葉子結點的子樹指標與關鍵字個數相同;

        2.非葉子結點的子樹指標P[i],指向關鍵字值屬於[K[i],K[i+1])的子樹(B-樹是開區間);

      3.為所有葉子結點增加一個鏈指標;

4所有關鍵字都在葉子結點出現

          B+的搜尋與B-樹也基本相同,區別是B+樹只有達到葉子結點才命中(B-樹可以在

非葉子結點命中),其效能也等價於在關鍵字全集做一次二分查詢;

       B+的特性:

       1.所有關鍵字都出現在葉子結點的連結串列中(稠密索引),且連結串列中的關鍵字恰好

是有序的;

       2.不可能在非葉子結點命中;

       3.非葉子結點相當於是葉子結點的索引(稀疏索引),葉子結點相當於是儲存

(關鍵字)資料的資料層;

       4.更適合檔案索引系統;

B+樹

B*樹

      是B+樹的變體,在B+樹的非根和非葉子結點再增加指向兄弟的指標;

B*樹定義了非葉子結點關鍵字個數至少為(2/3)*M,即塊的最低使用率為2/3

(代替B+樹的1/2);

      B+樹的分裂:當一個結點滿時,分配一個新的結點,並將原結點中1/2的資料

複製到新結點,最後在父結點中增加新結點的指標;B+樹的分裂隻影響原結點和父

結點,而不會影響兄弟結點,所以它不需要指向兄弟的指標;

      B*樹的分裂:當一個結點滿時,如果它的下一個兄弟結點未滿,那麼將一部分

資料移到兄弟結點中,再在原結點插入關鍵字,最後修改父結點中兄弟結點的關鍵字

(因為兄弟結點的關鍵字範圍改變了);如果兄弟也滿了,則在原結點與兄弟結點之

間增加新結點,並各複製1/3的資料到新結點,最後在父結點增加新結點的指標;

      所以,B*樹分配新結點的概率比B+樹要低,空間使用率更高;

B*樹

--------------------- 本文來自 zhangxl 的CSDN 部落格 ,全文地址請點選:https://blog.csdn.net/sdauzxl/article/details/52234482?utm_source=copy