B-Tree(B樹)
具體講解之前,有一點,再次強調下:B-樹,即為B樹。因為B樹的原英文名稱為B-tree,而國內很多人喜歡把B-tree譯作B-樹,其實,這是個非常不好的直譯,很容易讓人產生誤解。如人們可能會以為B-樹是一種樹,而B樹又是一種樹。而事實上是,B-tree就是指的B樹。特此說明。
m階B樹的M階指的是所有結點中的子結點個數的最大值。
一個m階B樹是一棵空樹,或者是滿足以下條件的樹:
(1)結點最多有m個分支。
(2)根結點最少有兩個分支,非根非葉結點至少有ceil(m/2)個分支。
(3)結點內關鍵字遞增排序。
(4)一個結點有n-1個關鍵字,則該結點有n個分支,將關鍵字一一隔開。
(5)結點中任何一個關鍵字,其左邊分支上的結點值都小於這個關鍵字,右邊分支的結點值都大於這個關鍵字。
(6)葉子結點處於同一層。
如圖5階B樹滿足:
(1)結點最多有5個分支(葉子結點)。
(2)根結點最少有兩個分支,非根非葉結點至少有3個分支。
(3)結點內關鍵字遞增排序。
(4)一個結點有2個關鍵字,則該結點有2+1個分支,將關鍵字一一隔開。
(5)結點中任何一個關鍵字,其左邊分支上的結點值都小於這個關鍵字,右邊分支的結點值都大於這個關鍵字。
(6)葉子結點處於同一層。
B樹插入操作
由上可知,m階B樹,非根非葉結點至少有ceil(m/2)個分支,最多由m個分支,則結點關鍵字個數的范圍為ceil(m/2)-1 ~ m-1。
B樹結點的插入是待插入結點的值與B樹結點依次比較的過程,從根結點開始,若小於當前結點的值,則遞歸與結點的左子樹進行比較,若大於則與右子樹進行比較。由此可見,B樹結點的插入總是落在葉子結點上,在插入過程中可能會破壞B樹的特征,如新關鍵字的插入使得結點中關鍵字的個數超過規定個數,則要進行結點拆分。
我們以關鍵字序列{1,2,6,7,11,4,8,13,10,5,17,9,16,20,3,12,14,18,19,15}創建一個5階B樹。
(1)確定結點關鍵字個數范圍,由於創建的是5階B樹,因此關鍵字的個數范圍為2~4。
(2)根結點最多可以容納4個關鍵字,依次插入關鍵字1、2、6、7
(3)插入關鍵字11,發現此時結點中關鍵字的個數變為5,超出范圍,需要拆分,去關鍵字數組中的中間位置,也就是k[3]=6,作為一個獨立的結點,即新的根結點,將關鍵字6左、右關鍵字分別做成兩個結點,作為新根結點的兩個分支(圖左為拆分前,圖右為拆分后)
(4)新關鍵字總是插在葉子結點上,插入關鍵字4、8、13
(5)關鍵字10需要插入在關鍵字8和11之間,此時又會出現關鍵字個數超出范圍的情況,因此需要拆分。拆分時需要將關鍵字10納入根結點中,並將10左右的關鍵字做成兩個新的結點連在根結點上。
(6)插入關鍵字5、17、9、16
(7)關鍵字20插入在關鍵字17以后,此時會造成結點關鍵字個數超出范圍,需要拆分,方法同上
(8)按照上述步驟依次插入關鍵字3、12、14、18、19
(9)插入最后一個關鍵字15,15應該插入在14之后,此時會出現關鍵字個數超出范圍的情況,則需要進行拆分,將13並入根結點,13並入根結點之后,又使得根結點的關鍵字個數超出范圍,需要再次進行拆分,將10作為新的根結點,並將10左、右關鍵字做成兩個新結點連接到新根結點的指針上,這種插入一個關鍵字之后出現多次拆分的情況稱為連鎖反應

