红黑树
下面网址中是红黑树很好的教材,很详细。
http://blog.csdn.net/eric491179912/article/details/6179908
另外经典教材就是算法导论中关于红黑树的章节了,以算法导论为主,实在不明白的地方再去网上查找资料。
红黑树是一种特殊的二叉查找树,大家都知道二叉查找树的复杂度最坏情况为O(h),为了减低最坏情况的复杂度,大神们设计了许多种二叉查找树的改进版本,红黑树便是其中之一,它可以保证在最坏情况下复杂度为O(lgn),也就是说h < lgn。
红黑树的五个性质
1)每个节点或者是红色,或者是黑色
2)根节点是黑色
3)每个叶子节点是黑色的(此处的叶子节点指的是外部节点)
4)红色节点的两个孩子都是黑色的
5)对于每个节点,从该节点到其子孙叶子节点的所有路径上包含相同数目的黑色节点
红黑树节点的定义
typedef struct node
{
int color;
int key;
struct node *p;//指向父节点
struct node *left, *right;
}RBtreeNode;
与二叉搜索树相比较,多出了2部分,本节点的颜色属性和指向父节点是指针,之所以需要指向父节点是为了后序操作的便利。
红黑树的左旋和右旋
在节点x上左旋,是以x和x的右孩子y之间的轴为支点,旋转结束后x成为y的左孩子;在节点y上右旋,是以y和y的左孩子x之间的轴为支点,旋转结束后y是x的右孩子;如图所示
,理论上与二叉搜索树的旋转没有任何区别
红黑树的插入
假设新插入节点z,我们将其置为红色,可能破坏性质2)和性质4),违反性质2)是因为新插入的点成为了根节点,违反性质4)是因为z->p也是红色;插入z后,从底向上逐层调整树的结构和颜色,使其仍然满足红黑树的性质。既然从底层开始调整,我们可以只考虑违反性质4),当然在调整过程中绝不允许出现违反其他性质的现象。
前提z的父亲是红色
case1--z的叔叔是红色
z的叔叔uncle_z是红色,那z的爷爷肯定是黑色,可以把z的父亲和叔叔置为黑色,z的爷爷置为红色,z <- z的爷爷,然后继续向上操作。

