樹及樹的演算法(5) B樹(上)

2021-06-08 03:17:27 字數 4378 閱讀 3314

1970

年,魯道夫·貝爾(

r.bayer

)的先於紅黑樹提出了

b樹。這種適用於外查詢的樹,是一種平衡的多叉樹,又稱

b-樹。

b樹與紅黑樹最大的不同在於,

b樹的結點可以有許多子女,從幾個到幾千個。那為什麼又說

b樹與紅黑樹很相似呢?因為與紅黑樹一樣,一棵含

n個結點的

b樹的高度也為o(

log2

n),但可能比一棵紅黑樹的高度小許多,應為它的分支因子比較大。所以,

b樹可以在o(

log2

n)時間內,實現各種如插入(

insert

),刪除(

delete

)等動態集合操作。

如下圖所示,即是一棵

b樹,一棵關鍵字為英語中子音字母的

b樹,現在要從樹中查詢字母

r(包含

n[x]

個關鍵字的內結點x,

x有n[x]+1]

個子女(也就是說,乙個內結點

x若含有

n[x]

個關鍵字,那麼

x將含有

n[x]+1

個子女)。所有的葉結點都處於相同的深度,帶陰影的結點為查詢字母

r時要檢查的結點):

相信,從上圖你能輕易的看到,乙個內結點x若含有n個關鍵字,那麼x將含有n+1個子女。如含有2個關鍵字d h的內結點有3個子女,而含有3個關鍵字q t x的內結點有4個子女。

一、b樹(b-樹)的概念

b 樹又叫平衡多路查詢樹。一棵m階的b 樹(m叉樹)的特性如下: 1.

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

除根結點和葉子結點外,其它每個結點至少有[ceil(m / 2)]個孩子(其中ceil(x)是乙個向上去整的函式); 3.

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

所有葉子結點都出現在同一層,葉子結點不包含任何關鍵字資訊

(可以看做是外部接點或查詢失敗的接點,實際上這些結點不存在,指向這些結點的指標都為null); 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。

針對上面第5點,再闡述下:b樹中每乙個結點能包含的關鍵字數有乙個上界和下界。這兩個界可以用乙個稱作b樹的最小度數t(t>=2)表示。

每個非根的結點必須至少含有t-1個關鍵字。每個非根的內結點至少有t個子女。如果樹是非空的,則根結點至少包含乙個關鍵字;

每個結點可包含之多2t-1個關鍵字。所以乙個內結點至多可有2t個子女。如果乙個結點恰好有2t-1個關鍵字,我們就說這個結點是滿的(而稍後介紹的b*樹作為b樹的一種常用變形,b*樹中要求每個內結點至少為2/3滿,而不是像這裡的b樹所要求的至少半滿);

當關鍵字數t=2(t=2的意思是,tmin=2,t可=2)時的b樹是最簡單的(有很多人會因此誤認為b樹就是二叉查詢樹,但二叉查詢樹就是二叉查詢樹,b樹就是b樹,b樹的真正最準確的定義為:一棵含有t(t>=2)個關鍵字的平衡多路查詢樹)。每個內結點可能因此而含有2個、3個或4個子女,亦即一棵2-3-4樹,然而在實際中,通常採用大得多的t值。

b樹中的每個結點根據實際情況可以包含大量的關鍵字資訊和分支(當然是不能超過磁碟塊的大小,根據磁碟驅動(disk drives)的不同,一般塊的大小在512b~4k左右);這樣樹的深度降低了,這就意味著查詢乙個元素只要很少結點從外存磁碟中讀入記憶體,很快訪問到要查詢的資料。

b樹的概念介紹完了,對於這麼複雜和抽象的演算法,要想把它吃透,只有拿出我們看家本領了,具體化:

為了簡單,這裡用少量資料構造一棵3叉樹的形式,實際應用中的b樹結點中關鍵字很多的。上面的圖中比如根結點,其中17比表示乙個磁碟檔案的檔名;小紅方塊表示這個17檔案內容在硬碟中的儲存位置;p1表示指向17左子樹的指標。

其結構可以簡單定義為:

typedef struct btnode;
假如每個盤塊可以正好存放乙個b樹的結點(正好存放2個檔名)。那麼乙個btnode結點就代表乙個盤塊,而子樹指標就是存放另外乙個盤塊的位址。

下面,咱們來模擬下查詢檔案29的過程: 1.

根據根結點指標找到檔案目錄的根磁碟塊1,將其中的資訊匯入記憶體。【磁碟io操作1次】 2.

此時記憶體中有兩個檔名17、35和三個儲存其他磁碟頁面位址的資料。根據演算法我們發現17<29<35,因此我們找到指標p2。 3.

根據p2指標,我們定位到磁碟塊3,並將其中的資訊匯入記憶體。【磁碟io操作2次】 4.

此時記憶體中有兩個檔名26,30和三個儲存其他磁碟頁面位址的資料。根據演算法我們發,26<29<30,因此我們找到指標p2。 5.

根據p2指標,我們定位到磁碟塊8,並將其中的資訊匯入記憶體。【磁碟io操作3次】 6.

