【算法】B樹、B+樹詳解


B樹

前言  

  首先,為什么要總結B樹、B+樹的知識呢?最近在學習數據庫索引調優相關知識,數據庫系統普遍采用B-/+Tree作為索引結構(例如mysql的InnoDB引擎使用的B+樹),理解不透徹B樹,則無法理解數據庫的索引機制;接下來將用最簡潔直白的內容來了解B樹、B+樹的數據結構

  另外,B-樹,即為B樹。因為B樹的原英文名稱為B-tree,而國內很多人喜歡把B-tree譯作B-樹,其實,這是個非常不好的直譯,很容易讓人產生誤解。如人們可能會以為B-樹是一種樹,而B樹又是一種樹。而事實上是,B-tree就是指的B樹,目前理解B的意思為平衡

  B樹的出現是為了彌合不同的存儲級別之間的訪問速度上的巨大差異,實現高效的 I/O。平衡二叉樹的查找效率是非常高的,並可以通過降低樹的深度來提高查找的效率。但是當數據量非常大,樹的存儲的元素數量是有限的,這樣會導致二叉查找樹結構由於樹的深度過大而造成磁盤I/O讀寫過於頻繁,進而導致查詢效率低下。另外數據量過大會導致內存空間不夠容納平衡二叉樹所有結點的情況。B樹是解決這個問題的很好的結構

概念

  首先,B樹不要和二叉樹混淆,在計算機科學中,B樹是一種自平衡樹數據結構,它維護有序數據並允許以對數時間進行搜索,順序訪問,插入和刪除。B樹是二叉搜索樹的一般化,因為節點可以有兩個以上的子節點。與其他自平衡二進制搜索樹不同,B樹非常適合讀取和寫入相對較大的數據塊(如光盤)的存儲系統。它通常用於數據庫和文件系統。

   定義

  B樹是一種平衡的多分樹,通常我們說m階的B樹(m代表最多含有多少顆子樹),它必須滿足如下條件: 

  • 每個節點最多有m個子節點
  • 根節點最少可以有1個關鍵字
  • 非根節點至少有math.ceil(m/2) - 1 個關鍵字 (math.ceil表示向上取整)
  • 具有k個子節點的非葉節點包含k -1個鍵。
  • 所有葉子結點都位於同一層(或者說根節點到每個葉子節點的長度都相同)

  第一次看到這個定義的時候,在想什么鬼?。。。。什么是階?子節點、飛葉子點、根???啥意思!少年別慌。。。

  什么是B樹的階 ?

  B樹中一個節點的子節點數目的最大值,用m表示,假如最大值為10,則為10階,如圖

   

  所有節點中,節點【13,16,19】擁有的子節點數目最多,四個子節點(灰色節點),所以可以定義上面的圖片為4階B樹,現在懂什么是階了吧

  什么是根節點 ?

  節點【10】即為根節點,特征:根節點擁有的子節點數量的上限和內部節點相同,如果根節點不是樹中唯一節點的話,至少有倆個子節點(不然就變成單支了)。

  在m階B樹中(根節點非樹中唯一節點),那么有關系式2<= M <=m,M為子節點數量;包含的元素數量 1<= K <=m-1,K為元素數量。

  什么是內部節點 ?

  節點【13,16,19】、節點【3,6】都為內部節點,特征:內部節點是除葉子節點和根節點之外的所有節點,擁有父節點和子節點。

  假定m階B樹的內部節點的子節點數量為M,則一定要符合(m/2)<=  M <=m關系式,包含元素數量M-1;包含的元素數量 (m/2)-1<= K <=m-1,K為元素數量。m/2向上取整。

  什么是葉子節點?

  節點【1,2】、節點【11,12】等最后一層都為葉子節點,葉子節點對元素的數量有相同的限制,但是沒有子節點,也沒有指向子節點的指針。特征:在m階B樹中葉子節點的元素符合(m/2)-1<= K <=m-1。

  好了,概念已經清楚,不用着急背公式, 接着往下看