case2--uncle_z是黑色,且z和uncle_z不是同一方向的孩子,即z是左孩子,uncle_z是右孩子;或者z是右孩子,uncle_z是左孩子
case2.1--z是左孩子,uncle_z是右孩子,如下面左图所示。我们以z的爷爷为输入,做一次右旋操作,同时把parent_z置为黑色,gparent_z置为红色,整棵树调整结束。
左右分割 
case2.2--z是右孩子,uncle_z是左孩子,如上面右图所示。我们,以z的爷爷为输入,做一次左旋操作,同时把parent_z置为黑色,gparent_z置为红色,整棵树调整结束。
可以看到,case2.1和case2.2是对称的两种情况。
case3--uncle_z是黑色,且z和uncle_z是同一方向的孩子,即z是左孩子,uncle_z也是左孩子;或者z是右孩子,uncle_z也是右孩子
case3.1--z和uncle_z同时是左孩子,如下面左图所示。我们以z的父亲为输入,做一次右旋操作,同时把z置为旋转前z的父亲,变成了case2.2,有木有!!
左右分割 
case3.2--z和uncle_z同时是右孩子,如上面右图所示。我们以z的父亲为输入,做一次左旋操作,同时把z置为旋转前z的父亲,变成了case2.1。
插入的最后,在把root的颜色置为黑色,完事。
红黑树的删除
假设被删除节点是z,可以找到真正要被删除的节点y,即如果z至多有一个孩子,y等于z;否则y是z的中序后继,此时y至多有一个右孩子;总的说来y至多只有一个右孩子x。如果y是红色,删除y后仍然能够保证红黑树的5个性质;如果y是黑色,可能违反性质2),4),5)。删除y时就是把x代替了y的位置,我们可以给x额外增加一个黑色,使其成为了双黑色和红黑色,这样满足了性质5),但违反性质1)。
如果x是红黑色,我们将其置为黑色,调整结束;
如果x是根节点,我们将其置为黑色,结束;
如果x是双黑色,做必要的旋转和涂色。
假设parent_x为删除节点y后x的父节点,实际上就是y的父节点,那么parent_x一定是有两个孩子的,因为此时y非空,且y是黑色,在不违反性质5)的前提下,y一定有兄弟。令parent_x的另一个孩子为w,即x的兄弟为w
case1--w为黑色,且w的两个孩子都是黑色
因为w是黑色,x是双重黑色,可以同时去掉x和w的黑色,x的父节点增加一重黑色,不会违反性质5),然后把x赋值给x的父节点,继续循环。如下面两幅图所示
左右分割 
case2--w是黑色,且w同一方向的孩子是红色,即若w是左孩子,w的左孩子是红色;若w是右孩子,w的右孩子是红色。我们可以通过旋转使x的高度减一,并且在x和x的父亲之间增加一个黑色节点,最后把x置为根节点,循环结束
case2.1--w是黑色,w是左孩子,w的左孩子是红色,以w的父节点为输入,做一次左旋,并且做一些颜色涂改
左右分割 
case2.2--w是黑色,w是右孩子,w的右孩子是红色,以w的父节点为输入,做一次右旋,并且做一些颜色涂改
case3--w是黑色,w同一方向的孩子是黑色,我们可以通过旋转使其转化为case2
case3.1--w是黑色,w是左孩子,w的左孩子是黑色,那么右孩子一定是红色,否则就成了case1;以w为输入,做一次右旋,变成了case2.1
左右分割 
case3.2--w是黑色,w是右孩子,w的右孩子是黑色,那么左孩子一定是红色,否则就成了case1;以w为输入,做一次左旋,变成了case2.2
case4--w是红色的,则w肯定有黑孩子,parent_x是黑色的,以parent_x为输入,做一次左旋,可转变成case1,case2,或者case3

