红黑树
1 #include "MyRBTree.h" 2 #include <iostream> 3 4 5 6 MyRBTree::MyRBTree() 7 { 8 root_ = nullptr; 9 } 10 11 12 MyRBTree::~MyRBTree() 13 { 14 } 15 16 17 void MyRBTree::PrePrint(RBTNode *tree) 18 { 19 if (tree == nullptr) 20 return; 21 PrePrint(tree->lchild); 22 23 auto tmp = (tree->color == COLOR::RED) ? "RED" : "BLACK "; 24 std::cout << tmp << "___:" << tree->value << "\n"; 25 26 PrePrint(tree->rchild); 27 } 28 29 void MyRBTree::MidPrint(RBTNode *tree) 30 { 31 if (tree == nullptr) 32 return; 33 auto tmp = (tree->color == COLOR::RED) ? "RED" : "BLACK "; 34 std::cout << tmp << "___:" << tree->value<<"\n"; 35 MidPrint(tree->lchild); 36 MidPrint(tree->rchild); 37 } 38 39 40 RBTNode* MyRBTree::Search(RBTNode *tree, int value) 41 { 42 //没有找到 43 if (tree == nullptr) 44 return nullptr; 45 46 if (tree->value == value) 47 return tree; 48 49 if (tree->value >= value) 50 return Search(tree->lchild, value); 51 else 52 return Search(tree->rchild, value); 53 } 54 55 56 RBTNode *MyRBTree::FindForwardNode(RBTNode *tree) 57 { 58 while (tree->rchild != nullptr) 59 { 60 tree = tree->rchild; 61 } 62 return tree; 63 } 64 65 void MyRBTree::Del(int value) 66 { 67 //第一步,找到节点 68 auto node = Search(root_,value); 69 if (node == nullptr) 70 return; 71 72 bool left_side_unbalance = true;//当前节点的左(右)子树缺少一个黑节点 73 RBTNode *backward_node = nullptr; 74 if (node->lchild != nullptr) { 75 backward_node = FindForwardNode(node->lchild);//真正的前驱,没有右节点 76 } 77 else 78 backward_node = node;//原始node,没有左节点 79 80 //交换后继节点和当前节点value 81 { 82 auto tmp = node->value; 83 node->value = backward_node->value; 84 backward_node->value = tmp; 85 } 86 87 //开始删除后继节点,只有一个或者没有子树 88 { 89 bool is_red = backward_node->color == COLOR::RED; 90 auto parent = backward_node->parent; 91 92 //如果backward_node为根节点 93 if (parent == nullptr) 94 { 95 if (backward_node->lchild != nullptr) 96 { 97 backward_node->lchild->parent = nullptr; 98 backward_node->lchild->color = COLOR::BLACK; 99 delete backward_node; 100 root_ = backward_node->lchild; 101 } 102 else if (backward_node->rchild != nullptr) 103 { 104 backward_node->rchild->parent = nullptr; 105 backward_node->rchild->color = COLOR::BLACK; 106 delete backward_node; 107 root_ = backward_node->rchild; 108 } 109 110 return; 111 } 112 113 if (parent->lchild == backward_node) { 114 left_side_unbalance = true; 115 } 116 else { 117 left_side_unbalance = false; 118 } 119 120 //不存在两个子节点都存在的情况 121 if (backward_node->lchild != nullptr) 122 { 123 if (left_side_unbalance) { 124 parent->lchild = backward_node->lchild; 125 } 126 else { 127 parent->rchild = backward_node->lchild; 128 } 129 backward_node->lchild->parent = parent; 130 } 131 else if (backward_node->rchild != nullptr) 132 { 133 if (left_side_unbalance) { 134 parent->lchild = backward_node->rchild; 135 } 136 else { 137 parent->rchild = backward_node->rchild; 138 } 139 backward_node->rchild->parent = parent; 140 } 141 else if (backward_node->lchild == nullptr 142 && 143 backward_node->rchild == nullptr 144 ) 145 { 146 if (left_side_unbalance) 147 parent->lchild = nullptr; 148 else 149 parent->rchild = nullptr; 150 } 151 152 delete backward_node; 153 //后继节点重新指向 154 backward_node = parent; 155 156 //如果删除的节点为红色的,不影响红黑树属性,完成删除 157 if (is_red) 158 return; 159 } 160 161 162 DelBalance(backward_node, left_side_unbalance); 163 164 } 165 166 167 void MyRBTree::DelBalance(RBTNode *forward_parent, bool left_side_unbalance) 168 { 169 auto parent = forward_parent; 170 171 //如果backward_node为根节点 172 if (parent == nullptr) 173 { 174 root_ = forward_parent; 175 return; 176 } 177 178 //讨论backward_node的左子树少了一个黑节点的情况 179 if (left_side_unbalance) 180 { 181 //node 节点到这里已经必须是黑色的 182 auto uncle = parent->rchild; 183 auto u_l = uncle->lchild; 184 auto u_r = uncle->rchild; 185 186 auto color_parent = parent->color; 187 auto color_uncle_parent = uncle==nullptr? COLOR::BLACK:uncle->color; 188 auto color_u_l_parent = u_l == nullptr ? COLOR::BLACK : u_l->color; 189 auto color_u_r_parent = u_r == nullptr ? COLOR::BLACK : u_r->color; 190 191 //情况1:全黑 192 if (color_parent == COLOR::BLACK 193 &&color_uncle_parent == COLOR::BLACK 194 &&color_u_l_parent == COLOR::BLACK 195 &&color_u_r_parent == COLOR::BLACK 196 ) 197 { 198 uncle->color = COLOR::BLACK; 199 return DelBalance(parent);//递归parent,整颗parent树少了一个黑节点 200 } 201 202 //情况2:P红 其他黑 203 if (color_parent == COLOR::RED 204 &&color_uncle_parent == COLOR::BLACK 205 &&color_u_l_parent == COLOR::BLACK 206 &&color_u_r_parent == COLOR::BLACK 207 ) 208 { 209 uncle->color = COLOR::RED; 210 parent->color = COLOR::BLACK; 211 return;//搞定 212 } 213 214 //情况3:U红 其他黑 215 if (color_parent == COLOR::BLACK 216 &&color_uncle_parent == COLOR::RED 217 &&color_u_l_parent == COLOR::BLACK 218 &&color_u_r_parent == COLOR::BLACK 219 ) 220 { 221 uncle->color = COLOR::BLACK; 222 parent->color = COLOR::RED; 223 L_Rotate(parent); 224 return DelBalance(parent,true);//递归当前节点 225 } 226 227 //情况4:UL红 P无所谓 其他黑 228 if (color_uncle_parent == COLOR::BLACK 229 &&color_u_l_parent == COLOR::RED 230 &&color_u_r_parent == COLOR::BLACK 231 ) { 232 uncle->color = COLOR::RED; 233 u_l->color = COLOR::BLACK; 234 R_Rotate(uncle); 235 return DelBalance(parent);//递归当前节点 236 } 237 238 //情况5:UR红 P\UL无所谓 U黑 239 if (color_uncle_parent == COLOR::BLACK 240 &&color_u_r_parent == COLOR::RED 241 ) 242 { 243 uncle->color = parent->color; 244 parent->color = COLOR::BLACK; 245 u_r->color = COLOR::BLACK; 246 L_Rotate(parent); 247 return; 248 } 249 } 250 } 251 252 void MyRBTree::Insert(int value) 253 { 254 RBTNode *node = new RBTNode(); 255 node->value = value; 256 //根节点 直接插入 257 if (root_ == nullptr) { 258 root_ = node; 259 root_->color = COLOR::BLACK;//跟节点颜色默认为黑 260 return; 261 } 262 else { 263 InsertNode(root_, root_,node); 264 265 Balance(node); 266 } 267 268 269 } 270 271 272 273 void MyRBTree::InsertNode(RBTNode*&tree, RBTNode*parent, RBTNode*node) 274 { 275 do { 276 if (tree == nullptr) 277 { 278 tree = node; 279 node->parent = parent; 280 break; 281 } 282 //插入到左子树 283 if (tree->value >= node->value) { 284 InsertNode(tree->lchild, tree, node); 285 break; 286 } 287 //插入到右子树 288 if (tree->value < node->value) { 289 InsertNode(tree->rchild, tree,node); 290 break; 291 } 292 } while (0); 293 294 } 295 296 297 void MyRBTree::Balance(RBTNode *&node) 298 { 299 auto parent = node->parent; 300 301 if (parent == nullptr) 302 { 303 //说明node已经是根节点,直接黑化 304 node->color = COLOR::BLACK; 305 root_ = node; 306 return; 307 } 308 if (parent->parent == nullptr) 309 { 310 //说明node->parent已经是根节点,直接黑化 311 node->parent->color = COLOR::BLACK; 312 root_ = node->parent; 313 return; 314 } 315 316 //前面两步确保node含有父节点、祖父节点 317 318 319 if (node->parent->color == COLOR::BLACK) 320 { 321 //父节点颜色为黑 无需调整 322 return; 323 } 324 else if (node->parent->color == COLOR::RED) 325 { 326 //父节点为红,继续讨论 327 bool node_is_L_Child = false; //当前节点是父节点的左节点 328 bool parent_L_Child = false; //父节点为祖父节点的左孩子 329 auto parent = node->parent; 330 auto grand_pa = node->parent->parent; 331 RBTNode*uncle = nullptr; 332 if (parent == grand_pa->lchild) { 333 uncle = grand_pa->rchild; 334 parent_L_Child = true; 335 } 336 else { 337 uncle = grand_pa->lchild; 338 parent_L_Child = false; 339 } 340 341 if (node == parent->lchild) 342 node_is_L_Child = true; 343 else 344 node_is_L_Child = false; 345 346 //最简单的情况 347 //第0种情况:叔叔为红,那祖父肯定是黑 348 if (uncle != nullptr && uncle->color == COLOR::RED) 349 { 350 //策略:父节点和叔节点变黑,祖父变红,祖父作为当前节点,递归此函数 351 parent->color = COLOR::BLACK; 352 uncle->color = COLOR::BLACK; 353 grand_pa->color = COLOR::RED; 354 Balance(grand_pa); 355 return; 356 } 357 358 //以下情况,叔叔节点必须为黑,G点为黑,P点为红,N点也为红. 359 360 //<型:P点作为G点的左孩子,N点作为右孩子 361 //策略:以P为当前节点,左旋 362 if (!node_is_L_Child && parent_L_Child) 363 { 364 L_Rotate(parent); 365 return Balance(parent); 366 } 367 368 //>型:P点作为G点的右孩子,N点作为左孩子 369 //策略:以P为当前节点,右旋 370 if (node_is_L_Child && !parent_L_Child) 371 { 372 R_Rotate(parent); 373 return Balance(parent); 374 } 375 376 // /型:P点作为G点的左孩子,N点作为左孩子 377 //策略:祖父节点为当前节点,祖父节点变红,父节点变黑. 祖父节点右旋 378 if (node_is_L_Child && parent_L_Child) 379 { 380 parent->color = COLOR::BLACK; 381 grand_pa->color = COLOR::RED; 382 R_Rotate(grand_pa); 383 return Balance(grand_pa); 384 } 385 386 // \型:P点作为G点的右孩子,N点作为右孩子 387 //策略:祖父节点为当前节点,祖父节点变红,父节点变黑. 祖父节点左旋 388 if (!node_is_L_Child && !parent_L_Child) 389 { 390 parent->color = COLOR::BLACK; 391 grand_pa->color = COLOR::RED; 392 L_Rotate(grand_pa); 393 394 return Balance(grand_pa); 395 } 396 } 397 else 398 { 399 std::cout << "\nerror"; 400 } 401 } 402 403 404 RBTNode* MyRBTree::L_Rotate(RBTNode*node) { 405 406 RBTNode* parent = node->parent; 407 RBTNode * r_child = node->rchild; 408 409 if (parent == nullptr) 410 { 411 } 412 else if (parent->lchild == node) 413 { 414 parent->lchild = r_child; 415 } 416 else if (parent->rchild == node) 417 { 418 parent->rchild = r_child; 419 } 420 421 r_child->parent = parent; 422 423 if (r_child->lchild != nullptr) 424 { 425 r_child->lchild->parent = node; 426 } 427 node->rchild = r_child->lchild; 428 429 r_child->lchild = node; 430 node->parent = r_child; 431 432 return node; 433 } 434 435 //对node作右旋 436 RBTNode* MyRBTree::R_Rotate(RBTNode*node) { 437 438 RBTNode* parent = node->parent; 439 RBTNode * l_child = node->lchild; 440 441 if (parent == nullptr) 442 { 443 } 444 else if (parent->lchild == node) 445 { 446 parent->lchild = l_child; 447 } 448 else if (parent->rchild == node) 449 { 450 parent->rchild = l_child; 451 } 452 453 l_child->parent = parent; 454 455 if (l_child->rchild != nullptr) 456 { 457 l_child->rchild->parent = node; 458 } 459 node->lchild = l_child->rchild; 460 461 l_child->rchild = node; 462 node->parent = l_child; 463 464 return node; 465 }
首先了解红黑树特性:
- 根节点必须为黑
- 节点不是红就是黑
- 叶子结点必须是黑,也就是nil,其实无所谓
- 两个红不能互为父子节点
- 每条从根节点到叶子结点的路径包含的黑节点数目,都是相同的(插入的算法决定的)
插入节点的步骤:
- 插入节点首先上色为红色,因为红色好调整
- 按二叉排序树找到插入位置后,开始调整
插入的调整:
情形1:
父节点与叔节点都为红,由此推断祖父必须为黑,只需要将祖父变红,父亲和叔叔变黑即可,以祖父节点为当前节点递归
情形2,默认父节点为红,叔节点为黑或者为nil:
2.1:当前节点作为左子树,父节点作为右子树,也就是>型
处理方法:父节点右旋,变成 \ 型
2.2:当前节点作为右子树,父节点作为左子树,也就是<型
处理方法:父节点左旋,变成 / 型
2.3:当前节点作为右子树,父节点作为右子树,也就是 \ 型
处理方法:祖父节点左旋,祖父变红,父亲变黑。
2.4:当前节点作为左子树,父节点作为左子树,也就是 / 型
处理方法:祖父节点右旋,祖父变红,父亲变黑。
总结:
<型和>型,都只是中间状态,将其转化成 \ /型,再对祖父节点操作,插入完毕。
红黑树与AVL的性能对比:
查找 AVL占优
插入和删除 红黑树占优
因为红黑树保证插入每次都能在三次以内完成,减少了复杂度。
而红黑树的深度,由其特性可知,两棵树的深度之差,不会太多,因为黑节点数目相同,红色节点不能相邻,因此要是该树的黑色路径长度为N,最长的路径也不会超过2N。
红黑树的删除:
步骤一:删除的节点X分两种情况
- 删除节点只有或者没有子节点,这就是需要讨论的重点
- 删除节点有两个子节点,这种情况与二叉平衡树的删除一样,先找到删除节点的后继或者前驱节点Y,交换X和Y的值,从而问题变成删除Y节点,转化成第一点讨论的情况
- 如果X节点颜色为红,经过前面1.2两点,这里讨论的N节点最多只有一个子节点,只需将N节点的子节点N顶替上来,红黑树性质不变
- 如果X节点颜色为黑,就是步骤二讨论的内容
步骤二:删除的关键在于理解下面这张图,有以下几点需要注意:
- N节点为删除节点X的子节点,N替换了X原来的位置。由于步骤一已经将问题简化成,被删除节点只有或者没有子节点,所以X节点只有N一个子节点,如果X没有子节点,N为NIL节点,颜色默认为黑色
- P为N的父节点,S为N的兄弟节点。经过P点的两条路径,PN&PS。PN路径由于删除了X节点这个黑节点(这里X节点经过步骤一,必须为黑),所以PN和PS两条路径已经不平衡
- PN为少了一个黑节点的路径,称之为短路径,另外一条称之为兄弟路径。后面只讨论短路径位于左侧这种情况。(短路径位于右侧的情况,可以通过反转操作,也就是,左旋换成右旋,右旋变成左旋)

步骤三:现在情况简化为只讨论上图,讨论的范围包括P,S,SL,SR四个节点的颜色情况,需要分为几种情况
情况1:
P红,其他均为黑
策略1:
PS换色(P黑化,S红化)
结果1:恢复平衡
短路径增加一个黑节点,兄弟路径不变。
情况2:
S红,其他均为黑
策略2:
PS换色&P左旋
结果2:
短路径依旧存在,但转化成情况1,所以再进行一次换色,问题解决
情况3:
全黑
策略3:
S变红
结果3:
经过P节点的两条路径现在都少了一个黑节点,所以当前节点从N转化成了P,接着继续递归分析P。
情况4:
SL红(因此S黑),SR黑,P无所谓
策略4:
S与SL换色,S右旋
结果4:
PN依旧为短路径,但是转化为情况5
情况5:
SR红(因此S黑),SL无所谓,P无所谓
策略5:
S变成P的颜色
P黑化
SR黑化
P左旋
结果5:恢复平衡
总结:上述情况看似不好记忆,但可以推理出来,下面是帮助记忆的方法。
重点在于五个节点:N P S SL SR,N的颜色必须为黑,因此就只有四个节点的颜色需要讨论
前面三种比较好记忆,要么全黑,要么除了P,其他全黑,要么除了S,其他全黑。
剩下的是SL或者SR为红的情况,称之为复杂情况
第一种复杂情况,SL为红,SR为黑,那么由于红黑树特性,S必须为黑。剩下P点无所谓
第二种复杂情况,SR为红,SL无所谓,S必须为黑,剩下P点无所谓
第一种复杂情况需要转化为第二种,因此旋转和变色的策略很好推导
第二种复杂情况,可以根据PN短路径需要增加一个黑节点,而SL和SR这两条路径需要和原来保持一致的黑色数,变色和旋转也是很好推导的
下面的图是上面几种情况的可视化总结

附上参考网络
浙公网安备 33010602011771号