数据结构-红黑树

数据结构-红黑树

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

右旋的操作与左旋的操作对称,因此只需要将其中出现的leftright进行对调即可。

下面是左旋和右旋的实例操作。
对结点12右旋
对结点12左旋

插入操作

红黑树的插入操作(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为右子树时,与作为左子树的情况相对称,因此,只需要将处理左子树的情况中的leftright进行对调即可。后面将结合例子讲以上这三种情况。这三种情况并不是相互独立,其中 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
RB-INSERT-FIXUP case 1

情况 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继续连接上层结点,同时满足红黑树的性质
RB-INSERT-FIXUP case 2 and 3

 无论是从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为右孩子时,只需要将处理左孩子的情况中出现的leftright进行对调即可。

首先注意, 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。
RB-DELETE-FIXUP case 1

情况 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)

RB-DELETE-FIXUP case 2

情况 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。

如图:
RB-DELETE-FIXUP case 3

情况 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值