B-tree 演算法詳解
作者:Chank
原文連結:http://blog.csdn.net/flq_chank/article/details/41928291
一、B-tree演算法定義
對於最小度數為d(d≥2, 最大度為2d-1),樹高為h的樹T來說,如果樹T擁有如下性質:
(1)所有的葉子結點都擁有相同的高度,即樹T的高度h。
(2)除了樹根和葉子結點外,所有的結點至少有d個孩子。樹根則是葉子結點或至少有2個孩子。
(3)每一個結點至多有2d–1個孩子。
我們則稱樹T為B-tree。如下圖所示即為一棵度數為2的簡單B-tree:
可以看出,B-tree是一種平衡樹,每個葉子結點都擁有相同的高度h。每一個結點中可以含有兩種型別的資料。一種是指標(葉子結點沒有),可以指向其孩子結點;另一種則是資料域,一般含有兩種資訊,即按升序排序的鍵和儲存的資訊。即一個B-tree結點的結構可以用如下方式來表示:
p0 | data0 | p1 | data1 | … | … | pn | datan | pn+1 |
其中p是指標,指向其孩子結點。data主要有兩個資料域,升序排序的鍵data.key(data0.key < data1.key < … < datan.key)和儲存的資訊data.info。對於度數為d的B-tree來說,由於d≤n+2≤2d-1,即d-2≤n≤2d-3。例如上圖中根結點的100即是鍵值也是資料資訊,即data.key=data.info=100,是一種及其簡單的形式。
二、B-tree查詢資料
B-tree演算法可以說是一種很優雅的演算法,對B-tree中資料的增加或刪除都能很容易地使之重新平衡。
假設要查詢資料x,則B-tree演算法的查詢演算法如下:
(1)將樹根r賦給p,即p=r。
(2) 如果p為NULL,就結束查詢返回未找到資料和當前結點的地址(插入資料時要用到)。否則,轉(3)
(3)如果x<data0.key,則將p0賦給p,轉(2)。否則,轉(4)
(4)判斷是否存在x=datai.key,如果存在,則返回找到資料。否則,轉(5)。
(5)判斷是否存在datai.key<x<datai+1.key(1≤i≤n),如果存在,則將pi賦給p,轉(2)。否則,將pn+1賦給p,轉(2)
如果要查詢資料60,查詢過程如下圖虛線所示
三、B-tree演算法插入
B-tree插入資料會可能導致結點滿而分裂,但分裂後卻仍然能保持B-tree平衡。假設要插入資料x,則B-tree演算法的插入演算法如下:
(1)對要查詢的資料x執行一次查詢操作。如果找到,就直接結束操作;否則,轉(2)
(2)如果p為NULL,則說明樹為空,建立一個根結點,返回成功。否則,判斷當前結點是否滿(n>2d-3),如果未滿,插入x結束操作。如果滿,轉(3)
(3)設當前結點p為(p0,data0,p1,data1 ,…datad-1,…,p2d-2,data2d-2,p2d-1 )。建立一個新的結點p’包含資料(pd,datad,…,p2d-2,data2d-2,p2d-1),則結點p變為(p0,data0,p1,data1 ,…,pd-2,datad-2,pd-1)。設p的父結點為P。此時,如果P為NULL(根結點已滿),建立一個新的根結點包含資料:p的地址、datad-1和p’的地址;如果P不為NULL,則轉(4)
(4)將datad-1和結點p’的地址插入到p的父結點P中。此時,如果父結點P未滿,則結點返回成功;否則將P賦給p,轉(3)
例如,對如圖3-1的B-tee插入資料300後的B-tree如下圖所示:
如果繼續插入資料1,則根結點會滿,此時會建立新的根結點,如下圖所示:
四、B-tree演算法刪除
假設要刪除資料x,則B-tree演算法的刪除演算法如下:
(1)對要刪除的資料x執行一次查詢操作。如果沒有找到,就直接結束操作;否則,轉(2)
(2)假設x在結點p(…,datai,pi,…)中(即datai.key=x),判斷p是否在葉子結點中,如果不是,轉(3);如果是,刪除datai,轉(5)
(3)根據pi和它所指向結點的p0,並一直沿著p0這條路徑查詢,直到找到葉子結點。用找到的葉子結點的data0來替換(2)中找到的datai,轉(4)
(4)刪除葉子結點的data0,轉(5)
(5)對於葉子結點,如果n≥d-2,則結束操作,返回成功。否則,轉(6)
(6)執行一次合併操作(跟父結點的datai和它的兄弟結點合併)。如果合併後的結點n>2d-3,則執行一次類似插入操作的分裂操作(將合併後的結點從中間分成兩部分)。如果合併後其父結點n≥d-2,則結束操作,返回成功。否則,轉(6)
如下圖所示,該B-tree的度數d=3:
如果要刪除該B-tree中的70,則刪除後的B-tree如下圖所示: