红黑树是一种自平衡二叉查找树,它的操作有着良好的最坏情况运行时间,并且在实践中是高效的: 它可以在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 }