插入

  針對m階高度h的B樹,插入一個元素時,首先在B樹中是否存在,如果不存在,即在葉子結點處結束,然后在葉子結點中插入該新的元素。

  • 若該節點元素個數小於m-1,直接插入;
  • 若該節點元素個數等於m-1,引起節點分裂;以該節點中間元素為分界,取中間元素(偶數個數,中間兩個隨機選取)插入到父節點中;
  • 重復上面動作,直到所有節點符合B樹的規則;最壞的情況一直分裂到根節點,生成新的根節點,高度增加1;

  上面三段話為插入動作的核心,接下來以5階B樹為例,詳細講解插入的動作;

  5階B樹關鍵點:

    • 2<=根節點子節點個數<=5
    • 3<=內節點子節點個數<=5
    • 1<=根節點元素個數<=4
    • 2<=非根節點元素個數<=4

   示例

  創建一個5階的Btree。插入的數據有:3、14、7、1、8、5、11、17、13、6、23、12、20、26、4、16、18、24、25根據Btree特性,5階則一個磁盤空間最多有5個指針(存的查找路徑),4個關鍵字(存的數據)。那么具體插入如下

  

  圖(1)插入元素【8】后變為圖(2),此時根節點元素個數為5,不符合 1<=根節點元素個數<=4,進行分裂(真實情況是先分裂,然后插入元素,這里是為了直觀而先插入元素,下面的操作都一樣,不再贅述),取節點中間元素【7】,加入到父節點,左右分裂為2個節點,如圖(3)

  

  接着插入元素【5】,【11】,【17】時,不需要任何分裂操作,如圖(4)

  

  插入元素【13】

  

  節點元素超出最大數量,進行分裂,提取中間元素【13】,插入到父節點當中,如圖(6)

  

  接着插入元素【6】,【12】,【20】,【23】時,不需要任何分裂操作,如圖(7)

  

  插入【26】時,最右的葉子結點空間滿了,需要進行分裂操作,中間元素【20】上移到父節點中,注意通過上移中間元素,樹最終還是保持平衡,分裂結果的結點存在2個關鍵字元素。

  

  插入【4】時,導致最左邊的葉子結點被分裂,【4】恰好也是中間元素,上移到父節點中,然后元素【16】,【18】,【24】,【25】陸續插入不需要任何分裂操作  

  

  最后,當插入【19】時,含有【14】,【16】,【17】,【18】的結點需要分裂,把中間元素【17】上移到父節點中,但是情況來了,父節點中空間已經滿了,所以也要進行分裂,將父節點中的中間元素【13】上移到新形成的根結點中,這樣具體插入操作的完成。