B樹刪除操作
(2)刪除關鍵字15,15雖然也在終端結點上,但是不能直接刪除,因為刪除后當前結點中關鍵字的個數小於2。這是需要向其兄弟結點借關鍵字,顯然應該向其右兄弟來借關鍵字,因為左兄弟的關鍵字個數已經是下限2.借關鍵字不能直接將18移到15所在的結點上,因為這樣會使得15所在的結點上出現比17大的關鍵字,所以正確的借法應該是先用17覆蓋15,在用18覆蓋原來的17,最后刪除原來的18。
(3)刪除關鍵字4,4在終端結點上,但是此時4所在的結點的關鍵字個數已經到下限,需要借關鍵字,不過可以看到其左右兄弟結點已經沒有多余的關鍵字可借。
所以就需要進行關鍵字的合並。可以先將關鍵字4刪除,然后將關鍵字5、6、7、9進行合並作為一個結點鏈接在關鍵字3右邊的指針上,也可以將關鍵字1、2、3、5合並作為一個結點鏈接在關鍵字6左邊的指針上.
顯然上述兩種情況下都不滿足B-樹的規定,即出現了非根的雙分支結點,需要繼續進行合並。
B+樹

在B+樹上進行隨機查找、插入和刪除過程基本與B樹類似。只是在查找時,若非終端結點上的關鍵字等於給定值,並不終止,而是繼續向下直到葉子結點。因此,在B+樹,不管查找成功與否,每次查找都是走了一條從根到葉子結點的路徑。B+樹查找的分析類似於B樹。B+樹的插入僅在葉子結點上進行,當結點中的關鍵字個數大於m時要分裂成兩個結點,它們所含關鍵字的個數分別為ceil((m+1)/2)和floor((m+1)/2)。並且,它們的雙親結點中應同時包含這兩個結點中的最大關鍵字。B+樹的刪除也僅在葉子結點進行,當葉子結點中的最大關鍵字被刪除時,其在非終端結點中的值可以作為一個“分界關鍵字”存在。若因刪除而使結點中關鍵字個數少於ceil(m/2)時,其和兄弟節點的合並過程亦和B樹類似。
B+樹和B樹的區別
1.B+樹中只有葉子結點會帶有指向記錄的指針,而B樹則所有結點都帶有,在內部節點出現的索引項不會再出現在葉子結點中。
2.B+樹中所有葉子結點都是通過指針連接在一起的,而B樹不會。
B+樹相比於B樹的查詢優勢
在學習HashMap的時候,當桶存儲的鏈表長度大於8時,鏈表會轉變為紅黑樹,因此學習一下紅黑樹,在此紀錄以備查詢。
紅黑樹
紅黑樹(Red Black Tree) 是一種自平衡二叉查找樹。紅黑樹和AVL樹類似,都是在進行插入和刪除操作時通過特定操作保持二叉查找樹的平衡,從而獲得較高的查找性能。
它雖然是復雜的,但它的最壞情況運行時間也是非常良好的,並且在實踐中是高效的: 它可以在O(log n)時間內做查找,插入和刪除,這里的n 是樹中元素的數目。

