红黑树是一种自平衡二叉查找树,它的操作有着良好的最坏情况运行时间,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n是树中元素的数目。
红黑树应用:
1.linux内核中,进程的虚拟地址区间由红黑树组织管理
2.nginx中,超时时间由红黑树组织管理
3.C++ STL中,C++中set,multiset,map,multimap集合模板类都是在STL红黑树的基础之上实现的
……
下面看红黑树在gcc中C++标准库的实现,只关注结点的插入、删除及相应的树平衡操作
I.红黑树的结点
/* gcc-4.4.5/libstdc++-v3/include/bits/stl_tree.h */
/* /usr/include/c++/4.4.4/bits/stl_tree.h */
85 enum _Rb_tree_color { _S_red = false, _S_black = true };
86
87 struct _Rb_tree_node_base
88 {
89 typedef _Rb_tree_node_base* _Base_ptr;
90 typedef const _Rb_tree_node_base* _Const_Base_ptr;
91
92 _Rb_tree_color _M_color;
93 _Base_ptr _M_parent;
94 _Base_ptr _M_left;
95 _Base_ptr _M_right;
96
97 static _Base_ptr
98 _S_minimum(_Base_ptr __x)
99 {
100 while (__x->_M_left != 0) __x = __x->_M_left;
101 return __x;
102 }
103
104 static _Const_Base_ptr
105 _S_minimum(_Const_Base_ptr __x)
106 {
107 while (__x->_M_left != 0) __x = __x->_M_left;
108 return __x;
109 }
110
111 static _Base_ptr
112 _S_maximum(_Base_ptr __x)
113 {
114 while (__x->_M_right != 0) __x = __x->_M_right;
115 return __x;
116 }
117
118 static _Const_Base_ptr
119 _S_maximum(_Const_Base_ptr __x)
120 {
121 while (__x->_M_right != 0) __x = __x->_M_right;
122 return __x;
123 }
124 };
II.结点的插入
结点的插入主要分以下两个步骤:
1.我们首先以二叉查找树的方法增加节点并标记它为红色。(如果设为黑色,就会导致根到叶子的路径上有一条路上,多一个额外的黑节点,这个是很难调整的。但是设为红色节点后,可能会导致出现两个连续红色节点的冲突,那么可以通过颜色调换(color flips)和树旋转来调整。)
2.出现连红时做插入平衡操作
i.插入平衡操作(消除连红)
__x:需要做插入平衡操作的结点
__p:__x的父节点
__xpp:__x的祖父节点
__y:__x的叔父节点
出现连红(__x,__p为红色,__xpp为黑色)时会有以下三种情况(只看__p是__xpp左儿子的情况)
1.叔父节点是红色,则不能通过翻转/颜色调换使树重新平衡,只能做颜色调换并向祖父节点递归做平衡操作
2.叔父节点是黑色,__x是__p的左儿子,通过祖父节点右翻转和颜色调换可使树平衡
3.叔父节点是黑色,__x是__p的右儿子,可以通过__p左翻转和颜色调换变成第二种情况,做相应的操作进而使树平衡
ii.结点插入实现
/* gcc-4.4.5/libstdc++-v3/src/tree.cc */
160 void
161 _Rb_tree_insert_and_rebalance(const bool __insert_left,
162 _Rb_tree_node_base* __x,
163 _Rb_tree_node_base* __p,
164 _Rb_tree_node_base& __header)
165 {
166 _Rb_tree_node_base *& __root = __header._M_parent;
167
168 // Initialize fields in new node to insert.
169 __x->_M_parent = __p;
170 __x->_M_left = 0;
171 __x->_M_right = 0;
172 __x->_M_color = _S_red;
173
174 // Insert.
175 // Make new node child of parent and maintain root, leftmost and
176 // rightmost nodes.
177 // N.B. First node is always inserted left.
178 if (__insert_left)
179 {
180 __p->_M_left = __x; // also makes leftmost = __x when __p == &__header
181
182 if (__p == &__header)
183 {
184 __header._M_parent = __x;
185 __header._M_right = __x;
186 }
187 else if (__p == __header._M_left)
188 __header._M_left = __x; // maintain leftmost pointing to min node
189 }
190 else
191 {
192 __p->_M_right = __x;
193
194 if (__p == __header._M_right)
195 __header._M_right = __x; // maintain rightmost pointing to max node
196 }
/* 当结点与父结点出现连红的情况,需要做树平衡操作;直到树根为止,当向上递归到树根且树根结点是红色时,会修改树根结点为黑色进而增加了树的深度 */
197 // Rebalance.
198 while (__x != __root
199 && __x->_M_parent->_M_color == _S_red)
200 {
201 _Rb_tree_node_base* const __xpp = __x->_M_parent->_M_parent;
202
203 if (__x->_M_parent == __xpp->_M_left) /* 父节点是祖父节点的左儿子,父节点是祖父的右儿子与其操作一致,只不过将一些操作由左变成右、由右变成左 */
204 {
205 _Rb_tree_node_base* const __y = __xpp->_M_right; /* 叔父节点 */
206 if (__y && __y->_M_color == _S_red) /* 叔父节点是红色,则不能通过翻转来平衡树,只能向祖父节点递归平衡 */
207 {
208 __x->_M_parent->_M_color = _S_black;
209 __y->_M_color = _S_black;
210 __xpp->_M_color = _S_red;
211 __x = __xpp;
212 }
213 else /* 叔父节点是黑色,则可以通过翻转来平衡树 */
214 {
215 if (__x == __x->_M_parent->_M_right) /* 节点是父节点的右儿子,翻转将父节点变成节点的左儿子 */
216 {
217 __x = __x->_M_parent;
218 _Rb_tree_rotate_left(__x, __root);
219 }
220 __x->_M_parent->_M_color = _S_black;
221 __xpp->_M_color = _S_red;
222 _Rb_tree_rotate_right(__xpp, __root); /* 祖父节点右翻转使树平衡 */
223 }
224 }
225 else
226 {
227 _Rb_tree_node_base* const __y = __xpp->_M_left;
228 if (__y && __y->_M_color == _S_red)
229 {
230 __x->_M_parent->_M_color = _S_black;
231 __y->_M_color = _S_black;
232 __xpp->_M_color = _S_red;
233 __x = __xpp;
234 }
235 else
236 {
237 if (__x == __x->_M_parent->_M_left)
238 {
239 __x = __x->_M_parent;
240 _Rb_tree_rotate_right(__x, __root);
241 }
242 __x->_M_parent->_M_color = _S_black;
243 __xpp->_M_color = _S_red;
244 _Rb_tree_rotate_left(__xpp, __root);
245 }
246 }
247 }
248 __root->_M_color = _S_black;
249 }
III.结点的删除
结点的删除主要分以下两个步骤:
1.如果需要删除的节点有两个儿子,那么问题可以被转化成删除另一个只有一个儿子的节点的问题;删除相应的结点
2.删除的结点是黑色时,破坏了树的平衡,则需做删除平衡操作
i.删除平衡操作(删除了黑色结点需要做删除平衡操作,通过添加黑色结点来使树重新平衡)
__x:需要做删除平衡操作的结点
__x_parent:__x的父节点
__w:__x的兄弟节点
__wl:__w的左儿子
__wr:__w的右儿子
需要删除平衡操作时会有以下五种情况(只看__x是__x_parent左儿子的情况)
1.__x是红色的,则直接将其变成黑色即可
2.__x是黑色或为NULL
2.1__w是黑色
2.1.1右儿子是红色,则可通过__w左翻转和颜色调换使树重新平衡
2.1.2左儿子是红色,则可通过__w右翻转和颜色调换,变成2.1.1的情况
2.1.3左、右儿子都不是红色,则要做颜色调换,并且向上递归做平衡树操作
2.2__w是红色
通过__x_parent的左翻转和颜色调换变成2.1的情况
ii.结点删除实现
251 _Rb_tree_node_base*
252 _Rb_tree_rebalance_for_erase(_Rb_tree_node_base* const __z,
253 _Rb_tree_node_base& __header)
254 {
255 _Rb_tree_node_base *& __root = __header._M_parent;
256 _Rb_tree_node_base *& __leftmost = __header._M_left;
257 _Rb_tree_node_base *& __rightmost = __header._M_right;
258 _Rb_tree_node_base* __y = __z;
259 _Rb_tree_node_base* __x = 0;
260 _Rb_tree_node_base* __x_parent = 0;
261
262 if (__y->_M_left == 0) // __z has at most one non-null child. y == z.
263 __x = __y->_M_right; // __x might be null.
264 else
265 if (__y->_M_right == 0) // __z has exactly one non-null child. y == z.
266 __x = __y->_M_left; // __x is not null.
267 else
268 {
269 // __z has two non-null children. Set __y to
270 __y = __y->_M_right; // __z's successor. __x might be null.
271 while (__y->_M_left != 0)
272 __y = __y->_M_left;
273 __x = __y->_M_right;
274 }
/*
* 如果需要删除的节点有两个儿子(为了表述方便,这里所指的儿子,为非叶子节点的儿子),那么问题可以被转化成删除另一个只有一个儿子的节点的问题
* 通过互换要删除节点的右子树的最小元素与要删除节点的值,再删除右子树的最小元素节点(必定有少于两个非叶子的儿子),这就把问题简化为如何删除最多有一个儿子的节点的问题
* __y : 实际要删除的节点
* __x : 实际要删除的节点的儿子(非叶子节点或NULL),__y是黑色则通过__x的路径少了一个黑色结点,所以要平衡的该结点的子树
*/
275 if (__y != __z) /* 实际删除的节点与要删除的节点不相同,则将实际删除节点与要删除节点互换,并删除要删除的节点,最后由__y指向实际删除的节点 */
276 {
/* 这里是relink而不是交换节点的值,是因为如果是交换节点的值那么对应对象的地址也会发生变化,通过地址访问的话会出现问题 */
277 // relink y in place of z. y is z's successor
278 __z->_M_left->_M_parent = __y;
279 __y->_M_left = __z->_M_left;
280 if (__y != __z->_M_right)
281 {
282 __x_parent = __y->_M_parent;
283 if (__x) __x->_M_parent = __y->_M_parent;
284 __y->_M_parent->_M_left = __x; // __y must be a child of _M_left
285 __y->_M_right = __z->_M_right;
286 __z->_M_right->_M_parent = __y;
287 }
288 else
289 __x_parent = __y;
290 if (__root == __z)
291 __root = __y;
292 else if (__z->_M_parent->_M_left == __z)
293 __z->_M_parent->_M_left = __y;
294 else
295 __z->_M_parent->_M_right = __y;
296 __y->_M_parent = __z->_M_parent;
297 std::swap(__y->_M_color, __z->_M_color);
298 __y = __z;
299 // __y now points to node to be actually deleted
300 }
301 else /* 删除结点__z,此时__leftmost或__rightmost可能会发生改变 */
302 { // __y == __z
303 __x_parent = __y->_M_parent;
304 if (__x)
305 __x->_M_parent = __y->_M_parent;
306 if (__root == __z)
307 __root = __x;
308 else
309 if (__z->_M_parent->_M_left == __z)
310 __z->_M_parent->_M_left = __x;
311 else
312 __z->_M_parent->_M_right = __x;
313 if (__leftmost == __z)
314 {
315 if (__z->_M_right == 0) // __z->_M_left must be null also
316 __leftmost = __z->_M_parent;
317 // makes __leftmost == _M_header if __z == __root
318 else
319 __leftmost = _Rb_tree_node_base::_S_minimum(__x);
320 }
321 if (__rightmost == __z)
322 {
323 if (__z->_M_left == 0) // __z->_M_right must be null also
324 __rightmost = __z->_M_parent;
325 // makes __rightmost == _M_header if __z == __root
326 else // __x == __z->_M_left
327 __rightmost = _Rb_tree_node_base::_S_maximum(__x);
328 }
329 }
330 if (__y->_M_color != _S_red) /* 如果实际删除的结点是红色,则不会改变树的平衡,所以不需要处理;但是要删除的结点是黑色,则会影响树的平衡,所以要做树平衡操作 */
331 {
/* 向上递归平衡__x子树操作(__x子树添加一个黑色结点),直到__x子树平衡(__x为红色或树根) */
332 while (__x != __root && (__x == 0 || __x->_M_color == _S_black))
333 if (__x == __x_parent->_M_left) /* __x是左子树;__x是右子树时操作相同,只不过将右变成左、将左变成右 */
334 {
335 _Rb_tree_node_base* __w = __x_parent->_M_right; /* __w为平衡子树节点的兄弟 */
/* 如果__w为红色,通过翻转转换成__w是黑色的情况 */
336 if (__w->_M_color == _S_red)
337 {
338 __w->_M_color = _S_black;
339 __x_parent->_M_color = _S_red;
340 _Rb_tree_rotate_left(__x_parent, __root);
341 __w = __x_parent->_M_right;
342 }
/* 此时__w必为黑色 */
343 if ((__w->_M_left == 0 ||
344 __w->_M_left->_M_color == _S_black) &&
345 (__w->_M_right == 0 ||
346 __w->_M_right->_M_color == _S_black)) /* __w的左、右子结点没有一个是红色,则修改兄弟__w的颜色为红色,向上层递归平衡上层子树
347 {
348 __w->_M_color = _S_red;
349 __x = __x_parent;
350 __x_parent = __x_parent->_M_parent;
351 }
352 else
353 {
354 if (__w->_M_right == 0
355 || __w->_M_right->_M_color == _S_black) /* 如果__w的左子结点是红色,通过右翻转转换成__w的右子结点是红色的情况 */
356 {
357 __w->_M_left->_M_color = _S_black;
358 __w->_M_color = _S_red;
359 _Rb_tree_rotate_right(__w, __root);
360 __w = __x_parent->_M_right;
361 }
/* 此时__w的右子结点必为红色 */
362 __w->_M_color = __x_parent->_M_color;
363 __x_parent->_M_color = _S_black;
364 if (__w->_M_right)
365 __w->_M_right->_M_color = _S_black;
366 _Rb_tree_rotate_left(__x_parent, __root);
367 break;
/* 通过翻转后可使树平衡,退出平衡操作 */
368 }
369 }
370 else
/* 同__x是左子树操作类似 */
371 {
372 // same as above, with _M_right <-> _M_left.
373 _Rb_tree_node_base* __w = __x_parent->_M_left;
374 if (__w->_M_color == _S_red)
375 {
376 __w->_M_color = _S_black;
377 __x_parent->_M_color = _S_red;
378 _Rb_tree_rotate_right(__x_parent, __root);
379 __w = __x_parent->_M_left;
380 }
381 if ((__w->_M_right == 0 ||
382 __w->_M_right->_M_color == _S_black) &&
383 (__w->_M_left == 0 ||
384 __w->_M_left->_M_color == _S_black))
385 {
386 __w->_M_color = _S_red;
387 __x = __x_parent;
388 __x_parent = __x_parent->_M_parent;
389 }
390 else
391 {
392 if (__w->_M_left == 0 || __w->_M_left->_M_color == _S_black)
393 {
394 __w->_M_right->_M_color = _S_black;
395 __w->_M_color = _S_red;
396 _Rb_tree_rotate_left(__w, __root);
397 __w = __x_parent->_M_left;
398 }
399 __w->_M_color = __x_parent->_M_color;
400 __x_parent->_M_color = _S_black;
401 if (__w->_M_left)
402 __w->_M_left->_M_color = _S_black;
403 _Rb_tree_rotate_right(__x_parent, __root);
404 break;
405 }
406 }
407 if (__x) __x->_M_color = _S_black;
408 }
409 return __y;
410 }