B樹,B+樹


B樹

為什么要B樹

磁盤中有兩個機械運動的部分,分別是盤片旋轉和磁臂移動。盤片旋轉就是我們市面上所提到的多少轉每分鍾,而磁盤移動則是在盤片旋轉到指定位置以后,移動磁臂后開始進行數據的讀寫。那么這就存在一個定位到磁盤中的塊的過程,而定位是磁盤的存取中花費時間比較大的一塊,畢竟機械運動花費的時候要遠遠大於電子運動的時間。當大規模數據存儲到磁盤中的時候,顯然定位是一個非常花費時間的過程,但是我們可以通過B樹進行優化,提高磁盤讀取時定位的效率。

為什么B類樹可以進行優化呢?我們可以根據B類樹的特點,構造一個多階的B類樹,然后在盡量多的在結點上存儲相關的信息,保證層數盡量的少,以便后面我們可以更快的找到信息,磁盤的I/O操作也少一些,而且B類樹是平衡樹,每個結點到葉子結點的高度都是相同,這也保證了每個查詢是穩定的。

簡介

這里的B樹,也就是英文中的B-Tree,一個 m 階的B樹滿足以下條件:

  1. 每個結點至多擁有m棵子樹;
  2. 根結點至少擁有兩顆子樹(存在子樹的情況下);
  3. 除了根結點以外,其余每個分支結點至少擁有 m/2 棵子樹;
  4. 所有的葉結點都在同一層上;
  5. 有 k 棵子樹的分支結點則存在 k-1 個關鍵碼,關鍵碼按照遞增次序進行排列;
  6. 關鍵字數量需要滿足ceil(m/2)-1 <= n <= m-1;

舉個栗子:

B樹上大部分的操作所需要的磁盤存取次數和B樹的高度是成正比的,在B樹中可以檢查多個子結點,由於在一棵樹中檢查任意一個結點都需要一次磁盤訪問,所以B樹避免了大量的磁盤訪問。

操作

既然是樹,那么必不可少的操作就是插入和刪除,這也是B樹和其它數據結構不同的地方,當然了,還有必不可少的搜索,分享一個對B樹的操作進行可視化的網址,它是由usfca提供的。

假定對高度為h的m階B樹進行操作。

插入

新結點一般插在第h層,通過搜索找到對應的結點進行插入,那么根據即將插入的結點的數量又分為下面幾種情況。

  • 如果該結點的關鍵字個數沒有到達m-1個,那么直接插入即可;
  • 如果該結點的關鍵字個數已經到達了m-1個,那么根據B樹的性質顯然無法滿足,需要將其進行分裂。分裂的規則是該結點分成兩半,將中間的關鍵字進行提升,加入到父親結點中,但是這又可能存在父親結點也滿員的情況,則不得不向上進行回溯,甚至是要對根結點進行分裂,那么整棵樹都加了一層。

其過程如下:

刪除

同樣的,我們需要先通過搜索找到相應的值,存在則進行刪除,需要考慮刪除以后的情況,

  • 如果該結點擁有關鍵字數量仍然滿足B樹性質,則不做任何處理;
  • 如果該結點在刪除關鍵字以后不滿足B樹的性質(關鍵字沒有到達ceil(m/2)-1的數量),則需要向兄弟結點借關鍵字,這有分為兄弟結點的關鍵字數量是否足夠的情況。
    • 如果兄弟結點的關鍵字足夠借給該結點,則過程為將父親結點的關鍵字下移,兄弟結點的關鍵字上移;
    • 如果兄弟結點的關鍵字在借出去以后也無法滿足情況,即之前兄弟結點的關鍵字的數量為ceil(m/2)-1,借的一方的關鍵字數量為ceil(m/2)-2的情況,那么我們可以將該結點合並到兄弟結點中,合並之后的子結點數量少了一個,則需要將父親結點的關鍵字下放,如果父親結點不滿足性質,則向上回溯;
  • 其余情況參照BST中的刪除。

其過程如下:

B+樹

為什么要B+樹

由於B+樹的數據都存儲在葉子結點中,分支結點均為索引,方便掃庫,只需要掃一遍葉子結點即可,但是B樹因為其分支結點同樣存儲着數據,我們要找到具體的數據,需要進行一次中序遍歷按序來掃,所以B+樹更加適合在區間查詢的情況,所以通常B+樹用於數據庫索引,而B樹則常用於文件索引。(為什么B+樹更適合做數據庫索引)

