《算法导论》第十三章----红黑树

《算法导论》学习记录目录

红黑树是"平衡的"二叉查找树(PS: 关于二叉查找树的内容见链接)。普通的二叉查找树,在最坏情况下基本操作的运行时间为Θ(n),大部分的操作的最坏情况运行时间与树的高度成正比,对于相同的数据如何构造出一棵高效的二叉查找树(即高度尽量小)(如下图)

图a为高效的二叉查找树,图b为低效的二叉查找树

 

造成图b中的二叉查找树低效的原因在于建树的时候结点插入的顺序不恰当,选取关键字为2的结点(最小关键字结点)作为根结点使得所有的结点都位于根结点的右子树里。

更糟糕是所有的结点都在同一条路上,这时候就相当于在链表上进行操作。

但是普通的二叉查找树不会自动调整,使自己的尽量平衡(根结点的左右子树的高度接近相同),它只会根据插入结点的关键字来判断插入的位置。为了使其可以接近平衡,我们可以在结点里添加一些属性,然后根据这些属性来动态调整树的形状。(例如红黑树添加了颜色属性,AVL树添加了结点高度属性。)

红黑树的基本性质:

颜色属性:颜色为红色(RED)或者黑色(BLACK)。

NIL结点:指向二叉查找数的外结点(叶子)指针,颜色为黑色;某些结点的父结点或者子结点指向NIL结点,相当于哨兵。(即为书中的nil[ T ])

红黑性质:1、每个结点的颜色为红色或者黑色

     2、根结点的颜色为黑色

     3、每个叶结点都是黑色

        4、如果一个结点是红色的,那么它的两个儿子都是黑色的

         5、对于每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点

黑高度:从该结点x出发(不包括该结点)到达叶结点的任意一条路径上,黑色结点的个数为该结点的黑色高度,用bh(x)

具体如下图所示(深色为黑色结点,浅色为红色结点):

下为红黑树结点结构体、红黑树结构体和NIL指针等基本实现

 1 #define RED 1
 2 #define BLACK 0
 3 
 4 typedef struct RB_TreeNode {
 5     int value;
 6     int color;
 7     struct RB_TreeNode * parent;
 8     struct RB_TreeNode * left;
 9     struct RB_TreeNode * right;
10 }RB_TreeNode;                       //红黑树结点结构体
11 
12 typedef struct RB_Tree {
13     RB_TreeNode * root;
14 }RB_Tree;                           //红黑树结构体,根结点
15 
16 RB_TreeNode  NILL = { -1, BLACK, NULL, NULL, NULL };
17 RB_TreeNode *NIL = &NILL;                               //NIL结点指针
View Code

一棵n个内结点的红黑树的高度最多为2lg(n+1),这是红黑树是一种好的查找树的原因。(PS:证明见书本,本人太菜,看完不会用自己的话总结。。。所以就不证明)

因此查找、插入、找最小值、找出最大值、找出前趋、找出后继、删除动态集合操作在红黑树上可以在O(lgn)时间内完成。

结点的旋转

因为直接会之前二叉查找树的插入、删除的实现不能保证操作后的二叉树还是红黑树,所以我们添加旋转操作,同过旋转操作来使红黑树在插入、删除操作后还能保持本身的性质。

旋转分为左旋转、右旋转(如下图所示)

 

通过旋转,我们可以修改结点的指针域使结点满足自己的需求。

下为左旋转、右旋转的实现

 1 /*
 2  * x结点上进行左旋转,y结点(x结点的右儿子)的左儿子成为x结点的新右儿子
 3  * x结点成为y结点的左儿子的新父结点
 4  * x结点的父结点成为y结点的新父结点,y结点成为x结点的新父结点
 5  * x结点成为y结点的新左儿子
 6  */
 7 void Left_Rotate(RB_Tree *T, RB_TreeNode *x){
 8     RB_TreeNode *y = x->right;       //x点右儿子          
 9     x->right = y->left;              //y结点的左儿子会成为x结点的右儿子
10     if(y->left != NIL)
11         y->left->parent = x;         //如果y有左儿子,y的左儿子的父结点为x
12     y->parent = x->parent;
13     if(x->parent == NIL)
14         T->root = y;                //如果x的父结点为哨兵,说明x为根结点,则y成为根结点
15     else if(x == x->parent->left)
16         x->parent->left = y;        
17     else
18         x->parent->right = y;       //判断x为其父结点的左、右儿子,y成为x父结点对应的儿子
19     y->left = x;                    //y的左儿子为x
20     x->parent = y;                  //x的父结点为y
21 }
22 
23 /*
24  * x结点上进行右旋转,y结点(x结点的左儿子)的右儿子成为x结点的新左儿子
25  * x结点成为y结点的右儿子的新父结点
26  * x结点的父结点成为y结点的新父结点,y结点成为x结点的新父结点
27  * x结点成为y结点的新右儿子
28  * PS:代码的解释可参照左旋转
29  */
30 void Right_Rotate(RB_Tree *T, RB_TreeNode *x){
31     RB_TreeNode *y = x->left;
32     x->left = y->right;
33     if(y->right != NIL)
34         y->right->parent = x;
35     y->parent = x->parent;
36     if(x->parent == NIL)
37         T->root = y;
38     else if(x == x->parent->left)
39         x->parent->left = y;
40     else
41         x->parent->right = y;
42     y->right = x;
43     x->parent = y;
44 }
View Code

选择效果例子如下图:

有了旋转操作,我们就可以进行插入和删除操作。红黑树的插入和删除,是基于普通二叉查找树的插入和删除,再添加维持红黑性质的操作(PS:二叉查找树的插入、删除操作见之前的博客)。

插入

当新的结点插入到红黑树时,我们将该结点的颜色设置为红色,这样红黑树的性质1(没有结点存在其他颜色)、3(新结点的左右儿子为NIL,黑色结点)、5(添加红色结点不影响黑色结点的数目)没改变,但是有性质2(新结点有可能为根结点)和性质4(新结点的父结点有可能也是红色的)。PS:该段中括号为对应的解释。。。。

插入新结点后,如果它不是根结点而且它的父结点不是红色的,那么就无需做有关调整。但是如果不符合红黑性质的时候就需要做有关调整,如果其为根结点,直接将其颜色设置为黑色即可。除此之外,还存在3种情况不符合红黑性质(PS:当前的情况可能经过一次调整后成为其他情况。具体来讲应该有6种情况,不过有3种和另外3种对称,下文是考虑z结点的父结点为左儿子):

情况1:结点z的叔叔是红色。这样我们直接将z父亲的父亲颜色变为红色,z的父亲和叔叔的颜色变为黑色(这样性质5没有改变),最后将z父亲的父亲作为新的z结点,继续上移,直到z结点的父结点为黑色或者z为根结点(当z为根结点,直接将其颜色改为黑色,这样整个红黑树就比原来多了一个黑色结点。但是改变颜色前已经经过各种调整,只违反性质2,改变颜色后,就没有违反任何红黑性质)。如下图所示:

情况2:结点z的叔叔是黑色的、而且z是右儿子(情况2可以通过旋转成为情况3)