此時記憶體中有兩個檔名28,29。根據演算法我們查詢到文,29,並定位了該檔案記憶體的磁碟位址。

分析上面的過程,發現需要3次磁碟io操作和3次記憶體查詢操作。關於記憶體中的檔名查詢,由於是乙個有序表結構,可以利用折半查詢提高效率。至於io操作時影響整個b樹查詢效率的決定因素。

當然,如果我們使用平衡二叉樹的磁碟儲存結構來進行查詢,磁碟4次,最多5次,而且檔案越多,b樹比平衡二叉樹所用的磁碟io操作次數將越少,效率也越高。

二、b+樹的概念

b+樹是應檔案系統所需而產生的一種b-tree的變形樹。一棵m階的b+樹和m階的b樹的差異在於:

1.有n棵子樹的結點中含有n個關鍵字;(而b 樹是n棵子樹有n-1個關鍵字)

2.所有的葉子結點中包含了全部關鍵字的資訊,及指向含有這些關鍵字記錄的指標,且葉子結點本身依關鍵字的大小自小而大的順序鏈結。(而b 樹的葉子節點並沒有包括全部需要查詢的資訊)

3.所有的非終端結點可以看成是索引部分,結點中僅含有其子樹根結點中最大(或最小)關鍵字。(而b 樹的非終節點也包含需要查詢的有效資訊)

為什麼說b+-tree比b 樹更適合實際應用中作業系統的檔案索引和資料庫索引?

(1)b+-tree的磁碟讀寫代價更低

b+-tree的內部結點並沒有指向關鍵字具體資訊的指標。因此其內部結點相對b 樹更小。如果把所有同一內部結點的關鍵字存放在同一盤塊中,那麼盤塊所能容納的關鍵字數量也越多。一次性讀入記憶體中的需要查詢的關鍵字也就越多。相對來說io讀寫次數也就降低了。

舉個例子,假設磁碟中的乙個盤塊容納16bytes,而乙個關鍵字2bytes,乙個關鍵字具體資訊指標2bytes。一棵9階b-tree(乙個結點最多8個關鍵字)的內部結點需要2個盤快。而b+ 樹內部結點只需要1個盤快。當需要把內部結點讀入記憶體中的時候,b 樹就比b+ 樹多一次盤塊查詢時間(在磁碟中就是碟片旋轉的時間)。

(2)b+-tree的查詢效率更加穩定

由於非終結點並不是最終指向檔案內容的結點,而只是葉子結點中關鍵字的索引。所以任何關鍵字的查詢必須走一條從根結點到葉子結點的路。所有關鍵字查詢的路徑長度相同,導致每乙個資料的查詢效率相當。

三、b*樹的概念

b*樹是b+樹的變體,在b+ 樹非根和非葉子結點再增加指向兄弟的指標;b*樹定義了非葉子結點關鍵字個數至少為(2/3)*m,即塊的最低使用率為2/3(代替b+樹的1/2)。給出了乙個簡單例項,如下圖所示:

b+樹的**:當乙個結點滿時,分配乙個新的結點,並將原結點中1/2的資料複製到新結點,最後在父結點中增加新結點的指標;b+樹的**只影響原結點和父結點,而不會影響兄弟結點,所以它不需要指向兄弟的指標。

b*樹的**:當乙個結點滿時,如果它的下乙個兄弟結點未滿,那麼將一部分資料移到兄弟結點中,再在原結點插入關鍵字,最後修改父結點中兄弟結點的關鍵字(因為兄弟結點的關鍵字範圍改變了);如果兄弟也滿了,則在原結點與兄弟結點之間增加新結點,並各複製1/3的資料到新結點,最後在父結點增加新結點的指標。

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

B樹 B 樹及索引

b樹 每個節點都儲存key和data,所有節點組成這棵樹,並且葉子節點指標為null。b 樹 只有葉子節點儲存data,葉子節點包含了這棵樹的所有鍵值,葉子節點不儲存指標。後來在b 樹上加了順序訪問指標,也就是每個葉子節點增加乙個指向相鄰葉子節點的指標。可以像遍歷鍊錶一樣遍歷葉子節點。b 樹是資料庫...

B樹 B 樹 B 樹 B 樹相關定義及操作

b 樹即二叉搜尋樹 1.所有非葉子結點至多擁有兩個兒子 left 和right 2.所有結點儲存乙個關鍵字 3.非葉子結點的左指標指向小於其關鍵字的子樹,右指標指向大於其關鍵字的子樹 如 b樹的搜尋,從根結點開始,如果查詢的關鍵字與結點的關鍵字相等,那麼就命中 否則,如果查詢關鍵字比結點關鍵字小,就...

演算法題目第3題(B樹,B 樹,B 樹,B 樹)

一道筆試題 記不清楚了 b 樹插入操作的平均時間複雜度為o logn 最壞時間複雜度為o n hash表插入操作的平均時間複雜度為o 1 最壞時間複雜度為o n 排序鍊錶插入操作的平均時間複雜度為o n 最壞時間複雜度為o n 紅黑樹插入操作的平均時間複雜度為o logn 最壞時間複雜度為o n 這...