刪除

  首先查找B樹中需刪除的元素,如果該元素在B樹中存在,則將該元素在其結點中進行刪除;刪除該元素后,首先判斷該元素是否有左右孩子結點,如果有,則上移孩子結點中的某相近元素(“左孩子最右邊的節點”或“右孩子最左邊的節點”)到父節點中,然后是移動之后的情況;如果沒有,直接刪除。

  • 某結點中元素數目小於(m/2)-1,(m/2)向上取整,則需要看其某相鄰兄弟結點是否豐滿;
  • 如果豐滿(結點中元素個數大於(m/2)-1),則向父節點借一個元素來滿足條件;
  • 如果其相鄰兄弟都不豐滿,即其結點數目等於(m/2)-1,則該結點與其相鄰的某一兄弟結點進行“合並”成一個結點;

  接下來還以5階B樹為例,詳細講解刪除的動作;

  • 關鍵要領,元素個數小於 2(m/2 -1)就合並,大於4(m-1)就分裂

  如圖依次刪除依次刪除【8】,【20】,【18】,【5】

  

  首先刪除元素【8】,當然首先查找【8】,【8】在一個葉子結點中,刪除后該葉子結點元素個數為2,符合B樹規則,操作很簡單,咱們只需要移動【11】至原來【8】的位置,移動【12】至【11】的位置(也就是結點中刪除元素后面的元素向前移動)

  

  下一步,刪除【20】,因為【20】沒有在葉子結點中,而是在中間結點中找到,咱們發現他的繼承者【23】(字母升序的下個元素),將【23】上移到【20】的位置,然后將孩子結點中的【23】進行刪除,這里恰好刪除后,該孩子結點中元素個數大於2,無需進行合並操作。

  

  下一步刪除【18】,【18】在葉子結點中,但是該結點中元素數目為2,刪除導致只有1個元素,已經小於最小元素數目2,而由前面我們已經知道:如果其某個相鄰兄弟結點中比較豐滿(元素個數大於ceil(5/2)-1=2),則可以向父結點借一個元素,然后將最豐滿的相鄰兄弟結點中上移最后或最前一個元素到父節點中,在這個實例中,右相鄰兄弟結點中比較豐滿(3個元素大於2),所以先向父節點借一個元素【23】下移到該葉子結點中,代替原來【19】的位置,【19】前移;然【24】在相鄰右兄弟結點中上移到父結點中,最后在相鄰右兄弟結點中刪除【24】,后面元素前移。

  

  最后一步刪除【5】, 刪除后會導致很多問題,因為【5】所在的結點數目剛好達標,剛好滿足最小元素個數(ceil(5/2)-1=2),而相鄰的兄弟結點也是同樣的情況,刪除一個元素都不能滿足條件,所以需要該節點與某相鄰兄弟結點進行合並操作;首先移動父結點中的元素(該元素在兩個需要合並的兩個結點元素之間)下移到其子結點中,然后將這兩個結點進行合並成一個結點。所以在該實例中,咱們首先將父節點中的元素【4】下移到已經刪除【5】而只有【6】的結點中,然后將含有【4】和【6】的結點和含有【1】,【3】的相鄰兄弟結點進行合並成一個結點。

  

  也許你認為這樣刪除操作已經結束了,其實不然,在看看上圖,對於這種特殊情況,你立即會發現父節點只包含一個元素【7】,沒達標(因為非根節點包括葉子結點的元素K必須滿足於2=<K<=4,而此處的K=1),這是不能夠接受的。如果這個問題結點的相鄰兄弟比較豐滿,則可以向父結點借一個元素。而此時兄弟節點元素剛好為2,剛剛滿足,只能進行合並,而根結點中的唯一元素【13】下移到子結點,這樣,樹的高度減少一層。

  

  看完插入,刪除,想必也把B樹的特征掌握了

B樹的高度

  一棵含有N個總關鍵字數的m階的B樹的最大高度是多少?

  log(m/2)(N+1)/2 + 1  ,log以(m/2)為低,(N+1)/2的對數再加1

  算法如下

  

B+樹

  B+樹是應文件系統所需而產生的B樹的變形樹,那么可能一定會想到,既然有了B樹,又出一個B+樹,那B+樹必然是有很多優點的

  B+樹的特征:  

  • 有k個子結點的結點必然有k個關鍵碼;
  • 非葉結點僅具有索引作用,跟記錄有關的信息均存放在葉結點中。
  • 樹的所有葉結點構成一個有序鏈表,可以按照關鍵碼排序的次序遍歷全部記錄。

      

  B+樹的查詢操作

  在單元查詢的時候,B+樹會自定向下逐層查找,最終找到匹配的葉子節點。例如我們查找3 。

  

  

  

  而B+樹中間節點沒有Data數據,所以同樣大小的磁盤頁可以容納更多的節點元素。所以數據量相同的情況下,B+樹比B樹更加“矮胖“,因此使用的IO查詢次數更少。

  由於B樹的查找並不穩定(最好的情況是查詢根節點,最壞查詢葉子節點)。而B樹每一次查找都是穩定的。

  比起B樹,B+樹 ①IO次數更少 ②查詢性能很穩定 ③范圍查詢更簡便

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM