文章目錄
- 資料結構-紅黑樹
-
- 1、紅黑樹簡介
- 紅黑樹的性質
-
- 紅黑樹結點
- 紅黑樹的5個性質
- 2、紅黑樹的操作
-
- 旋轉
- 插入操作
-
- 情況 1:z的叔結點y為紅色
- 情況 2:z的叔結點y為黑色的且z是一個右孩子
- 情況 3:z的叔結點y為黑色的且z是一個左孩子
- 删除操作
-
- 情況 1:x的兄弟結點w是紅色的
- 情況 2:x的兄弟結點w是黑色的,而且w的兩個子結點都是黑色的
- 情況 3:x的兄弟結點w是黑色的,w的左孩子是紅色的,w的右孩子是黑色的。
- 情況 4:x的兄弟結點w是黑色的,w的右孩子是紅色的
- 3、紅黑樹的實作
資料結構-紅黑樹
1、紅黑樹簡介
紅黑樹(red-black tree)是一種平衡的搜尋樹,常見的平衡搜尋樹包括
AVL樹
、
B樹
、
AA樹
、
treap樹
、
SBT樹
、
替罪羊樹
、
伸展樹
、
跳表
等。紅黑樹支援在最壞情況下對動态集合操作的時間複雜度為 O ( l g n ) O(lgn) O(lgn)。平衡樹的時間複雜度均為 O ( l g n ) O(lgn) O(lgn),但是紅黑樹的性能最優,有很多應用。如C++的STL中的集合(set、multiset)、映射(map、multimap),在java中的TreeSet和TreeMap資料結構均用到紅黑樹。
紅黑樹的性質
紅黑樹是一棵二叉搜尋樹,每個結點均有一個顔色位(RED or BLACK)。通過對任何一條從根到葉子的簡單路徑上各個結點的顔色進行限制,紅黑樹確定沒有一條路徑會比其他路徑長出2倍。是以是近似平衡的。
紅黑樹結點
紅黑樹每個結點包括基本的5個域:Color、left、right、p、key。如果一個結點沒有子結點或父節點,則該結點相應指針指向 NIL。我們可以把 NIL實作為 空指針(nullptr)或 哨兵結點。我們可以把 NIL視為指向葉結點(外部結點)的指針,而把帶有關鍵字的結點視為内部結點。
紅黑樹的5個性質
1、每個結點為BLACK或RED
2、根節點顔色為BLACK
3、每個葉結點(NIL)為BLACK。
4、如果一個結點為RED,那麼它的兩個子結點均為BLACK
5、對于每個結點,該結點到其所有後代葉結點的簡單路徑上,均包含數目相同的BLACK結點。
在後面的實作中,NIL采用哨兵來實作。
下面是一個紅黑樹的示例圖:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL5lEVPlXRU50dRpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zROBlLxMDO1AzMzYTM3EDOwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
該樹滿足上面紅黑樹的5個性質。在後面的具體實作中,我們令根和子結點為空的結點相應的指針指向 T . n i l T.nil T.nil。
定理:對于n個結點一棵紅黑樹,它的高度之多為 2 l g ( n + 1 ) 2lg(n+1) 2lg(n+1)。具體證明過程看算法導論。
2、紅黑樹的操作
旋轉
紅黑樹是基于旋轉來維持平衡的,類是有
伸展樹
,
AVL樹
。也有無旋轉的平衡搜尋樹,如:
替罪羊樹
、
fhq reap樹
。幾乎所有的平衡樹都是基于旋轉來進行操作。通過旋轉來維持平衡樹的性質,同時可以保持樹的中序周遊結果不變。
紅黑樹的旋轉隻有左旋和右旋。分别是左旋和右旋的示意圖。
下面是
LEFT-ROTATE
的僞代碼,對樹 T T T中的 x x x進行左旋,其中假設 x . r i g h t ! = T . n i l x.right \ != T.nil x.right !=T.nil,且根節點的父節點為 T . n i l T.nil T.nil。
LEFT-ROTATE(T,x)
y = x.right //擷取x的右孩子
x.right = y.left //擷取新的右孩子
if y.left != T.nil
y.left.p = x
y.p = x.p //更新與父親結點間的連結
if x.p == T.nil
T.root = y
elseif x == x.p.left
x.p.left = y
else
x.p.right = y
y.left = x //将x作為y的左孩子
x.p = y
右旋的操作與左旋的操作對稱,是以隻需要将其中出現的
left
和
right
進行對調即可。
下面是左旋和右旋的執行個體操作。
插入操作
紅黑樹的插入操作(
RB-INSERT
)與BST的插入操作基本一緻,插入操作後,需要額外的操作,如通過旋轉,變換顔色等操作進行調整,使之滿足紅黑樹的性質,這些操作在
RB-INSERT-FIXUP
中完成。
下面是插入操作
RB-INSERT
的僞代碼,将結點 z z z,插入 T T T中合适為止。
RB-INSERT(T,z)
y = T.nil //父節點為止
x = T.root //插入位置
while x != T.nil
y = x
if z.key < x.key
x = x.left
else
x = x.right
z.p = y
if y == T.nil
T.root = z
elseif z.key < y.key
y.left = z
else y.right = z
z.left = z.right = T.nil
z.color = RED
RB-INSERT-FIXUP(T,z) //對樹進行調整
這裡不具體證明算法的正确性,可以參考算法導論。
下面是
RB-INSERT-FIXUP
的僞代碼。
RB-INSERT-FIXUP(T,z)
while z.p.color == RED
if z.p == z.p.p.left
y = z.p.p.left //uncle node
if y.color == RED
z.p.color = BLACK //case 1
y.color = BLACK //case 1
z.p.p.color = RED //case 1
z = z.p.p //case 1
else
if z == z.p.right
z = z.p //case 2
LEFT-ROTATE(T,z)//case 2
z.p.color = BLACK //case 3
z.p.p.color = RED //case 3
RIGHT-ROTATE(T,z.p.p)//case 3
else(same as then clause
with "right" and "left" exchanged)
T.root.color = BLACK
實際上紅黑樹的插入調整操作一共有6種情況,但是當 x . p x.p x.p為右子樹時,與作為左子樹的情況相對稱,是以,隻需要将處理左子樹的情況中的
left
和
right
進行對調即可。後面将結合例子講以上這三種情況。這三種情況并不是互相獨立,其中 case 2 完成後就可以變為 case 3。
在紅黑樹的插入調整操作中,case 1 通過變色來上升 z z z,使 z z z的叔結點代碼中的 y y y變為黑色轉化為case 2、3,而case 2 和case 3各通過旋轉,最終使其滿足紅黑樹性質。是以隻有case 1 可以不斷疊代,直至根節點時,它的 z . p = T . n i l z.p = T.nil z.p=T.nil。此時恒成立推出,是以時間複雜度為 l g n lgn lgn。
情況 1:z的叔結點y為紅色
如圖所示, z z z所指為目前發生沖突的結點,它與 z . p z.p z.p顔色均為紅色。同時叔結點 y y y為紅色。此時 z z z是左孩子還是右孩子均屬該情況。根據上面case 1的僞代碼,實質上通過将父節點 z . p z.p z.p 和叔結點 y y y變為黑色,同時令 z . p . p z.p.p z.p.p變為新的 z z z,令它為紅色。通過這樣的操作,實質上是将 z z z轉移上升,最終或者到達根節點,那麼推出while後置根節點為黑色,或者使之得到新的叔結點y的顔色為黑色,轉化為case 2 or 3。
情況 2:z的叔結點y為黑色的且z是一個右孩子
情況 3:z的叔結點y為黑色的且z是一個左孩子
如圖所示,在case2、3中,此時叔結點 y y y為黑色。如果為case 2,目前 z z z為有右孩子,那麼将 z z z變為 z . p z.p z.p,同時對結點 z z z進行一次左旋,使之變為情況3。在case 3中,将此時 z z z為左孩子,将 z . p z.p z.p置為黑色,同時将 z . p . p z.p.p z.p.p置為紅色,對 z . p . p z.p.p z.p.p進行一次右旋。完成case 3的操作後,此時已經滿足了紅黑樹的性質。
對于case 2而言,實際是通過旋轉和變色,使 z z z轉化為一個左孩子,然後在case 3中,我們通過旋轉和變色,相當于将C的黑色傳遞給B,令B代替C繼續連接配接上層結點,同時滿足紅黑樹的性質。
無論是從case 2到case 3還是直接從case 1到case 3。最多進行2次旋轉,可在常數時間内完成,結合case 1。
RB-TREE-FIXUP
的時間複雜度為 O ( l g n ) O(lgn) O(lgn)。是以,對于一次插入操作,總的時間複雜度為 O ( l g n ) O(lgn) O(lgn)。
删除操作
紅黑樹的删除操作(
RB-DELETE
)相比插入操作更複雜一點。類似BST的實作,删除某個結點,利用該結點的後繼代替該結點位置,若後繼存在右孩子,将其右孩子代替後繼的位置。處理完成後,類似插入操作,需要對樹進行調整,進而滿足紅黑樹的性質,該過程通過RB-DELETE-FIXUP函數完成。
下面使删除操作的僞代碼,将樹 T T T中的結點 z z z删除。
删除過程中,需要采用一個結點替換另外一個結點的位置,采用
RB-TRANSPLANT(T,x,y)
實作,該函數實作用 y y y結點(可以為空,我們的T.nil采用哨兵實作,一定存在,是以可以當成内部結點處理)。
下面是
RB-TRANSPLANT
的僞代碼
RB-TRANSPLANT(T,u,v)
if u.p == T.nil //u為根節點
T.root = v
elseif u == u.p.left
u.p.left = v
else
u.p.right = v
v.p = u.p
下面是删除操作
TREE-DELETE
的僞代碼
RB-DELETE(T,z)
y = z
y_original_color = y.color
if z.left == T.nil //左子樹為空,采用右子樹代替z
x = z.right
RB-TRANSPLANT(T,z,z.right)
elseif z.right == T.nil//右子樹為空,采用左子樹代替z
x = z.right
RB-TRANSPLANT(T,z,z.left)
else
y = TREE-MINIMUM(z.right) //采用後繼代替
y_original_color = y.color
x = y.right
if y.p == z //後繼是z的右孩子
x.p = y
else RB-TRANSPLANT(T,y,y.right)//不是右孩子,需要将y用其右孩子替換
y.right = z.right
y.right.p = y
RB-TRANSPLANT(T,z,y)
y.left = z.left
y.left.p = y
y.color = z.color
if y_original_color == BLACK //被取走的後繼是黑色,需要進行調整
RB-DELETE-FIXUP(T,x)
删除操作中 y y y記錄被删除的結點 z z z或作為替換 z z z的結點,同時 y _ o r i g i n a l _ c o l o r y\_original\_color y_original_color記錄它的顔色。同時記錄 y y y的右子樹 x x x,它是替換 y y y的結點,同時後面可能需要對 x x x為根的子樹進行調整。
- 假設 z z z隻有單個孩子或沒有孩子,那麼 y = z y = z y=z即是被删除的結點。 x = x . r i g h t x = x.right x=x.right為替換 y y y的結點。同時記錄 y _ o r i g i n a l _ c o l o r y\_original\_color y_original_color,如果 y _ o r i g i n a l _ c o l o r y\_original\_color y_original_color為紅色, ∵ y = z \because y = z ∵y=z最多隻有一個孩子,删除它後用它的孩子代替,不會影響紅黑樹的性質。否則如果 y y y為黑色,那麼将會引起 x x x為根的子樹的黑高減1,需要進行調整。即最後一行判斷語句。
- 假設 z z z存在兩個孩子,那麼取 y = y = y=TREE-MINIMUM( x . r i g h t x.right x.right),此時 y y y記錄替換 z z z的結點。同時更新 y _ o r i g i n a l _ c o l o r y\_original\_color y_original_color和 x x x。如果 y y y是 z z z的右孩子,此時我們令 x . p = y x.p = y x.p=y,後面隻需要執行
用 y y y替換 z z z,更新 y y y的左子樹連結,否則,需要用 x = y . r i g h t x = y.right x=y.right先替換 y y y,更新 y y y的右子樹連結。和上面相同,用 y y y替換 z z z,如果 y y y的顔色是黑色,會引起 x x x為根的子樹的黑高-1,需要後面進行調整。RB-TRANSPLANT(T,z,y)
詳細的證明參考算法導論
最後是
RB-DELETE-FIXUP
的僞代碼
RB-DELETE-FIXUP(T,x)
while x != T.root AND x.color == BLACK
if x == x.p.left
w = x.p.right //brother node
if w.color == RED
w.color = BLACK //case 1
x.p.color = RED //case 1
LEFT-ROTATE(T,x.w) //case 1
w = w.p.right //case 1
if w.left.color == BLAKC AND w.right.color == BLACK
w.color = RED //case 2
x = x.p //case 2
else
if w.right.color == BLACK
w.color = RED //case 3
w.left.color =BLACK //case 3
RIGHT-ROTATE(T,w) //case 3
w = x.p.right //case 3
w.color = x.p.color //case 4
x.p.color = BLACK //case 4
w.right.color = BLACK //case 4
LEFT-ROTATE(T,x.p) //case 4
x = T.root //case 4
else (same as then clause with "right" and "left" exchanged)
x.color = BLACK
上面講到,用删除 y y y 或 y y y 代替 z z z後,如果 y _ o r i g i n a l _ c o l o r y\_original\_color y_original_color為黑色,會引起 x x x為根的子樹的黑高減1。對于這個黑高減1,我們可以把它了解為 将 y y y 的黑色加到了結點 x x x上,此時 x x x為雙黑色或紅黑色,RB-DELETE-FIXUP的過程實質上就是通過旋轉和變色等操作,将結點 x x x上多出來的黑色抽取出來,放在另一個節點上,然後通過調整樹,使之滿足紅黑樹的性質。
紅黑樹的删除調整操作中,可以分為8種情況,類似插入調整操作。删除調整操作根據結點 x x x是左孩子還是右孩子分為對稱的4種操作。這裡實作 x x x為左孩子的情形,當 x x x為右孩子時,隻需要将處理左孩子的情況中出現的
left
和
right
進行對調即可。
首先注意, w h i l e while while循環時, x x x始終指向雙黑色結點,直到 x x x到達根節點,或者 x . c o l o r = R E D x.color = RED x.color=RED,即 x x x抽取出黑色,放置到其他點上,并滿足紅黑樹的性質。
這裡簡單概述下這4種情況。這4種情況并不是互相獨立的。
- 對于case 1,兄弟結點 w w w為紅色時,那麼可以通過旋轉變色擷取 w w w的一個黑色孩子,作為自己新的兄弟。當 x x x的兄弟為黑色時,此時轉化為case 2,3,4。
- 在 w w w的孩子均為黑色結點時,此時為case 2,我們可以将 x x x和 w w w的黑色抽出,傳遞給 x . p x.p x.p,此時 x . p x.p x.p成為新的 x x x進入下一輪循環。
- 若 w w w左孩子為紅色,右孩子為黑色,此時為case 3,然後我們通過旋轉和變色,令 w w w的右孩子為紅色,進而轉化為case 4。
- 當case 4時, w w w為紅色,同時它的右孩子為紅色,然後通過旋轉和變色,将 w w w的黑色抽取出來,放置在原來的父結點上,同時令 x = T . r o o t x = T.root x=T.root跳出循環。
下面将具體讨論 x x x為左孩子的4種情況。
情況 1:x的兄弟結點w是紅色的
如圖,此時結點 x x x為雙黑色,結點 w w w為紅色,那麼根據紅黑樹的性質4, w w w的父子結點均為黑色。我們将 x . p x.p x.p和 w w w的顔色交換,然後對 x . p x.p x.p進行進行一次左旋,最後更新 w w w,通過這樣的操作,我們将原來 w w w的一個黑色的孩子作為 x x x的兄弟。進而換為case 2,3,4。
情況 2:x的兄弟結點w是黑色的,而且w的兩個子結點都是黑色的
如圖,其中灰色的結點對顔色無要求,既可以是紅色也可以是黑色,實際程式設計中,不存在灰色結點。
此時, w w w為黑色,同時孩子均為黑色。此時,我們将 w . c o l o r = R E D w.color = RED w.color=RED,該操作實質上是将 x x x和 w w w的黑色抽出,放置到 x . p x.p x.p中,然後 x = x . p x = x.p x=x.p,此時 x . p x.p x.p稱為新的 x x x,因為此時它具有雙重顔色,或者紅黑色,或者雙黑色。如果是通過case 1轉化為case 2,那麼新的 x x x為紅黑色,此時将會跳出循環,同時,我們令 x . c o l o r = B L A C K x.color = BLACK x.color=BLACK,完成後,此時成功将 x x x的黑色抽出放在另一個結點上,同時滿足紅黑樹性質。如果 x . p x.p x.p原來為黑色,那麼它将變為雙黑色,則進入下一次 w h i l e while while循環。
最壞情況下,每次 w w w和它的孩子均是黑色,此時時間複雜度為 l g ( n ) lg(n) lg(n)。
情況 3:x的兄弟結點w是黑色的,w的左孩子是紅色的,w的右孩子是黑色的。
在case 2下面的else分支時,此時 w w w為黑色,進入該分支,說明 w w w的左子樹或者右子樹為紅色。我們的最終目的是使 w w w的右孩子為紅色結點。是以,在下面的
if x.right.color == BLACK
分支中,說明 w w w的左孩子為紅色,此時,我們通過交換 w w w和 w . l e f t w.left w.left的顔色,然後對 w w w進行一次右旋,進而使 w w w獲得一個紅色的右孩子,最後更新 w = x . p . r i g h t w = x.p.right w=x.p.right,成功為case 4。如果 i f if if分支不成立,說明本身具備紅色的右孩子,後面的操作也不需要關注左孩子的顔色,此時即為case 4。
如圖:
情況 4:x的兄弟結點w是黑色的,w的右孩子是紅色的
如圖,當 w w w為紅色,其他的右孩子是紅色時,此時,我們可以交換 x . p x.p x.p和 w w w的顔色,同時将 x . r i g h t x.right x.right置為黑色,然後左旋 x . p x.p x.p結點。最終滿足紅黑樹性質。令 x . p x.p x.p為黑色,實質上是使 x x x為根的子樹的黑高加1,相當于抽取出,x為黑色,此時x滿足性質1,x為根的子樹黑高加1滿足性質5,同時w的左子樹,即圖中的C的黑高不變。但是此時 w w w的右子樹黑高減1,但是我們可以通過将 w . r i g h t w.right w.right即圖中的E置為黑色,進而使其黑高不變,此時整體滿足紅黑樹性質,置 x = T . r o o t x = T.root x=T.root退出循環。
對于
RB-DELETE-FIXUP
唯一可能進行疊代的是case 2,沿樹上升至多 O ( l g n ) O(lgn) O(lgn)次期間不進行任何旋轉,對于case 1,3,4的旋轉操作,最多盡量3次。是以
RB-DELETE-FIXUP
的時間複雜度為 O ( l g n ) O(lgn) O(lgn)。
3、紅黑樹的實作
下面紅黑樹采用C++實作,為了和上面的僞代碼形式一緻,便于了解,沒有采用類封裝操作,隻包含一些C++特性。
#include<iostream>
#include<vector>
#include<queue>
#include<random>
#include<ctime>
using namespace std;
//定義顔色宏
enum COLOR{RED,BLACK};
//結點定義
template<typename T>
struct Node
{
Node<T>* left;
Node<T>* right;
Node<T>* p;
T key;
COLOR color;
Node():color(BLACK){}
};
//結點指針定義
template<typename T>
using pNode=Node<T>*;
//紅黑樹定義
template<typename T>
struct RBTree
{
static pNode<T> nil;
/**
* Singleton Model
* 采用local-static對象
* 使模闆參數相同的對象公用一個nil
* 在main函數前被使用。
* 具體參考 下面這篇部落格
* https://blog.csdn.net/qq_40512922/article/details/90589657#41_274
*/
static pNode<T> getInstance(){
static Node<T> one_instance;
return &one_instance;
}
pNode<T> root;
RBTree():root(nil){}
};
//初始化 nil
template<typename T>
pNode<T> RBTree<T>::nil=RBTree<T>::getInstance();
/*
Function Decleration
----------------------------------------
*/
template<typename T>//插入
void RBTree_insert(RBTree<T> &t,pNode<T> z);
template<typename T>//插入調整
void RBTree_insert_fixup(RBTree<T> &t,pNode<T> z);
template<typename T>//删除
void RBTree_delete(RBTree<T> &t,pNode<T> z);
template<typename T>//删除調整
void RBTree_delete_fixup(RBTree<T> &t,pNode<T> x);
template<typename T>//O(1)空間複雜度疊代中序周遊
void inorder_travel_iterative(pNode<T> x);
template<typename T>//正常遞歸中序周遊
void inorder_travel_recursive(pNode<T> x);
template<typename T>//結點x的後繼
pNode<T> tree_successor(pNode<T> x);
template<typename T>//利用後繼函數在O(n)有序周遊
void tree_travel_successor(pNode<T> x);
template<typename T>//左旋
void left_rotate(RBTree<T> &t,pNode<T> z);
template<typename T>//右旋
void right_rotate(RBTree<T> &t,pNode<T> z);
template<typename T>//結點x為根的子樹的最小值
pNode<T> tree_minimum(pNode<T> x);
template<typename T>//初始化Vector
void getInitVec(vector<pNode<T>> &vec);
template<typename T>//釋放記憶體
void freeVec(vector<pNode<T>> &vec);
template<typename T>//列印結點x
void print(const Node<T>*x);
/*
Function Definition
----------------------------------------
*/
template<typename T>
void print(const Node<T>*x)
{
cout << x->key;
if(x->color==BLACK)
cout << "[BLACK] ";
else
cout << "[RED] ";
}
template<typename T>
void inorder_travel_recursive(pNode<T> x)
{
if(x!=RBTree<T>::nil)
{
inorder_travel_recursive(x->left);
print(x);
inorder_travel_recursive(x->right);
}
}
template<typename T>
void inorder_travel_iterative(pNode<T> x)
{
if(x==RBTree<T>::nil)return;
pNode<T> y=RBTree<T>::nil;
while(true)
{
if(y!=x->left)
while(x->left!=RBTree<T>::nil)
x=x->left;
print(x);
if(x->right!=RBTree<T>::nil)
{
x=x->right;
continue;
}
do{
y=x;
x=x->p;
if(x==RBTree<T>::nil)
return;
}while(y==x->right);
}
}
template<typename T>
void left_rotate(RBTree<T> &t,pNode<T> x)
{
pNode<T> y=x->right;
x->right=y->left;
if(y->left!=RBTree<T>::nil)
y->left->p=x;
y->p=x->p;
if(x->p==RBTree<T>::nil)
t.root=y;
else if(x->p->left==x)
x->p->left=y;
else
x->p->right=y;
y->left=x;
x->p=y;
}
template<typename T>
void right_rotate(RBTree<T> &t,pNode<T> x)
{
pNode<T> y=x->left;
x->left=y->right;
if(y->right!=RBTree<T>::nil)
y->right->p=x;
y->p=x->p;
if(x->p==RBTree<T>::nil)
t.root=y;
else if(x->p->left==x)
x->p->left=y;
else
x->p->right=y;
y->right=x;
x->p=y;
}
template<typename T>
void RBTree_insert(RBTree<T> &t,pNode<T> z)
{
pNode<T> y=RBTree<T>::nil;
pNode<T> x=t.root;
while(x!=RBTree<T>::nil)
{
y=x;
if(z->key<x->key)
x=x->left;
else
x=x->right;
}
z->p=y;
if(y==RBTree<T>::nil)
t.root=z;
else if(z->key<y->key)
y->left=z;
else
y->right=z;
z->left=z->right=RBTree<T>::nil;
z->color=RED;
RBTree_insert_fixup(t,z);
}
template<typename T>
void RBTree_insert_fixup(RBTree<T> &t,pNode<T> z)
{
while(z->p->color==RED)
{
if(z->p==z->p->p->left)
{
pNode<T> y=z->p->p->right;
if(y->color==RED)
{
z->p->color=BLACK; //case 1
y->color=BLACK;
z->p->p->color=RED;
z=z->p->p;
}
else
{
if(z==z->p->right)
{
z=z->p; //case 2
left_rotate(t,z);
}
z->p->color=BLACK; //case 3
z->p->p->color=RED;
right_rotate(t,z->p->p);
}
}//end-if
else
{
pNode<T> y=z->p->p->left;
if(y->color==RED)
{
z->p->color=BLACK;
y->color=BLACK;
z->p->p->color=RED;
z=z->p->p;
}
else
{
if(z==z->p->left)
{
z=z->p;
right_rotate(t,z);
}
z->p->color=BLACK;
z->p->p->color=RED;
left_rotate(t,z->p->p);
}
}//end-else
}//end while
t.root->color=BLACK;
}
template<typename T>
pNode<T> tree_minimum(pNode<T> x)
{
while(x->left!=RBTree<T>::nil)
x=x->left;
return x;
}
template<typename T>
void RBTree_transplant(RBTree<T> &t,pNode<T> u,pNode<T> v)
{
if(u->p==RBTree<T>::nil)
t.root=v;
else if(u==u->p->left)
u->p->left=v;
else
u->p->right=v;
v->p=u->p;
}
template<typename T>
void RBTree_delete(RBTree<T> &t,pNode<T> z)
{
pNode<T> y=z;
pNode<T> x;
COLOR y_original_color=y->color;
if(z->left==RBTree<T>::nil)
{
x=z->right;
RBTree_transplant(t,z,z->right);
}
else if(z->right==RBTree<T>::nil)
{
x=z->left;
RBTree_transplant(t,z,z->left);
}
else
{
y=tree_minimum(z->right);
y_original_color=y->color;
x=y->right;
if(y->p==z)
x->p=y;
else
{
RBTree_transplant(t,y,y->right);
y->right=z->right;
y->right->p=y;
}
RBTree_transplant(t,z,y);
y->left=z->left;
y->left->p=y;
y->color=z->color;
}
if(y_original_color==BLACK)
RBTree_delete_fixup(t,x);
}
template<typename T>
void RBTree_delete_fixup(RBTree<T> &t,pNode<T> x)
{
while(x!=t.root&&x->color==BLACK)
{
if(x==x->p->left)
{
pNode<T> w=x->p->right;//兄弟
if(w->color==RED)
{
w->color=BLACK; //case 1
x->p->color=RED;
left_rotate(t,x->p);
w=x->p->right;
}
if(w->left->color==BLACK&&w->right->color==BLACK)
{
w->color=RED; //case 2
x=x->p;
}
else
{
if(w->right->color==BLACK)
{
w->left->color=BLACK; //case 3
w->color=RED;
right_rotate(t,w);
w=x->p->right;
}
w->color=x->p->color; //case 4
x->p->color=BLACK;
w->right->color=BLACK;
left_rotate(t,x->p);
x=t.root;
}
}//end-if
else
{
pNode<T> w=x->p->left;//兄弟
if(w->color==RED)
{
w->color=BLACK; //case 1
x->p->color=RED;
right_rotate(t,x->p);
w=x->p->left;
}
if(w->left->color==BLACK&&w->right->color==BLACK)
{
w->color=RED; //case 2
x=x->p;
}
else
{
if(w->left->color==BLACK)
{
w->right->color=BLACK; //case 3
w->color=RED;
left_rotate(t,w);
w=x->p->left;
}
w->color=x->p->color; //case 4
x->p->color=BLACK;
w->left->color=BLACK;
right_rotate(t,x->p);
x=t.root;
}
}//end-else
}
x->color=BLACK;
}
template<typename T>
pNode<T> RBTree_search(RBTree<T> t,T key)
{
pNode<T> x=t.root;
while(x!=RBTree<T>::nil)
{
if(key==x->key)
return x;
else if(key<x->key)
x=x->left;
else
x=x->right;
}
return x;
}
template<typename T>
pNode<T> tree_successor(pNode<T> x)
{
if(x->right!=RBTree<T>::nil)
return tree_minimum(x->right);
pNode<T> y=x->p;
while(y!=RBTree<T>::nil&&x==y->right)
{
x=y;
y=y->p;
}
return y;
}
template<typename T>
void tree_travel_successor(pNode<T> x)
{
if(x==RBTree<T>::nil)
return;
x=tree_minimum(x);
do{
print(x);
x=tree_successor(x);
}while(x!=RBTree<T>::nil);
}
/*
*特例化 integer類型的随機初始化模闆。
*因為下面的 uniform_int_distrbution隻支援整型。
*/
template<> void getInitVec(vector<pNode<int>> &vec)
{
static default_random_engine e(time(nullptr));
static uniform_int_distribution<int> d(0,50000);
int key;
for(auto &i:vec){
i=new Node<int>();
i->key=d(e);
}
}
/*
* 特例化double類型的随機初始化模闆
*/
template<> void getInitVec(vector<pNode<double>> &vec)
{
static default_random_engine e(time(nullptr));
static uniform_real_distribution<double> d(0,50000);
double key;
for(auto &i:vec){
i=new Node<double>();
i->key=d(e);
}
}
template<typename T>
void freeVec(vector<pNode<T>> &vec)
{
for(auto i:vec)
{
delete i;
i=nullptr;
}
}
void RBTree_property_test()
{
int cnt;
cout << "Input the cnt:" << endl;
cin >> cnt;
RBTree<int> T;
vector<pNode<int>> vec(cnt);
getInitVec(vec);
clock_t sta=clock();
for(auto i:vec)
RBTree_insert(T,i);
for(auto i:vec)
RBTree_delete(T,i);
clock_t interval=clock()-sta;
cout << "CLOCKS_PER_SEC = " << CLOCKS_PER_SEC << endl;
cout << "succed\n" << interval << " clocks (when CLOCKS_PER_SEC=1000,equal to ms)" << endl;
cout << interval/CLOCKS_PER_SEC << " s" << endl;
}
int main()
{
RBTree_property_test();
return 0;
}