情况3:结点z的叔叔是黑色的、而且z是左儿子(PS:如果z结点的父结点为右儿子的时候情况2要改为“z是左儿子”,情况3要改为“z是右儿子”)因为z的叔叔是黑色,所以不可以直接通过改变颜色来维持红黑性质,要通过旋转操作来维持。如下图所示,如果为情况2就通过对A进行左旋转变为情况3,再改变结点的颜色,最后将C进行右旋转。这样就使得解决违反性质4,而且不违反性质5.(PS:如果z结点的父结点为右儿子的时候,应将左旋转改为右旋转,右旋转改为左旋转。具体画图理一理就明白

下为插入和插入调整实现(PS:插入的注释见二叉查找树的插入)

 1 /*
 2  * 插入函数,注意插入结点与其在树中对应的父结点的链接(需要记录父结点)。
 3  * 从根结点出发,不停用当前结点与插入的值比较,如果当前结点的值比较大就往当前结点的左儿子走,相反就往右儿子走,直到当前结点为空,
 4  * 在过程中记录当前结点的父结点。
 5  * 运行时间为O(h),h为树的高度。因为整个过程是一条沿着根结点下降的路径。
 6  */
 7 void RB_Insert(RB_Tree *T, int key){
 8     RB_TreeNode *z;
 9     z = (RB_TreeNode *)malloc(sizeof(RB_TreeNode));         //新建结点
10     z->value = key;
11     z->color = RED;
12     z->parent = z->left = z->right = NIL;
13     RB_TreeNode *x = T->root;
14     RB_TreeNode *y = NIL;
15     while(x != NIL){
16         y = x;
17         if(x->value < key)
18             x = x->right;
19         else
20             x = x->left;
21     }
22     z->parent = y;
23     if(y == NIL){
24         T->root = z;
25         T->root->parent = NIL;
26         T->root->parent->color = BLACK;
27     }
28     else if(z->value < y->value)
29         y->left = z;
30     else
31         y->right = z;
32     RB_Insert_Fixup(T, z);                                 //插入调整,维持红黑性质
33 }
34 
35 /*
36  * 插入调整,维持红黑性质
37  */
38 void RB_Insert_Fixup(RB_Tree *T, RB_TreeNode *z){
39     while(z->parent->color == RED){                         //如果z结点的父结点为黑色,就不用进入3种情况的处理
40         if(z->parent == z->parent->parent ->left){          //z的父结点为左儿子的情况
41             RB_TreeNode *y = z->parent->parent->right;
42             if(y->color == RED){                            //情况1
43                 z->parent->color = BLACK;
44                 y->color = BLACK;
45                 z->parent->parent->color = RED;
46                 z = z->parent->parent;
47             }                                           
48             else {
49                 if(z == z->parent->right){                  //情况2
50                     z = z->parent;
51                     Left_Rotate(T, z);                      //左旋转,情况2变为3
52                 }
53                 z->parent->color = BLACK;                   //情况3
54                 z->parent->parent->color = RED;
55                 Right_Rotate(T, z->parent->parent);         //右选择解决违反性质4
56             }
57         }
58         else{
59             RB_TreeNode *y = z->parent->parent->left;       //z的结点为右儿子的情况
60             if(y->color == RED){                            //情况1
61                 z->parent->color = BLACK;
62                 y->color = BLACK;
63                 z->parent->parent->color = RED;
64                 z = z->parent->parent;
65             }
66             else{
67                 if(z == z->parent->left){                   //情况2
68                     z = z->parent;
69                     Right_Rotate(T, z);                     //右旋转,情况2变为情况3
70                 }
71                 z->parent->color = BLACK;                   //情况3
72                 z->parent->parent->color = RED;
73                 Left_Rotate(T, z->parent->parent);          //左旋转解决违反性质4
74             }
75         }
76     }
77     T->root->color = BLACK;                                 //如果红黑树T的根结点为红色就会变成黑色,如果是黑色变成黑色也没影响
78 }
View Code

红黑树的插入操作总共花费时间为O(lgn)。因为插入部分花费O(lgn),而插入调整只有情况1执行的时候才可能要重复进行while循环,因此while循环可能的运行次数为O(lgn)。所以总共花费为O(lgn)。

删除(PS:下文的z为想删除的结点、y结点为实际要删除的结点、x结点为y的唯一孩子结点。如果觉得想删除结点、实际删除结点、实际删除结点的唯一孩子感到困惑,请看二叉查找树,里面有解释,虽然里面的命名又点不一样。。。)

对于删除结点,如果删除的是红色的结点,对红黑性质没有任何影响。但是如果删除的是黑色结点,就会产生3个问题:1、如果y是根结点,而y的一个红色孩子成为了根结点,违反了性质2;2、如果x和y的父结点都是红色,违反性质4;3、删除y导致包含y的任何路径黑结点个数少1,违反了性质5,解决这个问题的办法是x添加多一层黑色(双重黑色或红黑),这样就由违反性质5变为违反性质1。(PS:如果要恢复性质5会很麻烦。。。。这个我是看网友博客了。。还没探究这个问题)

对于删除调整如何恢复性质2、4:删除调整实现里对于x为根结点或者x的颜色为红色时直接将x结点的颜色变成黑色。如果x为根结点,直接改变为黑色即可,如果x不为根结点,将x变成黑色,可以解决违反性质4,而且之前包含y的任何路径的黑色结点个数也恢复。(这个是我自己看完伪代码想的,书中要求读者说明删除调整代码如何恢复2、4,所以可能有错,欢迎指出错误)。

删除调整主要将额外的黑色沿树上移,直到:1、x指向一个红黑结点,直接将x的颜色变为黑色

                    2、x指向根,直接消除额外的黑色

                    3、或者做必要的旋转和颜色修改

总共8情况(4种与另外4种对称,下文是考虑x为左儿子的情况)(下文的x结点为需要调整的结点,即增加了额外一层黑色)

情况1:x的兄弟w是红色。先改变w和x的父结点的颜色,对x的父结点进行一次做旋转,红黑性质继续维持,但是我们通过这些操作使得情况1转换成情况2、3、4

情况2:x的兄弟w是黑色,而且w的两个孩子都是黑色。x和w的去掉一重黑色,那么x只有一重黑色,而w变为红色(因为w的两个儿子都是黑色所以变成红色没有违反性质4)。然后我们再在x的父结点上添加一层额外的黑色,最后x的父结点成为新的x结点继续我和循环。

情况3:x的兄弟w是黑色的,w的左孩子是红色,右孩子是黑色的。首先交换w和其左孩子的颜色,对w进行右旋转。这样就从情况3转换成情况4.

情况4:x的兄弟w是黑色的,而且w的右孩子是红色的。首先交换w和x的父结点的颜色,对x的父结点进行左旋转,去掉x的额外黑色,又不破坏红黑性质。最后将x置为根结点,接受循环。

(PS:x为右儿子的情况时,需要将上文的左旋转换成右旋转,右旋转换成左旋转)

具体如下图所示

下为删除和删除调整实现:

 1 /*
 2  * 删除结点函数,首先要确定真正删除的结点是那个。
 3  * 如果z没有子结点,直接将z的父结点对应的指针指向NULL
 4  * 如果z只有一个子节点,直接将z的父结点对应的指针指向z的子结点
 5  * 如果z有两个子结点,实际上要删除的不是z,而是z的后继,,再用z的后继的内容代替z的内容
 6  */
 7 
 8 void RB_Delete(RB_Tree *T, RB_TreeNode *z){
 9     RB_TreeNode *x = NULL;
10     RB_TreeNode *y = NULL;
11 
12     if(z->left == NIL || z->right == NIL)
13         y = z;
14     else
15         y = RB_Tree_Successor(z);
16     if(y->left != NIL)
17         x = y->left;
18     else
19         x = y->right;
20     x->parent = y->parent;
21     if(y->parent == NIL)
22         T->root = x;
23     else if(y == y->parent->left)
24         y->parent->left = x;
25     else
26         y->parent->right = x;
27     if(y != z)
28         z->value = y->value;
29     if(y->color == BLACK)
30         RB_Delete_Fixup(T, x);          //当实际要删除的结点y为黑色时才需要进行调整
31 }
32 
33 /*
34  * 删除调整,使红黑树维持红黑性质
35  */
36 void RB_Delete_Fixup(RB_Tree *T, RB_TreeNode *x){
37     while(x != T->root && x->color == BLACK){               //当x结点为根结点或者x的颜色为红色(即为红黑, 实际上额外黑色没有直接加上去,只是默认x节点有一重额外的黑色)
38         if(x == x->parent->left){                           //x为左儿子情况
39             RB_TreeNode *w = x->parent->right;
40             if(w->color == RED){                            //情况1
41                 w->color = BLACK;
42                 x->parent->color = RED;
43                 Left_Rotate(T, x->parent);                  //左旋转,使得情况1转换成情况2、3或4
44                 w = x->parent->right;                       
45             }
46             
47             if(w->left->color == BLACK && w->right->color == BLACK){      //情况2
48                  w->color = RED;                            //修改颜色
49                  x = x->parent;                             //上移
50             }
51             else{
52                 if(w->right->color == BLACK){               //情况3
53                     w->left->color = BLACK;
54                     w->color = RED;
55                     Right_Rotate(T, w);                     //右旋转,情况3转换成情况4
56                     w = x->parent->right;
57                 }
58                 w->color = x->parent->color;
59                 x->parent->color = BLACK;
60                 w->right->color = BLACK;
61                 Left_Rotate(T, x->parent);                  //左旋转,去掉x的额外黑色
62                 x = T->root;                                //使循环结束
63             }
64             
65         }
66         else{                                               //x为右儿子情况(PS:下文的注释参考上文)
67             RB_TreeNode *w = x->parent->left;
68             if(w->color == RED){
69                 w->color = BLACK;
70                 x->parent->color = RED;
71                 Right_Rotate(T, x->parent);
72                 w = x->parent->left;
73             }
74             
75             if(w->left->color == BLACK && w->right->color == BLACK){
76                 w->color = RED;
77                 x = x->parent;
78             }
79             else {
80                 if(w->left->color == BLACK){
81                     w->right->color = BLACK;
82                     w->color = RED;
83                     Left_Rotate(T, w);
84                     w = x->parent->left;
85                 }
86                 w->color = x->parent->color;
87                 x->parent->color = BLACK;
88                 w->left->color = BLACK;
89                 Right_Rotate(T, x->parent);
90                 x = T->root;
91             }
92         }
93     }
94 }
View Code

删除操作的总运行时间为O(lgn)。

 

下为全部代码(除了删除、插入实现的注释见二叉查找树

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 #define RED 1
  5 #define BLACK 0
  6 
  7 typedef struct RB_TreeNode {
  8     int value;
  9     int color;
 10     struct RB_TreeNode * parent;
 11     struct RB_TreeNode * left;
 12     struct RB_TreeNode * right;
 13 }RB_TreeNode;                       //红黑树结点结构体
 14 
 15 typedef struct RB_Tree {
 16     RB_TreeNode * root;
 17 }RB_Tree;                           //红黑树结构体,根结点
 18 
 19 RB_TreeNode  NILL = { -1, BLACK, NULL, NULL, NULL };
 20 RB_TreeNode *NIL = &NILL;                               //NIL结点指针
 21 
 22 void Left_Rotate(RB_Tree *T, RB_TreeNode *x);
 23 
 24 void Right_Rotate(RB_Tree *T, RB_TreeNode *x);
 25 
 26 void RB_Insert(RB_Tree *T, int key);
 27 
 28 void RB_Insert_Fixup(RB_Tree *T, RB_TreeNode *z);
 29 
 30 void RB_Delete(RB_Tree *T, RB_TreeNode *z);
 31 
 32 void RB_Delete_Fixup(RB_Tree *T, RB_TreeNode *x);
 33 
 34 RB_TreeNode * RB_Search(RB_TreeNode *x, int key);
 35 
 36 RB_TreeNode * RB_Tree_Minimum(RB_TreeNode *x);
 37 
 38 RB_TreeNode * RB_Tree_Maximum(RB_TreeNode *x);
 39 
 40 RB_TreeNode * RB_Tree_Successor(RB_TreeNode *x);
 41 
 42 RB_TreeNode * RB_Tree_Predecesor(RB_TreeNode *x);
 43 
 44 void Inorder_RB_Tree_Walk(RB_TreeNode *x);
 45 
 46 void free_men(RB_TreeNode *x);
 47 
 48 int main(){
 49     RB_Tree *T;
 50     T->root = NIL;
 51 
 52     int n, value, i;
 53     scanf("%d", &n);
 54     for(i = 1; i<= n; i++){
 55         scanf("%d", &value);
 56         RB_Insert(T, value);
 57         Inorder_RB_Tree_Walk(T->root);    
 58         printf("\n");
 59     }
 60     RB_TreeNode *s = RB_Search(T->root, 3);
 61     if(s != NIL)
 62         printf("%d is exists!\n", s->value);
 63     /*Inorder_RB_Tree_Walk(T->root);
 64 
 65     printf("\n");*/
 66     printf("%d\n", RB_Tree_Minimum(T->root)->value);
 67     printf("%d\n", RB_Tree_Maximum(T->root)->value);
 68     printf("%d\n", RB_Tree_Successor(s)->value);
 69     printf("%d\n", RB_Tree_Predecesor(s)->value);
 70     RB_Delete(T, s);
 71     Inorder_RB_Tree_Walk(T->root);
 72     printf("\n");
 73     return 0;
 74 }
 75 
 76 /*
 77  * x结点上进行左旋转,y结点(x结点的右儿子)的左儿子成为x结点的新右儿子
 78  * x结点成为y结点的左儿子的新父结点
 79  * x结点的父结点成为y结点的新父结点,y结点成为x结点的新父结点
 80  * x结点成为y结点的新左儿子
 81  */
 82 void Left_Rotate(RB_Tree *T, RB_TreeNode *x){
 83     RB_TreeNode *y = x->right;       //x点右儿子          
 84     x->right = y->left;              //y结点的左儿子会成为x结点的右儿子
 85     if(y->left != NIL)
 86         y->left->parent = x;         //如果y有左儿子,y的左儿子的父结点为x
 87     y->parent = x->parent;
 88     if(x->parent == NIL)
 89         T->root = y;                //如果x的父结点为哨兵,说明x为根结点,则y成为根结点
 90     else if(x == x->parent->left)
 91         x->parent->left = y;        
 92     else
 93         x->parent->right = y;       //判断x为其父结点的左、右儿子,y成为x父结点对应的儿子
 94     y->left = x;                    //y的左儿子为x
 95     x->parent = y;                  //x的父结点为y
 96 }
 97 
 98 /*
 99  * x结点上进行右旋转,y结点(x结点的左儿子)的右儿子成为x结点的新左儿子
100  * x结点成为y结点的右儿子的新父结点
101  * x结点的父结点成为y结点的新父结点,y结点成为x结点的新父结点
102  * x结点成为y结点的新右儿子
103  * PS:代码的解释可参照左旋转
104  */
105 void Right_Rotate(RB_Tree *T, RB_TreeNode *x){
106     RB_TreeNode *y = x->left;
107     x->left = y->right;
108     if(y->right != NIL)
109         y->right->parent = x;
110     y->parent = x->parent;
111     if(x->parent == NIL)
112         T->root = y;
113     else if(x == x->parent->left)
114         x->parent->left = y;
115     else
116         x->parent->right = y;
117     y->right = x;
118     x->parent = y;
119 }
120 
121 /*
122  * 插入函数,注意插入结点与其在树中对应的父结点的链接(需要记录父结点)。
123  * 从根结点出发,不停用当前结点与插入的值比较,如果当前结点的值比较大就往当前结点的左儿子走,相反就往右儿子走,直到当前结点为空,
124  * 在过程中记录当前结点的父结点。
125  * 运行时间为O(h),h为树的高度。因为整个过程是一条沿着根结点下降的路径。
126  */
127 void RB_Insert(RB_Tree *T, int key){
128     RB_TreeNode *z;
129     z = (RB_TreeNode *)malloc(sizeof(RB_TreeNode));         //新建结点
130     z->value = key;
131     z->color = RED;
132     z->parent = z->left = z->right = NIL;
133     RB_TreeNode *x = T->root;
134     RB_TreeNode *y = NIL;
135     while(x != NIL){
136         y = x;
137         if(x->value < key)
138             x = x->right;
139         else
140             x = x->left;
141     }
142     z->parent = y;
143     if(y == NIL){
144         T->root = z;
145         T->root->parent = NIL;
146         T->root->parent->color = BLACK;
147     }
148     else if(z->value < y->value)
149         y->left = z;
150     else
151         y->right = z;
152     RB_Insert_Fixup(T, z);                                 //插入调整,维持红黑性质
153 }
154 
155 /*
156  * 插入调整,维持红黑性质
157  */
158 void RB_Insert_Fixup(RB_Tree *T, RB_TreeNode *z){
159     while(z->parent->color == RED){                         //如果z结点的父结点为黑色,就不用进入3种情况的处理
160         if(z->parent == z->parent->parent ->left){          //z的父结点为左儿子的情况
161             RB_TreeNode *y = z->parent->parent->right;
162             if(y->color == RED){                            //情况1
163                 z->parent->color = BLACK;
164                 y->color = BLACK;
165                 z->parent->parent->color = RED;
166                 z = z->parent->parent;
167             }                                           
168             else {
169                 if(z == z->parent->right){                  //情况2
170                     z = z->parent;
171                     Left_Rotate(T, z);                      //左旋转,情况2变为3
172                 }
173                 z->parent->color = BLACK;                   //情况3
174                 z->parent->parent->color = RED;
175                 Right_Rotate(T, z->parent->parent);         //右选择解决违反性质4
176             }
177         }
178         else{
179             RB_TreeNode *y = z->parent->parent->left;       //z的结点为右儿子的情况
180             if(y->color == RED){                            //情况1
181                 z->parent->color = BLACK;
182                 y->color = BLACK;
183                 z->parent->parent->color = RED;
184                 z = z->parent->parent;
185             }
186             else{
187                 if(z == z->parent->left){                   //情况2
188                     z = z->parent;
189                     Right_Rotate(T, z);                     //右旋转,情况2变为情况3
190                 }
191                 z->parent->color = BLACK;                   //情况3
192                 z->parent->parent->color = RED;
193                 Left_Rotate(T, z->parent->parent);          //左旋转解决违反性质4
194             }
195         }
196     }
197     T->root->color = BLACK;                                 //如果红黑树T的根结点为红色就会变成黑色,如果是黑色变成黑色也没影响
198 }
199 
200 /*
201  * 删除结点函数,首先要确定真正删除的结点是那个。
202  * 如果z没有子结点,直接将z的父结点对应的指针指向NULL
203  * 如果z只有一个子节点,直接将z的父结点对应的指针指向z的子结点
204  * 如果z有两个子结点,实际上要删除的不是z,而是z的后继,,再用z的后继的内容代替z的内容
205  */
206 
207 void RB_Delete(RB_Tree *T, RB_TreeNode *z){
208     RB_TreeNode *x = NULL;
209     RB_TreeNode *y = NULL;
210 
211     if(z->left == NIL || z->right == NIL)
212         y = z;
213     else
214         y = RB_Tree_Successor(z);
215     if(y->left != NIL)
216         x = y->left;
217     else
218         x = y->right;
219     x->parent = y->parent;
220     if(y->parent == NIL)
221         T->root = x;
222     else if(y == y->parent->left)
223         y->parent->left = x;
224     else
225         y->parent->right = x;
226     if(y != z)
227         z->value = y->value;
228     if(y->color == BLACK)
229         RB_Delete_Fixup(T, x);          //当实际要删除的结点y为黑色时才需要进行调整
230 }
231 
232 /*
233  * 删除调整,使红黑树维持红黑性质
234  */
235 void RB_Delete_Fixup(RB_Tree *T, RB_TreeNode *x){
236     while(x != T->root && x->color == BLACK){               //当x结点为根结点或者x的颜色为红色(即为红黑, 实际上额外黑色没有直接加上去,只是默认x节点有一重额外的黑色)
237         if(x == x->parent->left){                           //x为左儿子情况
238             RB_TreeNode *w = x->parent->right;
239             if(w->color == RED){                            //情况1
240                 w->color = BLACK;
241                 x->parent->color = RED;
242                 Left_Rotate(T, x->parent);                  //左旋转,使得情况1转换成情况2、3或4
243                 w = x->parent->right;                       
244             }
245             
246             if(w->left->color == BLACK && w->right->color == BLACK){      //情况2
247                  w->color = RED;                            //修改颜色
248                  x = x->parent;                             //上移
249             }
250             else{
251                 if(w->right->color == BLACK){               //情况3
252                     w->left->color = BLACK;
253                     w->color = RED;
254                     Right_Rotate(T, w);                     //右旋转,情况3转换成情况4
255                     w = x->parent->right;
256                 }
257                 w->color = x->parent->color;
258                 x->parent->color = BLACK;
259                 w->right->color = BLACK;
260                 Left_Rotate(T, x->parent);                  //左旋转,去掉x的额外黑色
261                 x = T->root;                                //使循环结束
262             }
263             
264         }
265         else{                                               //x为右儿子情况(PS:下文的注释参考上文)
266             RB_TreeNode *w = x->parent->left;
267             if(w->color == RED){
268                 w->color = BLACK;
269                 x->parent->color = RED;
270                 Right_Rotate(T, x->parent);
271                 w = x->parent->left;
272             }
273             
274             if(w->left->color == BLACK && w->right->color == BLACK){
275                 w->color = RED;
276                 x = x->parent;
277             }
278             else {
279                 if(w->left->color == BLACK){
280                     w->right->color = BLACK;
281                     w->color = RED;
282                     Left_Rotate(T, w);
283                     w = x->parent->left;
284                 }
285                 w->color = x->parent->color;
286                 x->parent->color = BLACK;
287                 w->left->color = BLACK;
288                 Right_Rotate(T, x->parent);
289                 x = T->root;
290             }
291         }
292     }
293 }
294 
295 
296 RB_TreeNode * RB_Search(RB_TreeNode *x, int key){
297     if(x->value == key || x == NIL)
298         return x;
299     if(x->value > key)
300         RB_Search(x->left, key);
301     else
302         RB_Search(x->right, key);
303 }
304 
305 RB_TreeNode * RB_Tree_Minimum(RB_TreeNode *x){
306     RB_TreeNode *r = x;
307     while(r->left != NIL)
308         r = r->left;
309     return r;
310 }
311 
312 RB_TreeNode * RB_Tree_Maximum(RB_TreeNode *x){
313     RB_TreeNode *r = x;
314     while(r->left != NIL)
315         r = r->left;
316     return r;
317 }
318 
319 RB_TreeNode * RB_Tree_Successor(RB_TreeNode *x){
320     RB_TreeNode *r = x;
321     if(r->right != NIL)
322         return RB_Tree_Minimum(r->right);
323     RB_TreeNode *y = r->parent;
324     while(y != NIL && r == y->right){
325         r = y;
326         y = y->parent;
327     }
328     return y;
329 }
330 RB_TreeNode * RB_Tree_Predecesor(RB_TreeNode *x){
331     RB_TreeNode *r = x;
332     if(r->left != NIL)
333         return RB_Tree_Maximum(r->left);
334     RB_TreeNode *y = r->parent;
335     while(y != NIL && r == y->left){
336         r = y;
337         y = y->parent;
338     }
339     return y;
340 }
341 
342 void Inorder_RB_Tree_Walk(RB_TreeNode *x){
343     if(x != NIL){
344         Inorder_RB_Tree_Walk(x->left);
345         printf("%d : ", x->value);
346         if(x->color == 1)
347             printf("red ");
348         else
349             printf("black ");
350         Inorder_RB_Tree_Walk(x->right);
351     }
352 }
353 
354 void free_men(RB_TreeNode *x){
355     if(x != NIL){
356         free_men(x->left);
357         free_men(x->right);
358         free(x);
359     }
360 }
View Code

 

PS:吐槽来了。。。以后要多更新博客,打算把当天学到有感觉的东西记录下来。。。算导可能更新会有点慢(已经两个星期才一篇。。。太弱菜了,越到最后要好好磨)。。。打算写SICP学习记录和Linux学校记录。。。。。好好努力吧!!!博客能更新真开心。。。。。

 

 

posted @ 2013-11-23 00:54  alan_forever  阅读(2618)  评论(0编辑  收藏  举报