1. 程式人生 > >【資料結構與演算法】B/B+ 樹 、RB樹

【資料結構與演算法】B/B+ 樹 、RB樹

B / B+ / B*樹採用 多叉樹 結構降低樹深度,主要用在磁碟檔案系統與資料庫。

參考自:

B 樹

通常我們所說的 B樹 或 B-樹,其實指的是一種樹,這裡我將其稱為 B樹。

一顆 M 階的 B樹具有以下特點:

1)樹的根或者是一片葉子,或者其兒子數在 2 和 M 之間;

2)除根外,所有非樹葉節點的兒子數在 ⌈M/2⌉ 和 M 之間;

3)所有的樹葉都在相同的深度上。

B樹的深度最多是:⌈log⌈M/2⌉ N⌉。這個公式表明 B樹 的高度可以較小。

B樹是為了磁碟或其它儲存裝置而設計的一種多叉平衡查詢樹,在降低磁碟I/0操作方面效能較好,許多資料庫系統一般使用B樹或者B樹的各種變形結構。

B樹 有多種實現方式,這裡給出網上常見的一種:


特點如下:

1)所有鍵值分佈在整顆樹中;
2)任何一個關鍵字出現且只出現在一個結點中;
3)搜尋有可能在非葉子結點結束;
4)在關鍵字全集內做一次查詢,效能逼近二分查詢。

要注意的是《資料結構與演算法》一書中的 B樹 與這棵樹有所區別,它更像下面的 B+ 樹,但其樹葉之間沒有鏈指標。

B+ 樹


1)B+樹 和 B樹 的區別主要在於 B+樹 的非葉節點並無指向關鍵字具體資訊的指標,所以 B+樹 的節點大小相對於 B樹 就會小一些,如果把所有同一內部結點的關鍵字存放在同一盤塊中,那麼盤塊所能容納的關鍵字數量也越多,一次性讀入記憶體中的關鍵字也就越多,相對來說IO讀寫次數也就降低了。正因為這個原因,B+樹 的搜尋必須到葉節點,那裡才有指向關鍵字資訊的指標,而 B樹 的搜尋則可能在非葉節點結束,因為其非葉節點有指向關鍵字資訊的指標。

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

3)B+樹只要遍歷葉子節點就可以實現整棵樹的遍歷,支援基於範圍的查詢,而B樹不支援這樣的操作(或者說效率太低)。

通過以上介紹,大致將B樹,B+樹總結如下:

1)B樹:有序陣列+平衡多叉樹;
2)B+樹:有序陣列連結串列+平衡多叉樹.

無論是B樹,還是B+樹,由於根或者樹的上面幾層被反覆查詢,所以這幾塊可以存在記憶體中,換言之,B樹、B+樹的根結點和部分頂層資料在記憶體中,大部分下層資料在磁碟上。

紅黑樹等資料結構也可以用來實現索引,但是檔案系統及資料庫系統普遍採用B/B+Tree作為索引結構,一般來說,索引本身也很大,不可能全部儲存在記憶體中,因此索引往往以索引檔案的形式儲存的磁碟上。這樣的話,索引查詢過程中就要產生磁碟I/O消耗,相對於記憶體存取,I/O存取的消耗要高几個數量級,所以評價一個數據結構作為索引的優劣最重要的指標就是在查詢過程中磁碟I/O操作次數的漸進複雜度。換句話說,索引的結構組織要儘量減少查詢過程中磁碟I/O的存取次數。一般來說,B/B+樹的出度很大,所以樹的深度就會比較小。而紅黑樹就會深很多。

RB 樹

RB樹與AVL樹類似,也是一種平衡二叉查詢樹,廣泛應用與 STL(set,map),Linux的程序排程(管理程序控制塊),epoll在核心中的實現(管理事件塊),nginx中(管理timer),對 RB樹 的操作在最壞情形下花費 O(logN)。

紅黑樹的特性:

(1)每個節點或者是黑色,或者是紅色;
(2)根節點是黑色;
(3)如果一個節點是紅色的,則它的子節點必須是黑色的;
(4)從一個節點到NULL節點的任意路徑上包含相同數目的黑節點(確保沒有一條路徑會比其他路徑長出倆倍。因而,紅黑樹是相對是接近平衡的二叉樹);

(5)NULL 節點是黑色的。

紅黑樹示意圖:


著色法則的一個推論是,紅黑樹的高度最多是 2log(N + 1)。經驗指出,平均紅黑樹大約和平均AVL樹一樣深,從而查詢時間一般接近最優,紅黑樹的優點是執行插入所需要的開銷相對於AVL較低,再有就是實踐中發生的旋轉相對較小。但是,紅黑樹的具體實現是複雜的,不僅因為有大量可能的旋轉,而且還因為一些子樹可能是空的,以及處理根的特殊情況(尤其是根沒有父節點)。

紅黑樹的 Insert 操作有兩種做法:

1)自底向上(插入的樹葉塗紅色)

2)自頂向下(兩個兒子都是紅色的翻轉顏色)

兩種方法都會涉及單旋轉與雙旋轉的操作,類似AVL樹,但注意還要變換顏色。

Delete操作可用自底向上,也可自頂向下。

AVL 樹和紅黑樹的比較:

1)如果插入一個node引起了樹的不平衡,AVL和RB-Tree都是最多隻需要2次旋轉操作,即兩者都是O(1);但是在刪除node引起樹的不平衡時,最壞情況下,AVL需要維護從被刪node到root這條路徑上所有node的平衡性,因此需要旋轉的量級O(logN),而RB-Tree最多隻需3次旋轉,只需要O(1)的複雜度。
2)其次,AVL的結構相較RB-Tree來說更為平衡,在插入和刪除node更容易引起Tree的unbalance,因此在大量資料需要插入或者刪除時,AVL需要rebalance的頻率會更高。因此,RB-Tree在需要大量插入和刪除node的場景下,效率更高。自然,由於AVL高度平衡,因此AVL的search效率更高。
3)map的實現只是折衷了兩者在search、insert以及delete下的效率。總體來說,RB-tree的統計效能是高於AVL的。

這裡的講解還不錯: