转自 http://blog.youkuaiyun.com/Hackbuteer1?viewmode=contents and http://blog.youkuaiyun.com/v_JULY_v/article/details/6114226
hackbutter1
一、红黑树概述
红黑树和我们以前学过的AVL树类似,都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。不过自从红黑树出来 后,AVL树就被放到了博物馆里,据说是红黑树有更好的效率,更高的统计性能。这一点在我们了解了红黑树的实现原理后,就会有更加深切的体会。
红黑树和AVL树的区别在于它使用颜色来标识结点的高度,它所追求的是局部平衡而不是AVL树中的非常严格的平衡。学过数据结构的人应该都已经领教过AVL树的复杂,但AVL树的复杂比起红黑树来说简直是小巫见大巫,红黑树才是真正的变态级数据结构。
由于STL中的关联式容器默认的底层实现都是红黑树,因此红黑树对于后续学习STL源码还是很重要的,有必要掌握红黑树的实现原理和源码实现。
红黑树是AVL树的变种,红黑树通过一些着色法则确保没有一条路径会比其它路径长出两倍,因而达到接近平衡的目的。所谓红黑树,不仅是一个二叉搜索树,而且必须满足一下规则:
1、每个节点不是红色就是黑色。
2、根节点为黑色。
3、如果节点为红色,其子节点必须为黑色。
4、任意一个节点到到NULL(树尾端)的任何路径,所含之黑色节点数必须相同。
上面的这些约束保证了这个树大致上是平衡的,这也决定了红黑树的插入、删除、查询等操作是比较快速的。 根据规则4,新增节点必须为红色;根据规则3,新增节点之父节点必须为黑色。当新增节点根据二叉搜索树的规则到达其插入点时,却未能符合上述条件时,就必须调整颜色并旋转树形,如下图:
假设我们为上图分别插入节点3、8、35、75,根据二叉搜索树的规则,插入这四个节点后,我们会发现它们都破坏了红黑树的规则,因此我们必须调整树形,也就是旋转树形并改变节点的颜色。
在讨论红黑树的插入操作之前必须要明白,任何一个即将插入的新结点的初始颜色都为红色。这一点很容易理解,因为插入黑点会增加某条路径上黑结点的数目,从而导致整棵树黑高度的不平衡。但如果新结点的父结点为红色时(如下图所示),将会违反红黑树的性质:一条路径上不能出现相邻的两个红色结点。这时就需要通 过一系列操作来使红黑树保持平衡。
为了清楚地表示插入操作以下在结点中使用“新”字表示一个新插入的结点;使用“父”字表示新插入点的父结点;使用“叔”字表示“父”结点的兄弟结点;使用“祖”字表示“父”结点的父结点。插入操作分为以下几种情况:
1、黑父 (直接插)
如下图所示,如果新节点的父结点为黑色结点,那么插入一个红点将不会影响红黑树的平衡,此时插入操作完成。红黑树比AVL树优秀的地方之一在于黑父的情况比较常见,从而使红黑树需要旋转的几率相对AVL树来说会少一些。
2、红父(红父)
如果新节点的父结点为红色,这时就需要进行一系列操作以保证整棵树红黑性质。如下图所示,由于父结点为红色,此时可以判定,祖父结点必定为黑色。这时需要 根据叔父结点的颜色来决定做什么样的操作。青色结点表示颜色未知。由于有可能需要根结点到新点的路径上进行多次旋转操作,而每次进行不平衡判断的起始点 (我们可将其视为新点)都不一样。所以我们在此使用一个蓝色箭头指向这个起始点,并称之为判定点。
2.1 红叔(红父+红叔变黑祖父变红(当祖父是根的时候,必须为黑.))
当叔父结点为红色时,如下图所示,无需进行旋转操作,只要将父和叔结点变为黑色,将祖父结点变为红色即可。但由于祖父结点的父结点有可能为红色,从而违反红黑树性质。此时必须将祖父结点作为新的判定点继续向上(迭代)进行平衡操作。
需要注意的是,无论“父节点”在“叔节点”的左边还是右边,无论“新节点”是“父节点”的左孩子还是右孩子,它们的操作都是完全一样的(其实这种情况包括4种,只需调整颜色,不需要旋转树形)。
2.2 黑叔 (红父黑叔各种变)
当叔父结点为黑色时,需要进行旋转,以下图示了所有的旋转可能:
Case 1:
Case 2:
Case 3:
Case4:
可以观察到,当旋转完成后,新的旋转根全部为黑色,此时不需要再向上回溯进行平衡操作,插入操作完成。需要注意,上面四张图的“叔”、“1”、“2”、“3”结点有可能为黑哨兵结点。其实红黑树的插入操作不是很难,甚至比AVL树的插入操作还更简单些。
july
十、红黑树删除的4种情况
情况1:x的兄弟w是红色的。
情况2:x的兄弟w是黑色的,且w的俩个孩子都是黑色的。
情况3:x的兄弟w是黑色的,w的左孩子是红色,w的右孩子是黑色。
情况4:x的兄弟w是黑色的,且w的右孩子时红色的。
情况5: x为红色 直接删除
操作流程图:
ok,简单分析下,红黑树删除的4种情况:
针对情况1:x的兄弟w是红色的。
上图重要看伪代码
针对情况2:x的兄弟w是黑色的,且w的俩个孩子都是黑色的
针对情况3:x的兄弟w是黑色的,w的左孩子是红色,w的右孩子是黑色。
针对情况4:x的兄弟w是黑色的,且w的右孩子时红色的
code: july
#include <iostream>
typedef int key_t;
typedef int data_t;
typedef enum color_t
{
RED=0,
BLACK=1
}color_t;
typedef struct rb_node_t
{
struct rb_node_t *left,*right,*parent;
key_t key;
data_t data;
color_t color;
}rb_node_t;
rb_node_t* rb_insert(key_t key,data_t data,rb_node_t* root);
rb_node_t* rb_search(key_t key,rb_node_t* root);
rb_node_t* rb_insert_rebalance(rb_node_t* node,rb_node_t* root);
rb_node_t* rb_erase(key_t key,rb_node_t *root);
rb_node_t* rb_earse_rebalance(rb_node_t* node,rb_node_t* parent,rb_node_t* root);
static rb_node_t* rb_new_node(key_t key,data_t data)
{
rb_node_t* node=(rb_node_t*)malloc(sizeof(struct rb_node_t));
if(!node)
{
printf("malloc error!\n");
exit(-1);
}
node->key=key;
node->data=data;
return node;
}
//左旋
static rb_node_t* rb_rotate_left(rb_node_t* node,rb_node_t* root)
{
rb_node_t* right=node->right;
if((node->right=right->left))
{
right->left->parent=node;
}
right->left=node;
if((right->parent=node->parent))
{
if(node==node->parent->right)
node->parent->right=right;
else
node->parent->left=right;
}
else
{//根
root=right;
}
node->parent=right;
return root;
}
//右旋
static rb_node_t* rb_rotate_right(rb_node_t* node,rb_node_t* root)
{
rb_node_t* left=node->left;
if((node->left=left->right))
left->right->parent=node;
if((left->parent=node->parent))
{//node非根
if(node==node->parent->right)
node->parent->right=left;
else
node->parent->left=left;
}
else
root=left;
node->parent=left;
return root;
}
static rb_node_t* rb_search_auxiliary(key_t key,rb_node_t* root,rb_node_t** save)
{
rb_node_t *node=root,*parent=NULL;
int ret;
while(node)
{
parent=node;
ret=node->key-key;
if(0<ret)
node=node->left;
else if(0>ret)
node=node->right;
else
return node;
}
if(save)
*save=parent;
return NULL;//当没有找到的时候返回该插入节点的父节点
}
rb_node_t* rb_search(key_t key,rb_node_t* root)
{
return rb_search_auxiliary(key,root,NULL);
}
//红黑树的插入
rb_node_t* rb_insert(key_t key,data_t data,rb_node_t* root)
{
rb_node_t* parent=NULL;
rb_node_t* node;
parent=NULL;
if((node=rb_search_auxiliary(key,root,&parent)))//如果都已经有了就不需要在插入了
return root;
//parent返回的是该插入节点的位置
node=rb_new_node(key,data);
node->parent=parent;
node->left=node->right=NULL;
node->color=RED;
if(parent)
{
if(parent->key>key)
parent->left=node;
else
parent->right=node;
}
else
root=node;
return rb_insert_rebalance(node,root);
}
//红黑树的调整
//z表示当前节点,p[z]表示父母,p[p[z]]表示祖父,y表示叔叔
static rb_node_t* rb_insert_rebalance(rb_node_t* node,rb_node_t* root)
{
rb_node_t* parent;
rb_node_t* gparent;
rb_node_t* uncle;
rb_node_t* tmp;
while((parent=node->parent)&&parent->color==RED)
{//parent为node的父母,当父母颜色为红色的时候需要调整,否则不需要调整
gparent=parent->parent;//祖父
if(parent==gparent->left)//当祖父的左孩子为父亲是
{
uncle=gparent->right;
if(uncle&&uncle->color==RED)
{//红父红叔
uncle->color=BLACK;
parent->color=BLACK;
gparent->color=RED;
node=gparent;//将祖父作为新增节点卓为红色
}
else
{//红父黑叔右孩子
if(parent->right==node)
{
root=rb_rotate_left(parent,root);
tmp=parent;
parent=node;
node=tmp;//交换parent与node
}
parent->color=BLACK;//
gparent->color=RED;//祖父节点变为红色的
root=rb_rotate_right(gparent,root);
}
}
else
{
uncle=gparent->left;//祖父的做孩子作为叔叔节点
if(uncle&&uncle->color==RED)
{//叔叔父亲全是红色的
uncle->color=BLACK;
parent->color=BLACK;
gparent->color=RED;
node=gparent;
}
else
{//黑叔叔
if(parent->left==node)
{//左孩子黑叔叔
root=rb_rotate_right(parent,root);
tmp=parent;
parent=node;
node=tmp;
}
// 右边孩子,黑叔叔
parent->color=BLACK;
gparent->color=RED;
root=rb_rotate_left(gparent,root);
}
}
}
root->color=BLACK;
return root;
}
//红黑树的删除操作
static rb_node_t* rb_erase(key_t key,rb_node_t *root)
{
rb_node_t *child,*parent,*old,*left,*node;
color_t color;
if(!(node=rb_search_auxiliary(key,root,NULL)))
{//如果就没有找到直接返回
printf("key %d is not exist!\n");
return root;
}
old=node;
if(node->left&&node->right)
{//node有左右孩子,并且需要删除node节点,用node的直接后继替换之
node=node->right;//找old节点的直接后继
while((left=node->left)!=NULL)
node=left;
child=node->right;
parent=node->parent;
color=node->color;
if(child)
{
child->parent=parent;
}
if(parent)
{
if(parent->left==node)
parent->left=child;
else
parent->right=child;
}
else
{
root=child;
}
if(node->parent==old)
{
parent=node;
}
node->parent=old->parent;
node->color=old->color;
node->right=old->right;
node->left=old->left;
if(old->parent)
{
if(old->parent->left==old)
old->parent->left=node;
else
old->parent->right=node;
}
else
root=node;
old->left->parent=node;
if(old->right)
old->right->parent=node;
}
else
{
if(!node->left)
{//node的左孩子为空
child=node->right;
}
else
child=node->left;
parent=node->parent;
color=node->color;
if(child)
child->parent=parent;
if(parent)
{
if(parent->left==node)
parent->left=child;
else
parent->right=child;
}
else
root=child;
}
free(old);
if(color==BLACK)
{//删除黑色节点需要调整树形结构
root=rb_earse_rebalance(child,parent,root);
}
return root;
}
//红黑树删除的种情况
//修复之
static rb_node_t* rb_earse_rebalance(rb_node_t* node,rb_node_t* parent,rb_node_t* root)
{
rb_node_t *other,*o_left,*o_right;
while((!node||node->color==BLACK)&&node!=root)
{//node为空或者node的节点为黑色
if(parent->left==node)
{
other=parent->right;//node的兄弟节点
if(other->color==RED)//情况:node的兄弟节点为红色
{
other->color=BLACK;
parent->color=RED;
root=rb_rotate_left(parent,root);
other=parent->right;//转化为情况,3,4
}
if((!other->left||other->left->color==BLACK)&&(!other->right||other->right->color==BLACK))
{//情况node的兄弟是黑色的兄弟的两个儿子也是黑色的
other->color=RED;
node=parent;
parent=node->parent;
}
else
{
if(!other->right||other->right->color==BLACK)
{//情况兄弟是黑色的,右孩子为黑色的
if((o_left=other->left))
o_left->color=BLACK;
other->color=RED;
root=rb_rotate_right(other,root);
other=parent->right;//转变为情况四
}
//情况:x的兄弟w是黑色的,但是兄弟的右孩子是红色的
other->color=parent->color;
parent->color=BLACK;
if(other->right)//
{
other->right->color=BLACK;
}
root=rb_rotate_left(parent,root);
node=root;
break;
}
}
else
{
other = parent->left;
if (other->color == RED)
{
other->color = BLACK;
parent->color = RED;
root = rb_rotate_right(parent, root);
other = parent->left;
}
if ((!other->left || other->left->color == BLACK) &&
(!other->right || other->right->color == BLACK))
{
other->color = RED;
node = parent;
parent = node->parent;
}
else
{
if (!other->left || other->left->color == BLACK)
{
if ((o_right = other->right))
{
o_right->color = BLACK;
}
other->color = RED;
root = rb_rotate_left(other, root);
other = parent->left;
}
other->color = parent->color;
parent->color = BLACK;
if (other->left)
{
other->left->color = BLACK;
}
root = rb_rotate_right(parent, root);
node = root;
break;
}
}
}
if(node)
node->color=BLACK;//根节点必须为黑色的
return root;
}
int main()
{
int i,count=100;
key_t key;
rb_node_t* root=NULL,*node=NULL;
srand(NULL);
for(i=1;i<count;i++)
{
key=rand()%count;
if((root=rb_insert(key,i,root)))
printf("[i=%d] insert key %d success\n",i,key);
else
{
printf("[i=%d] insert key %d error!\n",i,key);
}
if((node=rb_search(key,root)))
printf("[i=%d] search key %d success!\n",i,key);
if(!(i%10))
{
if((root=rb_erase(key,root)))
printf("[i=%d] erase key %d success\n",i,key);
else
printf("error");
}
}
return 0;
}