這裏的B樹,也就是英文中的B-Tree,一個 m 階的B樹知足如下條件:html
每一個結點至多擁有m棵子樹;web
根結點至少擁有兩顆子樹(存在子樹的狀況下),根結點至少有一個關鍵字;算法
除了根結點之外,其他每一個分支結點至少擁有 m/2 棵子樹;數據結構
全部的葉結點都在同一層上,B樹的葉子結點能夠當作是一種外部節點,不包含任何信息;優化
有 k 棵子樹的分支結點則存在 k-1 個關鍵碼,關鍵碼按照遞增次序進行排列;spa
關鍵字數量須要知足ceil(m/2)-1 <= n <= m-1;指針
舉個栗子:orm
磁盤中有兩個機械運動的部分,分別是盤片旋轉和磁臂移動。盤片旋轉就是咱們市面上所提到的多少轉每分鐘,而磁盤移動則是在盤片旋轉到指定位置之後,移動磁臂後開始進行數據的讀寫。那麼這就存在一個定位到磁盤中的塊的過程,而定位是磁盤的存取中花費時間比較大的一塊,畢竟機械運動花費的時候要遠遠大於電子運動的時間。當大規模數據存儲到磁盤中的時候,顯然定位是一個很是花費時間的過程,可是咱們能夠經過B樹進行優化,提升磁盤讀取時定位的效率。htm
爲何B類樹能夠進行優化呢?咱們能夠根據B類樹的特色,構造一個多階的B類樹,而後在儘可能多的在結點上存儲相關的信息,保證層數儘可能的少,在B樹中能夠檢查多個子結點,因爲在一棵樹中檢查任意一個結點都須要一次磁盤訪問,因此B樹避免了大量的磁盤訪問;並且B類樹是平衡樹,每一個結點到葉子結點的高度都是相同,這也保證了每一個查詢是穩定的,查詢的時間複雜度是O(log2N)。blog
總的來講就是利用平衡樹的優點,保證了查詢的穩定性和加快了查詢的速度。
既然是樹,那麼必不可少的操做就是插入和刪除,這也是B樹和其它數據結構不一樣的地方,固然了,還有必不可少的搜索,分享一個對B樹的操做進行可視化的網址,它是由usfca提供的。
假定對高度爲h的m階B樹進行操做。
經過搜索找到對應的結點進行插入,那麼根據即將插入的結點的數量又分爲下面幾種狀況。
若是該結點的關鍵字個數沒有到達到m-1個,那麼直接插入便可;
若是該結點的關鍵字個數已經到達了m-1個,那麼根據B樹的性質顯然沒法知足,須要將其進行分裂。分裂的規則是該結點分紅兩半,將中間的關鍵字進行提高,加入到父親結點中,可是這又可能存在父親結點也滿員的狀況,則不得不向上進行回溯,甚至是要對根結點進行分裂,那麼整棵樹都加了一層。
其過程以下:
一樣的,咱們須要先經過搜索找到相應的值,存在則進行刪除,須要考慮刪除之後的狀況,
若是該結點擁有的關鍵字數量仍然知足B樹性質,則不作任何處理;
若是該結點在刪除關鍵字之後不知足B樹的性質(關鍵字沒有到達ceil(m/2)-1的數量),則須要向兄弟結點借關鍵字,這又分爲兄弟結點的關鍵字數量是否足夠的狀況。
若是兄弟結點的關鍵字足夠借給該結點,則將父親結點的關鍵字下移,兄弟結點的關鍵字上移;
若是兄弟結點的關鍵字在借出去之後也沒法知足B樹性質,即以前兄弟結點的關鍵字的數量爲ceil(m/2)-1,借的一方的關鍵字數量爲ceil(m/2)-2的狀況,那麼咱們能夠將該結點合併到兄弟結點中,合併以後的子結點數量少了一個,則須要將父親結點的關鍵字下放,若是父親結點不知足性質,則向上回溯;
其他狀況參照BST中的刪除。
其過程以下:
B+樹是B樹的變形體,性質和B樹一致;
如圖
其操做和B樹的操做是相似的,不過須要注意的是,在增長值的時候,若是存在滿員的狀況,將選擇結點中的值做爲新的索引,還有在刪除值的時候,索引中的關鍵字並不會刪除,也不會存在父親結點的關鍵字下沉的狀況,由於那只是索引。
這都是因爲B+樹和B樹具備不一樣的存儲結構所形成的區別,以一個m階樹爲例。
關鍵字的數量不一樣;B+樹中分支結點有m個關鍵字,其葉子結點也有m個,其關鍵字只是起到了一個索引的做用,雖然B樹也有m個子結點,可是其只擁有m-1個關鍵字。
存儲的位置不一樣;B+樹中的數據都存儲在葉子結點上,也就是其全部葉子結點的數據組合起來就是完整的數據,可是B樹的數據存儲在每個結點中,並不只僅存儲在葉子結點上。
分支結點的構造不一樣;B+樹的分支結點存儲着關鍵字信息和兒子的指針(這裏的指針指的是磁盤塊的偏移量),也就是說內部結點僅僅包含着索引信息。
查詢不一樣;B樹在找到具體的數值之後就結束,而B+樹則須要經過索引找到葉子結點中的數據才結束,也就是說B+樹的搜索過程當中走了一條從根結點到葉子結點的路徑,其高度是相同的,相對來講更加的穩定;
區間訪問:B+樹的葉子結點會按照順序創建起鏈狀指針,能夠進行區間訪問;