码迷,mamicode.com
首页 > 其他好文 > 详细

数据结构之红黑树

时间:2015-05-15 22:42:39      阅读:265      评论:0      收藏:0      [点我收藏+]

标签:

  红黑树(Red Black Tree) 是一种自平衡二叉查找树

红黑树和AVL树类似,都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,
从而获得较高的查找性能。
它虽然是复杂的,但它的最坏情况运行时间也是非常良好的,并且在实践中是高效的:
它可以在O(log n)时间内做查找,插入和删除,这里的n 是树中元素的数目。(度娘)
C++ stl里面的set,map底层就是用红黑树实现的。
红黑树具体的插入删除原理请参考<<算法导论>> 维基上面也讲得不错。
反正插入过程就是要解决"红-红"冲突,删除就是要解决"黑-黑"冲突。
下面是按照理我解的方式来实现红黑树,我只写了插入和删除过程,

其它的操作和普通的二叉树没多大区别。。
分享一个可以演示红黑树各种操作的网页:

https://www.cs.usfca.edu/~galles/visualization/RedBlack.html

技术分享
  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<string>
  6 #include<cstdio>
  7 #include<vector>
  8 #include<ctime>
  9 const int RED= 1;
 10 const int BLACK = 0;
 11 struct Node {
 12     int data;
 13     bool color;
 14     Node *fa, *left, *right;
 15     Node() :color(BLACK), data(0){ fa = left = right = NULL; }
 16     Node(int _v, Node *p) :data(_v), color(RED){ fa = left = right = p; }
 17 };
 18 struct RedBlackTree{
 19     Node *root, *null;
 20     void init(){
 21         null = new Node();
 22         root = null;
 23     }
 24     /*
 25     * 
 26     *    
 27     * 
 28     *    对红黑树的节点(x)进行右旋转
 29     *    
 30     *          px                            px
 31     *          /                             /
 32     *  ->    x                             y
 33     *       / \                           /  34     *  ->  y   rx     --(右旋)-->        ly   x
 35     *      / \                               /  36     *     ly  ry                            ry  rx
 37     *
 38     *
 39     *
 40     */
 41     //   旋转操作可以不传递引用(reference)话说传引用会快一些。。。
 42     void rotate_right(Node* &x) {
 43         Node *y = x->left;
 44         x->left = y->right;
 45         if (y->right != null) y->right->fa = x;
 46         y->fa = x->fa;
 47         if (x->fa == null) root = y;
 48         else if (x->fa->left == x) x->fa->left = y;
 49         else x->fa->right = y;
 50         y->right = x;
 51         x->fa = y;
 52     }
 53     //   左旋同上
 54     void rotate_left(Node* &x) {
 55         Node *y = x->right;
 56         x->right = y->left;
 57         if (y->left != null) y->left->fa = x;
 58         y->fa = x->fa;
 59         if (x->fa == null) root = y;
 60         else if (x->fa->left == x) x->fa->left = y;
 61         else x->fa->right = y;
 62         y->left = x;
 63         x->fa = y;
 64     }
 65     Node *find(Node *x, int &data) {
 66         while (x != null && x->data != data) {
 67             x = data < x->data ? x->left : x->right;
 68         }
 69         return x;
 70     }
 71     void insert(int v) {
 72         Node *x = root;
 73         Node *y = null;
 74         while (x != null) {        // 先找到带插入节点的位置,y保存该路径上最后一个节点
 75             y = x;
 76             x = v < x->data ? x->left : x->right;
 77         }
 78         x = new Node(v, null);
 79         if (y != null) {           // 确定新节点x与其父节点y的大小关系,再将它们连起来
 80             if (v < y->data) y->left = x;
 81             else y->right = x;
 82         } else {
 83             root = x;
 84         }
 85         x->fa = y;
 86         insert_fix(x);
 87     }
 88     void insert_fix(Node* &x) {
 89         while (x->fa->color != BLACK) {
 90             //    x为当前节点
 91             //    par x的父节点,Gp x的祖父节点, uncle x的叔叔节点
 92             Node *par = x->fa, *Gp = par->fa, *uncle = null;
 93             if (par == Gp->left) {                // 若父节点是祖父的左孩子
 94                 uncle = Gp->right;                // 叔叔为祖父的右孩子
 95                 if (uncle->color == RED) {        // 若叔叔颜色为红色 
 96             //    Case1:父亲和叔叔节点变为红色,祖父颜色变为红色
 97             //    将祖父节点设置为当前节点,再继续(因为Gp由黑变成红色,Gp的父节点可能为红色)
 98             //    所以要继续向上递归调整
 99                     par->color = BLACK;            
100                     Gp->color = RED;
101                     uncle->color = BLACK;
102                     x = Gp;
103                 } else if (x == par->right) {
104             //    Case2:x为右孩子,将父节点设置为当前节点,再进行左旋
105             //    即变成Case3:
106                     rotate_left(x = par);
107                 } else {
108             //    Case3:x,父节点,祖父节点三者共线(左侧)
109             //    将祖父节点改为红色,父节点改为黑色
110             //    此时调整完成,红黑树性质得到恢复
111                     Gp->color = RED;
112                     par->color = BLACK;
113                     rotate_right(Gp);
114                 }
115             } else {
116             //    同上,只是由左变成右而已
117                 uncle = Gp->left;
118                 if (uncle->color == RED) {
119                     par->color = BLACK;
120                     Gp->color = RED;
121                     uncle->color = BLACK;
122                     x = Gp;
123                 } else if (x == par->left) {
124                     rotate_right(x = par);
125                 } else {
126                     Gp->color = RED;
127                     par->color = BLACK;
128                     rotate_left(Gp);
129                 }
130             }
131         }
132         //    将根置为黑色
133         root->color = BLACK;
134     }
135     void del(int data){
136         //    先找到待删除的节点
137         Node *z = find(root, data);
138         //    若没找到直接退出
139         if (z == null) return;
140         Node *y = z, *x = null;
141         //    若z的左右孩子均不为空,则用y保存z的右子树中最小的节点
142         if (z->left != null && z->right != null) {
143             y= z->right;
144             while (y->left != null) y = y->left;
145         }
146         //    此时y只有左子树,或只有右子树,或左右子树均不存在
147         //    x可能为 null !!!
148         x = y->left != null ? y->left : y->right;
149         //    将x与y的父节点连接起来,这里可能会改变null节点的fa指针,但没有关系的。。。
150         x->fa = y->fa;
151         if (y->fa == null) root = x;
152         //    确定y节点与其父亲的左右关系
153         else  if (y->fa->left == y) y->fa->left = x;
154         else y->fa->right = x;
155         //    若z不等于y 拷贝数据,y才是真正要删除的节点
156         if (z != y) z->data = y->data;
157         //    如果删除的节点y的颜色为黑色,对树进行调整使得树满足红黑树的要求
158         if (y->color == BLACK) del_fix(x);
159         //    释放y
160 #ifdef DE_BUG
161         delete y;
162 #endif
163     }
164     void del_fix(Node* &x) {
165         while (x != root && x->color == BLACK) {
166             //    x为当前节点
167             //    par x的父节点, sibling x的兄弟节点
168             Node *par = x->fa, *sibling = null;
169             //    x为父节点的左孩子
170             if (par->left == x){
171             //    兄弟节点则为父节点的右孩子
172                 sibling = par->right;
173             //    若兄弟节点的颜色为红色
174                 if (sibling->color == RED) {
175             //    Case1:将兄弟节点染成黑色,父节点染成红色
176                     sibling->color = BLACK;
177                     par->color = RED;
178             //    父节点左旋
179                     rotate_left(par);
180             //    重新设置兄弟节点
181                     sibling = par->right;
182                 } else 
183             //    Case2:兄弟节点为黑色,兄弟节点的左右孩子均为黑色
184                 if (sibling->left->color == BLACK && sibling->right->color == BLACK) {
185             //    将兄弟节点染成红色
186                     sibling->color = RED;
187             //    将父节点变成当前节点
188                     x = par;
189                 } else {
190             //    Case3:兄弟节点为黑色,兄弟节点的右孩子为黑色,左孩子为红色
191                     if (sibling->right->color == BLACK) {
192             //    将兄弟节点的左孩子染成黑色
193                         sibling->left->color = BLACK;
194             //    将兄弟节点染成红色
195                         sibling->color = RED;
196             //    将兄弟节点右旋
197                         rotate_right(sibling);
198             //    重新设置兄弟节点
199                         sibling = par->right;
200                     }
201             //    Case4:兄弟节点为黑色,兄弟节点的右孩子为红色,左孩子为任意颜色
202             //    将兄弟节点染成父节点的颜色
203                     sibling->color = par->color;
204             //    父节点染成黑色
205                     par->color = BLACK;
206             //    兄弟节点的右孩子染成黑色
207                     sibling->right->color = BLACK;
208             //    将父节点左旋,跳出循环。
209                     rotate_left(par);
210                     break;
211                 }
212             } else {
213             //    同上,只是由左变成右而已
214                 sibling = par->left;
215                 if (sibling->color == RED) {
216                     sibling->color = BLACK;
217                     par->color = RED;
218                     rotate_right(par);
219                     sibling = par->left;
220                 } else 
221                 if (sibling->left->color == BLACK && sibling->right->color == BLACK) {
222                     sibling->color = RED;
223                     x = par;
224                 } else {
225                     if (sibling->left->color == BLACK){
226                         sibling->right->color = BLACK;
227                         sibling->color = RED;
228                         rotate_left(sibling);
229                         sibling = par->left;
230                     } else {
231                         sibling->color = par->color;
232                         par->color = BLACK;
233                         sibling->left->color = BLACK;
234                         rotate_right(par);
235                         break;
236                     }
237                 }
238             }
239         }
240         x->color = BLACK;
241     }
242 }rbt_tree;
243 int main() {
244 //  以下为测试
245     int a = clock();
246     rbt_tree.init();
247     for (int i = 0; i < 2000000; i++) {
248         rbt_tree.insert(i);
249     }
250 #ifdef DE_BUG
251     for (int i = 0; i < 2000000; i++) {
252         rbt_tree.del(i);
253     }
254 #endif
255     rbt_tree.del(4);
256     printf("%d\n", clock() - a);
257     return 0;
258 }
View Code

