轉自 http://blog.csdn.net/Hackbuteer1?viewmode=contents and http://blog.csdn.net/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;
}