簡介

同樣的,以一個m階樹為例:

  1. 根結點只有一個,分支數量范圍為[2,m];
  2. 分支結點,每個結點包含分支數范圍為[ceil(m/2), m];
  3. 分支結點的關鍵字數量等於其子分支的數量減一,關鍵字的數量范圍為[ceil(m/2)-1, m-1],關鍵字順序遞增;
  4. 所有葉子結點都在同一層;

 

B+樹和二叉樹、平衡二叉樹一樣,都是經典的數據結構。B+樹由B樹和索引順序訪問方法(ISAM,是不是很熟悉?對,這也是MyISAM引擎最初參考的數據結構)演化而來,但是在實際使用過程中幾乎已經沒有使用B樹的情況了。

B+樹的定義十分復雜,因此只簡要地介紹B+樹:B+樹是為磁盤或其他直接存取輔助設備而設計的一種平衡查找樹,在B+樹中,所有記錄節點都是按鍵值的大小順序存放在同一層的葉節點中,各葉節點指針進行連接。

我們先來看一個B+樹,其高度為2,每頁可存放4條記錄,扇出(fan out)為5。

可以看出,所有記錄都在葉節點中,並且是順序存放的,如果我們從最左邊的葉節點開始順序遍歷,可以得到所有鍵值的順序排序:5、10、15、20、25、30、50、55、60、65、75、80、85、90。

B+樹的插入操作

B+樹的插入必須保證插入后葉節點中的記錄依然排序,同時需要考慮插入B+樹的三種情況,每種情況都可能會導致不同的插入算法,如表5-1所示。 

我們用實例來分析B+樹的插入,我們插入28這個鍵值,發現當前Leaf Page和Index Page都沒有滿,我們直接插入就可以了。

這次我們再插入一條70這個鍵值,這時原先的Leaf Page已經滿了,但是Index Page還沒有滿,符合表5-1的第二種情況,這時插入Leaf Page后的情況為50、55、60、65、70。我們根據中間的值60拆分葉節點。

因為圖片顯示的關系,這次我沒有能在各葉節點加上雙向鏈表指針。最后我們來插入記錄95,這時符合表5-1討論的第三種情況,即Leaf Page和Index Page都滿了,這時需要做兩次拆分。

 

可以看到,不管怎么變化,B+樹總是會保持平衡。但是為了保持平衡,對於新插入的鍵值可能需要做大量的拆分頁(split)操作,而B+樹主要用於磁盤,因此頁的拆分意味着磁盤的操作,應該在可能的情況下盡量減少頁的拆分。因此,B+樹提供了旋轉(rotation)的功能。

旋轉發生在Leaf Page已經滿了、但是其左右兄弟節點沒有滿的情況下。這時B+樹並不會急於去做拆分頁的操作,而是將記錄移到所在頁的兄弟節點上。通常情況下,左兄弟被首先檢查用來做旋轉操作,這時我們插入鍵值70,其實B+樹並不會急於去拆分葉節點,而是做旋轉,50,55,55旋轉。

 

可以看到,采用旋轉操作使B+樹減少了一次頁的拆分操作,而這時B+樹的高度依然還是2。

B+樹的刪除操作

B+樹使用填充因子(fill factor)來控制樹的刪除變化,50%是填充因子可設的最小值。B+樹的刪除操作同樣必須保證刪除后葉節點中的記錄依然排序,同插入一樣,B+樹的刪除操作同樣需要考慮如表5-2所示的三種情況,與插入不同的是,刪除根據填充因子的變化來衡量。 

首先,刪除鍵值為70的這條記錄,該記錄符合表5-2討論的第一種情況,刪除后。

接着我們刪除鍵值為25的記錄,這也是表5-2討論的第一種情況,但是該值還是Index Page中的值,因此在刪除Leaf Page中25的值后,還應將25的右兄弟節點的28更新到Page Index中,最后可得到圖。

最后我們來看刪除鍵值為60的情況,刪除Leaf Page中鍵值為60的記錄后,填充因子小於50%,這時需要做合並操作,同樣,在刪除Index Page中相關記錄后需要做Index Page的合並操作,最后得到圖。

 


免責聲明!

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



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