下面是以bzoj3224/Tyvj 1728普通平衡树 为例实现了红黑树的各种操作
增加了size域(子树的大小),cnt域(关键字出现的次数)。
不想吐槽了,wa的快吐了%>_<% 由于插入,删除均用非递归方式实现的,

导致维护size,cnt域太麻烦了。。。
自己对拍了数据有输出1w多行才出错的(这咋调试啊 (*>﹏<*) )。还好最后发现了bug。

程序只通过了oj的数据,不知道还有没有隐含的bug →_→ 写的很搓懒得注释了。。。
欢迎各位游客批评指正O(∩_∩)O~~

技术分享
  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<string>
  6 #include<cstdio>
  7 #include<vector>
  8 #include<ctime>
  9 const int Max_N = 110000;
 10 struct Node {
 11     int data, s, c;
 12     bool color;
 13     Node *fa, *ch[2];
 14     inline void set(int _v, bool _color, int i, Node *p) {
 15         data = _v, color = _color, s = c = i;
 16         fa = ch[0] = ch[1] = p;
 17     }
 18     inline void push_up() {
 19         s = ch[0]->s + ch[1]->s + c;
 20     }
 21     inline void push_down() {
 22         for (Node *x = this; x->s; x = x->fa) x->s--;
 23     }
 24     inline int cmp(int v) const {
 25         return data == v ? -1 : v > data;
 26     }
 27 };
 28 struct RedBlackTree {
 29     int top;
 30     Node *root, *null;
 31     Node stack[Max_N], *tail, *store[Max_N];
 32     void init() {
 33         tail = &stack[0];
 34         null = tail++;
 35         null->set(0, 0, 0, NULL);
 36         root = null;
 37         top = 0;
 38     }
 39     inline Node *newNode(int v) {
 40         Node *p = null;
 41         if (!top) p = tail++;
 42         else p = store[--top];
 43         p->set(v, 1, 1, null);
 44         return p;
 45     }
 46     inline void rotate(Node* &x, bool d ) {
 47         Node *y = x->ch[!d];
 48         x->ch[!d] = y->ch[d];
 49         if (y->ch[d]->s) y->ch[d]->fa = x;
 50         y->fa = x->fa;
 51         if (!x->fa->s) root = y;
 52         else x->fa->ch[x->fa->ch[0] != x] = y;
 53         y->ch[d] = x;
 54         x->fa = y;
 55         y->s = x->s;
 56         x->push_up();
 57     }
 58     inline void insert(int v) {
 59         Node *x = root, *y = null;
 60         while (x->s) {
 61             x->s++, y = x;    
 62             int d = x->cmp(v);
 63             if (-1 == d) {
 64                 x->c++;
 65                 return;
 66             }
 67             x = x->ch[d];
 68         }
 69         x = newNode(v);
 70         if (y->s) y->ch[v > y->data] = x;
 71         else root = x;
 72         x->fa = y;
 73         insert_fix(x);
 74     }
 75     inline void insert_fix(Node* &x) {
 76         while (x->fa->color) {
 77             Node *par = x->fa, *Gp = par->fa;
 78             bool d = par == Gp->ch[0];
 79             Node *uncle = Gp->ch[d];
 80             if (uncle->color) {
 81                 par->color = uncle->color = 0;
 82                 Gp->color = 1;
 83                 x = Gp;
 84             } else if (x == par->ch[d]) {
 85                 rotate(x = par, !d);
 86             } else {
 87                 Gp->color = 1;
 88                 par->color = 0;
 89                 rotate(Gp, d);
 90             }
 91         }
 92         root->color = 0;
 93     }
 94     inline Node *find(Node *x, int data) {
 95         while (x->s && x->data != data) x = x->ch[x->data < data];
 96         return x;
 97     }
 98     inline void del_fix(Node* &x) {
 99         while (x != root && !x->color) {
100             bool d = x == x->fa->ch[0];
101             Node *par = x->fa, *sibling = par->ch[d];
102             if (sibling->color) {
103                 sibling->color = 0;
104                 par->color = 1;
105                 rotate(x->fa, !d);
106                 sibling = par->ch[d];
107             } else if (!sibling->ch[0]->color && !sibling->ch[1]->color) {
108                 sibling->color = 1, x = par;
109             } else {
110                 if (!sibling->ch[d]->color) {
111                     sibling->ch[!d]->color = 0;
112                     sibling->color = 1;
113                     rotate(sibling, d);
114                     sibling = par->ch[d];
115                 }
116                 sibling->color = par->color;
117                 sibling->ch[d]->color = par->color = 0;
118                 rotate(par, !d);
119                 break;
120             }
121         }
122         x->color = 0;
123     }
124     inline void del(int data) {
125         Node *z = find(root, data);
126         if (!z->s) return;
127         if (z->c > 1) {        
128             z->c--;
129             z->push_down();
130             return;
131         }
132         Node *y = z, *x = null;
133         if (z->ch[0]->s && z->ch[1]->s) {
134             y = z->ch[1];
135             while (y->ch[0]->s) y = y->ch[0];
136         }
137         x = y->ch[!y->ch[0]->s];
138         x->fa = y->fa;
139         if (!y->fa->s) root = x;
140         else y->fa->ch[y->fa->ch[1] == y] = x;
141         if (z != y) z->data = y->data, z->c = y->c;
142         y->fa->push_down();
143         for (Node *k = y->fa; y->c > 1 && k->s && k != z; k = k->fa) k->s -= y->c - 1;
144         if (!y->color) del_fix(x);
145         store[top++] = y;
146     }
147     inline void kth(int k) {
148         int t;
149         Node *x = root;
150         for (; x->s;) {
151             t = x->ch[0]->s;
152             if (k <= t) x = x->ch[0];
153             else if (t + 1 <= k && k <= t + x->c) break;
154             else k -= t + x->c, x = x->ch[1];
155         }
156         printf("%d\n", x->data);
157     }
158     inline void rank(int v) {
159         int t, cur = 0;
160         Node *x = root;
161         for (; x->s;) {
162             t = x->ch[0]->s;
163             if (v == x->data) break;
164             else if (v < x->data) x = x->ch[0];
165             else cur += t + x->c, x = x->ch[1];
166         }
167         printf("%d\n", cur + t + 1);
168     }
169     inline void succ(int v) {
170         int ret = 0;
171         Node *x = root;
172         while (x->s) {
173             if (x->data > v) ret = x->data, x = x->ch[0];
174             else x = x->ch[1];
175         }
176         printf("%d\n", ret);
177     }
178     inline void pred(int v) {
179         int ret = 0;
180         Node *x = root;
181         while (x->s) {
182             if (x->data < v) ret = x->data, x = x->ch[1];
183             else x = x->ch[0];
184         }
185         printf("%d\n", ret);
186     }
187 }rbt;
188 int main() {
189 #ifdef LOCAL
190     freopen("in.txt", "r", stdin);
191     freopen("out.txt", "w+", stdout);
192 #endif
193     rbt.init();
194     int n, op, v;
195     scanf("%d", &n);
196     while (n--) {
197         scanf("%d %d", &op, &v);
198         if (1 == op) rbt.insert(v);
199         else if (2 == op) rbt.del(v);
200         else if (3 == op) rbt.rank(v);
201         else if (4 == op) rbt.kth(v);
202         else if (5 == op) rbt.pred(v);
203         else rbt.succ(v);
204     }
205     return 0;
206 }
View Code

 

数据结构之红黑树

标签:

原文地址:http://www.cnblogs.com/GadyPu/p/4488875.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!