文章目录
数据结构-红黑树
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采用哨兵来实现。
下面是一个红黑树的示例图:
该树满足上面红黑树的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,后面只需要执行
RB-TRANSPLANT(T,z,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-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;
}