從圖可以看出,從根節點到每一個葉節點(NIL),都包含了相同數量的黑色節點。
當我們進行插入、刪除操作,所做的一切都是為了調整紅黑樹使之符合這五條性質。
預備知識
1.插入的節點顏色永遠為紅色
如果插入的節點為黑色,則違反性質5,如果節點為紅色,則少違背一條性質,減少代價。
2.左旋和右旋
這個和平衡二叉樹的左旋右旋時一致的。
3.節點關系
4.二叉排序樹的插入和刪除
1.插入:紅黑樹通過二叉查找樹的插入方法來找到要插入的位置。
2.刪除:
1.如果刪除的是葉節點,可以直接刪除;
2.如果被刪除的元素有一個子節點,可以將子節點直接移到被刪除元素的位置;
3.如果要刪除節點的左右孩子都存在,則將被刪除節點與后繼節點(位於被刪除節點的右子樹上)互換位置,再將被刪除節點刪除。
插入節點
首先根據二叉查找樹的插入方法,找到要插入的位置。
1.插入節點是根節點時
直接塗黑即可,滿足五條性質。
2.插入節點的父節點是黑色時
直接插入即可,滿足五條性質。
3.①父節點為紅色②父節點是祖父節點的左孩子
兩種情況:
1.叔叔節點為黑
繼續細分兩種情況:
(1)要插入節點是父節點的左孩子
違反性質4,對應的操作:
1)將祖父節點和父節點的顏色進行互換。
2)將祖父節點進行右旋。
(2)要插入節點是父節點的右孩子
對應的操作:
1)對父節點進行左旋
2)這是情況轉變為上一種情況
2.叔叔節點為紅
對應操作:
1)將“父節點”設為黑色。
2)將“叔叔節點”設為黑色。
3)將“祖父節點”設為紅色。
4)將“祖父節點”設為“當前節點”(紅色節點)。
5)繼續對“當前節點”進行操作。
4.①父節點為紅色②父節點是祖父節點的右孩子
和上一小節為鏡像情況
刪除節點
加入顏色之后,被刪除元素和后繼元素互換只是值的互換,並不互換顏色,這個要注意。
1.當刪除的節點是紅色時,直接拿其孩子節點補控位即可,性質5仍然滿足。
2.當刪除的節點是黑色時,性質5被破壞
(1)如果該節點的孩子節點為紅色時,直接拿孩子節點替換被刪除的節點,並將孩子節點染成黑色。
(2)如果孩子節點為黑色,分為6種情況。
在對這6中情況進行分析之前,我們先做一些假設,我們刪除的節點是X(至多只有一個孩子節點),其孩子節點為N,X的兄弟節點是S,S的左節點為SL,右節點是SR。
接下來的討論是建立在節點X(黑色)已經被刪除,節點N已經替換X的基礎上進行的。
情況一:
要刪除的節點X是根節點,且左右孩子節點均為空節點,此時將節點X用空節點替換完成刪除操作。
情況二:
S為紅色,其他節點為黑色。這種情況下對N的父節點進行左旋操作,然后互換P與S的顏色。但這並未結束,經過節點P和N的路徑刪除前有3個黑色節點(P -> X -> N),現在只剩兩個了(P -> N)。比未經過N的路徑少一個黑色節點,性質5仍不滿足,還需要繼續調整。不過此時可以按照情況四、五、六進行調整。
情況三:
N 的父節點,兄弟節點 S 和 S 的孩子節點均為黑色。這種情況下可以簡單的把 S 染成紅色,所有經過 S 的路徑比之前少了一個黑色節點,這樣經過 N 的路徑和經過 S 的路徑黑色節點數量一致了。但經過 P 的路徑比不經過 P 的路徑少一個黑色節點,此時需要從情況一開始對 P 進行平衡處理。
情況四:
N 的父節點是紅色,S 和 S 孩子為黑色。這種情況比較簡單,我們只需交換 P 和 S 顏色即可。這樣所有通過 N 的路徑上增加了一個黑色節點,所有通過 S 的節點的路徑必然也通過 P 節點,由於 P 與 S 只是互換顏色,並不影響這些路徑。
情況五:
S 為黑色,S 的左孩子為紅色,右孩子為黑色。N 的父節點顏色可紅可黑,且 N 是 P 左孩子。這種情況下對 S 進行右旋操作,並互換 S 和 SL 的顏色。此時,所有路徑上的黑色數量仍然相等,N 兄弟節點的由 S 變為了 SL,而 SL 的右孩子變為紅色。接下來我們到情況六繼續分析。
情況六:
S 為黑色,S 的右孩子為紅色。N 的父節點顏色可紅可黑,且 N 是其父節點左孩子。這種情況下,我們對 P 進行左旋操作,並互換 P 和 S 的顏色,並將 SR 變為黑色。因為 P 變為黑色,所以經過 N 的路徑多了一個黑色節點,經過 N 的路徑上的黑色節點與刪除前的數量一致。對於不經過 N 的路徑,則有以下兩種情況:
- 該路徑經過 N 新的兄弟節點 SL ,那它之前必然經過 S 和 P。而 S 和 P 現在只是交換顏色,對於經過 SL 的路徑不影響。
- 該路徑經過 N 新的叔叔節點 SR,那它之前必然經過 P、 S 和 SR,而現在它只經過 S 和 SR。在對 P 進行左旋,並與 S 換色后,經過 SR 的路徑少了一個黑色節點,性質5被打破。另外,由於 S 的顏色可紅可黑,如果 S 是紅色的話,會與 SR 形成連續的紅色節點,打破性質4(每個紅色節點必須有兩個黑色的子節點)。此時僅需將 SR 由紅色變為黑色即可同時恢復性質4和性質5(從任一節點到其每個葉子的所有簡單路徑都包含相同數目的黑色節點。)。
參考文獻
1. B-樹(B樹)詳解
2.《數據結構》— 嚴蔚敏
4. 最容易懂得紅黑樹