学习方法:我主要是参考算法导论以及Nginx中rbtree.h和rbtree.c两部分内容来学习红黑树的。网上有很多关于红黑树的介绍,不可否认,有很多文章讲的很详细,但是我想经典毕竟是经典,去阅读算法导论,将会使你更加明白红黑树的原理。一句话,读算法导论,学红黑树。 0.序 一.二叉查找树 1.性质 2.叶子结点的表示方法: 3.程序中所使用的数据结构: 4.操作之查找 5.操作之某个结点的孩子中最小的孩子结点 6.创建结点 7.遍历二叉树(中序遍历) 8.操作之插入结点 9.操作之删除结点 10.测试程序: 二、红黑树 <一>.红黑树插入的步骤 <二>红黑树插入的修正。 <三>红黑树删除的修正 <四>红黑树删除的实际操作 <五>红黑树删除的总结 <六>红黑树删除的完整代码 |
1)每个结点要么是红的,要么是黑的。 2)根结点是黑的。 3)每个叶结点,即空结点(NIL)是黑的。 4)如果一个结点是红的,那么它的俩个儿子都是黑的。 5)对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点。 |
typedef
struct
rbtree_node_s
rbtree_node_t
;
typedef
struct
rbtree_s
rbtree_t
;
typedef
void
(*
insert_node_to_tree_pt
)(
rbtree_node_t
* temp,
rbtree_node_t
* sentinel,
rbtree_node_t
* node);
struct
rbtree_node_s {
rbtree_node_t
*
left
;
rbtree_node_t
*
right
;
rbtree_node_t
*
parent
;
int
key
;
int
color
;
/*color = 1,red;color = 0,black*/
};
struct
rbtree_s{
rbtree_node_t
*
root
;
rbtree_node_t
*
sentinel
;
insert_node_to_tree_pt
insert
;
};
|
rbtree_node_t
* search_node(
rbtree_node_t
*node ,
rbtree_node_t
* sentinel,
int
key)
{
rbtree_node_t
* temp = node;
for
(;;){
if
(temp == sentinel){
break
;
}
if
(temp->
key
< key)
temp = temp->
right
;
else
if
(temp->
key
> key)
temp = temp->
left
;
if
(temp->
key
== key)
break
;
}
return
temp;
}
|
rbtree_node_t
* minimum(
rbtree_node_t
* node,
rbtree_node_t
* sentinel)
{
rbtree_node_t
*temp = node;
for
(;temp->
left
!= sentinel;){
temp = temp->
left
;
}
return
temp;
}
|
rbtree_node_t
* rbtree_create_node(
int
key)
{
rbtree_node_t
* newnode = NULL;
newnode = (
rbtree_node_t
*)
malloc
(
sizeof
(
rbtree_node_t
));
if
(NULL == newnode)
return
NULL;
memset
(newnode,0,
sizeof
(
rbtree_node_t
));
newnode->
key
= key;
return
newnode;
}
|
void
rbtree_traverse(
rbtree_node_t
*node,
rbtree_node_t
* sentinel)
{
if
(node == sentinel)
return
;
rbtree_traverse(node->
left
,sentinel);
printf
(
"key : %d color :%d\n"
,node->
key
,node->
color
);
rbtree_traverse(node->
right
,sentinel);
}
|
if
(rbtree->
root
== rbtree->
sentinel
){
/*empty tree*/
rbtree->
root
= node;
node ->
parent
= rbtree->
sentinel
;
node->
left
= rbtree->
sentinel
;
node->
right
= rbtree->
sentinel
;
return
;
}
|
for
(;;){
/*no-empty tree*/
if
(temp->
key
< node->
key
)
pp = &temp->
right
;
else
if
(temp->
key
> node->
key
)
pp = &temp->
left
;
else
{
printf
(
"existing node\n"
);
return
;
}
if
(*pp == rbtree->
sentinel
)
break
;
temp = * pp;
}
|
/*modify pointer*/
if
(temp->
key
< node->
key
)
temp->
right
= node;
else
temp->
left
= node;
node->
parent
= temp;
node->
left
= rbtree->
sentinel
;
node->
right
= rbtree->
sentinel
;
|
void
insert_node_to_tree(
rbtree_t
*rbtree,
rbtree_node_t
* node)
{
rbtree_node_t
** pp;
rbtree_node_t
* temp = rbtree->
root
;
if
(rbtree->
root
== rbtree->
sentinel
){
/*empty tree*/
rbtree->
root
= node;
node ->
parent
= rbtree->
sentinel
;
node->
left
= rbtree->
sentinel
;
node->
right
= rbtree->
sentinel
;
return
;
}
/*find the location where the node will insert into
* temp is used to store the node which is the last non-leaf node
* the location is the leaf child of temp
* */
for
(;;){
/*no-empty tree*/
if
(temp->
key
< node->
key
)
pp = &temp->
right
;
else
if
(temp->
key
> node->
key
)
pp = &temp->
left
;
else
{
printf
(
"existing node\n"
);
return
;
}
if
(*pp == rbtree->
sentinel
)
break
;
temp = *pp;
}
/*modify pointer*/
if
(temp->
key
< node->
key
)
temp->
right
= node;
else
temp->
left
= node;
node->
parent
= temp;
node->
left
= rbtree->
sentinel
;
node->
right
= rbtree->
sentinel
;
return
;
}
|
case1:删除结点node的两个孩子均为叶子结点sentinel,那么subst就是node,temp为叶子结点,直接删除即可。case2:删除结点node只有一个孩子child,那么subst就是node,temp就是该孩子结点child,更改其指针即可。case3:情况稍微复杂。删除结点node有两个孩子结点lchild 和rchild,我们要寻找rchild这颗子树上最小的结minnode,那么subst就是minnode。 令node的key的取值等于minnode的key的取值,然后删除subst(也就是minnode)即可,情况转化为case1 or case2。
/*find subst and temp*/
if
(node->
left
== sentinel){
subst = node;
temp = subst->
right
;
}
else
if
(node->
right
== sentinel){
subst = node;
temp = subst->
left
;
}
else
{
subst = rbtree_min_node(node->
right
,sentinel);
temp = subst->
right
;
}
|
/*modify the pointer*/
//modify the parent pointer of child
temp->
parent
= subst->
parent
;
//modify the child pointer of parent
if (subst-> parent == rbtree->sentinel ) /*must add the correction of subst is root node */
rbtree-> root = temp;
if
(subst == subst->
parent
->
left
)
subst->
parent
->
left
= temp;
else
subst->
parent
->
right
= temp;
|
/*if it is case 3,change the key of node*/
if
(subst != node){
node->
key
= subst->
key
;
}
free
(subst);
|
void
rbtree_delete(
rbtree_t
*rbtree,
rbtree_node_t
*node)
{
/*
* description : subst :the real deleted node
* temp : the node which will replace subst after subst is deleted;
* */
rbtree_node_t
* temp,*subst;
//step 1: find the location of subst and temp .
if
(node->
left
== rbtree->
sentinel
){
subst = node;
temp = subst->
right
;
}
else
if
(node->
right
== rbtree->
sentinel
){
subst = node;
temp = subst->
left
;
}
else
{
subst = rbtree_min_node(node->
right
,rbtree->
sentinel
);
temp = subst->
right
;
/*it is different from nginx rbtree ,because I think there is no left child for subst,so temp is sentinel or temp is subst->right child*/
}
//step 2:replace node with subst
temp->
parent
= subst->
parent
;
if
(subst->
parent
==rbtree->sentinel
)
/*must add the correction of subst is root node */
rbtree->
root
= temp;
else
if
(subst == subst->
parent
->
right
)
subst->
parent
->
right
= temp;
else
subst->
parent
->
left
= temp;
//step 3: change the value of node with the content of subst
if
(subst != node){
node->
key
= subst->
key
;
}
free
(subst);
}
|
#include
"rbtree.h"
int
main(
void
)
{
rbtree_t
*rbtree;
rbtree_node_t
*node = NULL,*sentinel = NULL;
rbtree_node_t
*del_node = NULL;
int
key_array[] = {12,1,9,2,0,11,7,19,4,15,18,5,14,13,10,16,6,3,8,17};
int
i;
/*begin initial*/
sentinel = (
rbtree_node_t
*)
malloc
(
sizeof
(
rbtree_node_t
));
rbtree = (
rbtree_t
*)
malloc
(
sizeof
(
rbtree_t
));
if
(NULL == sentinel || NULL ==rbtree)
return
-1;
node_black(sentinel);
rbtree->
root
= sentinel;
rbtree->
sentinel
= sentinel;
rbtree->
insert
= insert_value;
/*end initial*/
for
(i = 0; i <
sizeof
(key_array)/
sizeof
(
int
); i++){
node = rbtree_create_node(key_array[i]);
#if
BST
insert_node_to_tree(rbtree,node);
#else
rbtree_insert_node( rbtree, node);
#endif
}
rbtree_traverse(rbtree->
root
,rbtree->
sentinel
);
for
(i = 0; i <
sizeof
(key_array)/
sizeof
(
int
); i++){
del_node = rbtree_search_key( rbtree,key_array[i]);
if
(del_node == rbtree->
sentinel
){
printf
(
"there is no key\n"
);
return
-1;
}
// rbtree_delete(rbtree,del_node);/*binary search tree delete*/
#if
BST
rbtree_delete(rbtree,del_node);
#else
rbtree_fixup_delete(rbtree,del_node);
#endif
printf
(
"after delete node %d\n"
,key_array[i]);
rbtree_traverse(rbtree->
root
,rbtree->
sentinel
);
}
return
0;
}
|
rbtree_node_t
** root = &rbtree->
root
;
|
if
((node == *root) || (node_is_black(node->
parent
)))
node_black(*root);
|
while
((node != *root) && (node_is_red(node->
parent
)))
|
根据叔叔结点颜色,分为case1 , case2+case3根据左右结点,分为case2 ,case3
temp = node->
parent
->
parent
->
right
;
if
(node_is_red(temp)){
/*case 1*/
node_black(node->
parent
);
node_black( temp);
node_red(node->
parent
->
parent
);
node = node->
parent
->
parent
;
}
|
if
(node == node->
parent
->
right
){
/*case 2*/
node = node->
parent
;
rbtree_left_rotate( root,rbtree->
sentinel
, node);
}
|
if
(node == node->
parent
->
right
){
/*case 2*/
node = node->
parent
;
rbtree_left_rotate( root,rbtree->
sentinel
, node);
}
|
while
((node != *root) && (node_is_red(node->
parent
))){
if
(node->
parent
== node->
parent
->
parent
->
left
){
temp = node->
parent
->
parent
->
right
;
if
(node_is_red(temp)){
/*case 1*/
node_black(node->
parent
);
node_black(temp);
node_red(node->
parent
->
parent
);
node = node->
parent
->
parent
;
}
else
{
if
(node == node->
parent
->
right
){
/*case 2*/
node = node->
parent
;
rbtree_left_rotate( root,rbtree->
sentinel
, node);
}
/*case 3*/
node_black(node->
parent
);
node_red(node->
parent
->
parent
);
rbtree_right_rotate(root,rbtree->
sentinel
, node->
parent
->
parent
);
}
}
/*parent of node is the left of parent of parent of node */
else
{
temp = node->
parent
->
parent
->
left
;
if
(node_is_red(temp)){
/*case 1*/
node_black(node->
parent
);
node_black(temp);
node_red(node->
parent
->
parent
);
node = node->
parent
->
parent
;
}
else
{
if
(node == node->
parent
->
left
){
/*case 2*/
node = node->
parent
;
rbtree_right_rotate( root,rbtree->
sentinel
, node);
}
/*case 3*/
node_black(node->
parent
);
node_red(node->
parent
->
parent
);
rbtree_left_rotate(root,rbtree->
sentinel
, node->
parent
->
parent
);
/*left rotate must be temp->parent or node->parent->parent*/
}
}
/*parent of node is the right of parent of parent of node */
}
/*while*/
node_black (*root);
|
red = node_is_red(subst);
if
(1 == red){
printf
(
"delete red node\n"
);
return
;
}
|
while
((temp != rbtree->
root
) && (node_is_black(
temp
)) ) 不进入该while 循环
node_black (temp);
|
if
(temp == temp->
parent
->
left
){
/* temp is left node*/
|
if
(node_is_red(w)){
/*it is essential to change color*/
node_black(w);
node_red(temp->
parent
);
rbtree_left_rotate(&rbtree->
root
,rbtree->
sentinel
,temp->
parent
);
/*rotate temp->parent*/
w = temp->
parent
->
right
;
}
|
if
(node_is_black(w->
right
) && node_is_black(w->
left
)){
/*case 2*/
node_red(w);
temp = temp->
parent
;
}
|
if(node_is_black(w->right)){ node_black(w->left); node_red(temp->parent); rbtree_right_rotate(&rbtree->root,rbtree->sentinel,w); w = temp->parent->right; } |
copy_node_color(w,temp->
parent
);
node_black(temp->
parent
);
node_black(w->
right
);
rbtree_left_rotate(&rbtree->
root
,rbtree->
sentinel
,temp->
parent
);
temp = rbtree->
root
;
|
void
rbtree_fixup_delete(
rbtree_t
*rbtree,
rbtree_node_t
*node)
{
/*
* description : subst :the real deleted node
* temp : the node which will replace subst after subst is deleted;
* */
rbtree_node_t
* temp,*subst;
rbtree_node_t
* w;
int
red = 0;
//step 1: find the location of subst and temp .
if
(node->
left
== rbtree->
sentinel
){
subst = node;
temp = subst->
right
;
}
else
if
(node->
right
== rbtree->
sentinel
){
subst = node;
temp = subst->
left
;
}
else
{
subst = rbtree_min_node(node->
right
,rbtree->
sentinel
);
temp = subst->
right
;
/*it is different from nginx rbtree ,because I think there is no left child for subst,so temp is sentinel or temp is subst->right child*/
}
//step 2:replace node with subst
// if(temp != rbtree->sentinel)/*for rbtree delete*/
temp->
parent
= subst->
parent
;
if
(subst->
parent
== rbtree->
sentinel
)
/*must add the correction of subst is root node */
rbtree->
root
= temp;
else
if
(subst == subst->
parent
->
right
)
subst->
parent
->
right
= temp;
else
subst->
parent
->
left
= temp;
//step 3: change the value of node with the content of subst
if
(subst != node){
node->
key
= subst->
key
;
}
red = node_is_red(subst);
if
(1 == red){
printf
(
"delete red node\n"
);
return
;
}
while
((temp != rbtree->
root
) && (node_is_black(temp)) ){
if
(temp == temp->
parent
->
left
){
/*temp is left node*/
w = temp->
parent
->
right
;
if
(node_is_red(w)){
/*case1: the brother node of( temp) is red;through next steps,we change the case from 1 to 2 or 3 or 4*/
/*it is essential to change color*/
node_black(w);
node_red(temp->
parent
);
rbtree_left_rotate(&rbtree->
root
,rbtree->
sentinel
,temp->
parent
);
/*rotate temp->parent*/
w = temp->
parent
->
right
;
}
if
(node_is_black(w->
right
) && node_is_black(w->
left
)){
/*case 2*/
node_red(w);
temp = temp->
parent
;
}
else
{
if
(node_is_black(w->
right
)){
/*case 3 : the far nephew of temp node is black.through next steps,we change the case from 3 to 4*/
node_black(w->
left
);
node_red(temp->
parent
);
rbtree_right_rotate(&rbtree->
root
,rbtree->
sentinel
,w);
w = temp->
parent
->
right
;
}
/*case 4 :the far nephew of temp node is red*/
copy_node_color(w,temp->
parent
);
node_black(temp->
parent
);
node_black(w->
right
);
rbtree_left_rotate(&rbtree->
root
,rbtree->
sentinel
,temp->
parent
);
/*rotate temp->parent*/
temp = rbtree->
root
;
}
}
else
{
/* temp is right node*/
w = temp->
parent
->
left
;
if
(node_is_red(w)){
/*case1: the brother node of( temp) is red;through next steps,we change the case from 1 to 2 or 3 or 4*/
/*it is essential to change color*/
node_black(w);
node_red(temp->
parent
);
rbtree_right_rotate(&rbtree->
root
,rbtree->
sentinel
,temp->
parent
);
/*rotate temp->parent*/
w = temp->
parent
->
left
;
}
if
(node_is_black(w->
right
) && node_is_black(w->
left
)){
/*case 2*/
node_red(w);
temp = temp->
parent
;
}
else
{
if
(node_is_black(w->
left
)){
/*case 3 : the far nephew of temp node is black.through next steps,we change the case from 3 to 4*/
node_black(w->
right
);
node_red(temp->
parent
);
rbtree_left_rotate(&rbtree->
root
,rbtree->
sentinel
,w);
w = temp->
parent
->
left
;
}
/*case 4 :the far nephew of temp node is red*/
copy_node_color(w,temp->
parent
);
node_black(temp->
parent
);
node_black(w->
left
);
rbtree_right_rotate(&rbtree->
root
,rbtree->
sentinel
,temp->
parent
);
/*rotate temp ->parent*/
temp = rbtree->
root
;
}
}
}
/*while*/
node_black(temp);
}
|