附源代码,另附测试数据的大神博客网址:http://blog.csdn.net/v_JULY_v/article/details/6284050
//红黑树基本操作
#include <stdio.h>
#include <list>
#define BLACK 0
#define RED 1
typedef struct node
{
int color;
int key;
struct node *p;
struct node *left, *right;
}treeNode;
//在节点x上左旋操作,以x和x右孩子之间的轴为支点,旋转结束后x成为y的左孩子
// x y
// / \ left_rotate / \
// lx y ---> x ry
// / \ / \
// ly ry lx ly
treeNode* left_rotate(treeNode* root, treeNode* x)
{
treeNode *y = x->right;
x->right = y->left;
if(y->left != NULL)
(y->left)->p = x;
y->p = x->p;
if(x->p == NULL)//x是根节点
root = y;
else if(x == (x->p)->left)
(x->p)->left = y;
else (x->p)->right = y;
y->left = x;
x->p = y;
return root;
}
//在节点y上的右旋操作,以y和y的左孩子x之间的轴为支点,旋转结束后y是x的右孩子
// y x
// / \ right_rotate / \
// x ry ---> lx y
// / \ / \
// lx rx rx ry
treeNode* right_rotate(treeNode* root, treeNode* y)
{
treeNode *x = y->left;
y->left = x->right;
if(x->right != NULL)
(x->right)->p = y;
x->p = y->p;
if(y->p == NULL)//y是根节点
root = x;
else if(y == (y->p)->left)
(y->p)->left = x;
else (y->p)->right = x;
x->right = y;
y->p = x;
return root;
}
//插入新的节点后必须得调整
treeNode* rb_insert_fixup(treeNode *root, treeNode *z)
{
treeNode *uncle_z;
while(z->p && z->p->color == RED && z->p->p)
{
if (z->p->p->left == z->p)//z的父亲是左孩子
{
uncle_z = z->p->p->right;//z的叔父是右孩子
//case1--叔父是右孩子,红色
if(uncle_z && uncle_z->color == RED)
{
uncle_z->color = BLACK;
z->p->color = BLACK;
z->p->p->color = RED;
z = z->p->p;
}
//case1 end
else
{
//case2--叔父是右孩子,黑色 z是右孩子
if (z == z->p->right)//如果z是右孩子
{
z = z->p;
root = left_rotate(root, z);
}
//case2 end
//case3--叔父是右孩子,黑色 z是左孩子
z->p->color = BLACK;
z->p->p->color = RED;
root = right_rotate(root, z->p->p);
//case3 end
}
}
else//z的父亲是右孩子
{
uncle_z = z->p->p->left;//z的叔父是左孩子
//case4--叔父是左孩子,红色
if (uncle_z && uncle_z->color == RED)
{
uncle_z->color = BLACK;
z->p->color = BLACK;
z->p->p->color = RED;
z = z->p->p;
}
//case4 end
else
{
//case5--叔父是左孩子,黑色,z是左孩子
if (z == z->p->left)
{
z = z->p;
root = right_rotate(root, z);
}
//case5 end
//case6--叔父是左孩子,黑色 z是右孩子
z->p->color = BLACK;
z->p->p->color = RED;
root = left_rotate(root, z->p->p);
//case6 end
}
}
}
root->color = BLACK;
return root;
}
//插入新的节点
treeNode* rb_insert(treeNode *root, int value)
{
treeNode *z = new treeNode;
z->key = value;
treeNode *x = root;
treeNode *y = NULL;
while(x != NULL)
{
y = x;
if(value == x->key)
return root;
if(value < x->key)
x = x->left;
else x = x->right;
}
z->p = y;
if (y == NULL)
{
root = z;
}
else
{
if(value < y->key)
y->left = z;
else
y->right = z;
}
z->left = NULL;
z->right = NULL;
z->color = RED;
root = rb_insert_fixup(root, z);
return root;
}
//删除节点x的父节点后调整, x相当于多重黑色或者红黑色
treeNode* rb_delete_fixup(treeNode *root, treeNode *x, treeNode *parent_x)
{
treeNode *w;//x_brother
while(x!=root && (x == NULL ||x->color == BLACK))
{
//x的父亲parent_x一定有两个孩子
if(x == parent_x->left)
{
w = parent_x->right;//x的右兄弟w
//case1--x的兄弟w为红色,则w肯定有黑孩子,左旋,转换成case2,case3....
if(w->color == RED)
{
w->color = BLACK;
parent_x->color = RED;
root = left_rotate(root, parent_x);
w = parent_x->right; //w重新置为parent_x的右孩子
}
//case1 end
//case2--w为黑色,w的两个孩子(如果有)也是黑色
if((w->left == NULL || w->left->color == BLACK) && (w->right == NULL || w->right->color == BLACK))
{
w->color = RED;
x = parent_x;
parent_x = parent_x->p;
}
//case2 end
else
{ //case3--w的右孩子是黑色,左孩子是红色
if(w->right == NULL || w->right->color == BLACK)
{
if(w->left != NULL)//如果w有左孩子,一定是红色
w->left->color = BLACK;
w->color = RED;
root = right_rotate(root, w);
w = parent_x->right;
}
//case3 end
//case4 w的右孩子是红色
if (w->right != NULL)//如果w有右孩子,一定是红色
w->right->color = BLACK;
w->color = parent_x->color;
parent_x->color = BLACK;
root = left_rotate(root, parent_x);
x = root;
}
}
else//与上面对称
{
w = parent_x->left;//x的左兄弟w
//case5--x的兄弟w为红色,则w肯定有黑孩子,右旋,转换成case2,case3....
if(w->color == RED)
{
w->color = BLACK;
parent_x->color = RED;
root = right_rotate(root, parent_x);
w = parent_x->left;
}
//case5 end
//case6--w为黑色,w的两个孩子(如果有)也是黑色
if((w->left == NULL || w->left->color == BLACK) && (w->right == NULL || w->right->color == BLACK))
{
w->color = RED;
x = parent_x;
parent_x = parent_x->p;
}
//case6 end
else
{
//case7--w的左孩子是黑色,右孩子是红色
if(w->left == NULL || w->left->color == BLACK)
{
if(w->right != NULL)
w->right->color = BLACK;
w->color = RED;
root = left_rotate(root, w);
w = parent_x->left;
}
//case7 end
//case8 w的左孩子是红色
if (w->left->color == RED)
w->left->color = BLACK;
w->color = parent_x->color;
parent_x->color = BLACK;
root = right_rotate(root, parent_x);
x = root;
//case8 end
}
}
}
if(x != NULL)
x->color = BLACK;
return root;
}
treeNode* rb_delete(treeNode *root, int value)
{
treeNode *z, *y, *x;
z = root;
while(z != NULL)
{
if(z->key == value)
break;
if(z->key < value)
z = z->right;
else
z = z->left;
}
if(z == NULL) //木有找到要删除的节点
return root;
y = z;
if(y->left!=NULL && y->right!=NULL)//两个孩子的情况,y是z的中序后继
{
y = y->right;
while (y->left != NULL)
{
y = y->left;
}
z->key = y->key;
}
//x是y唯一的孩子或者NULL
if(y->left != NULL)
x = y->left;
else x = y->right;
if(x)
x->p = y->p;
if(y->p == NULL)//y是根节点
root = x;
else if(y == y->p->left)
y->p->left = x;
else y->p->right = x;
if(y->color==BLACK)
root = rb_delete_fixup(root, x, y->p);
delete y;
return root;
}
treeNode* rb_find(treeNode *root, int value)
{
treeNode *x = root;
int h = 0;
while (x != NULL)
{
if (x->key == value)
{
if(x->color == RED)
printf("RED ");
else
printf("BLACK ");
printf("从0层计数,%d在第%d层\n", value, h);
return x;
}
if (x->key < value)
x = x->right;
else x = x->left;
h++;
}
return NULL;
}
void midOrder(treeNode *root)
{
if(root == NULL)
return;
midOrder(root->left);
printf("%d-", root->key);
if(root->color == RED)
printf("RED ");
else
printf("BLACK ");
midOrder(root->right);
}
void preOrder(treeNode *root)
{
if(root == NULL)
return;
printf("%d-", root->key);
if(root->color == RED)
printf("RED ");
else
printf("BLACK ");
preOrder(root->left);
preOrder(root->right);
}
int main()
{
int select, a;
treeNode *root = NULL;
do
{
printf("请输入选择 1--插入,2--查询, 3--删除, 4--输出中序和前序,其他跳出\n");
scanf("%d", &select);
if (select == 1)
{
printf("输入将要插入的值, -1表示结束\n");
while(scanf("%d", &a), a != -1)
{
root = rb_insert(root, a);
}
}
else if (select == 2)
{
printf("输入将要查询的值, -1表示退出查询\n");
while(scanf("%d", &a), a != -1)
{
if(rb_find(root, a) != NULL)
{
//printf("找到了\n");
}
else
printf("木有找到\n");
}
}
else if(select == 3)
{
printf("输入将要删除的值, -1表示退出删除\n");
while(scanf("%d", &a), a != -1)
{
root = rb_delete(root, a);
}
}
else if(select == 4)
{
printf("中序是:\n");
midOrder(root);
printf("\n前序是:\n");
preOrder(root);
printf("\n");
}
else break;
} while (true);
getchar();
return 0;
}
运行结果,据小雨自己测试没有错误,欢迎大家前来拍砖


浙公网安备 33010602011771号