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 }
首先了解紅黑樹特性:node
插入節點的步驟:ios
插入的調整:算法
情形1:ide
父節點與叔節點都爲紅,由此推斷祖父必須爲黑,只須要將祖父變紅,父親和叔叔變黑便可,以祖父節點爲當前節點遞歸函數
情形2,默認父節點爲紅,叔節點爲黑或者爲nil:性能
2.1:當前節點做爲左子樹,父節點做爲右子樹,也就是>型spa
處理方法:父節點右旋,變成 \ 型code
2.2:當前節點做爲右子樹,父節點做爲左子樹,也就是<型blog
處理方法:父節點左旋,變成 / 型排序
2.3:當前節點做爲右子樹,父節點做爲右子樹,也就是 \ 型
處理方法:祖父節點左旋,祖父變紅,父親變黑。
2.4:當前節點做爲左子樹,父節點做爲左子樹,也就是 / 型
處理方法:祖父節點右旋,祖父變紅,父親變黑。
總結:
<型和>型,都只是中間狀態,將其轉化成 \ /型,再對祖父節點操做,插入完畢。
紅黑樹與AVL的性能對比:
查找 AVL佔優
插入和刪除 紅黑樹佔優
由於紅黑樹保證插入每次都能在三次之內完成,減小了複雜度。
而紅黑樹的深度,由其特性可知,兩棵樹的深度之差,不會太多,由於黑節點數目相同,紅色節點不能相鄰,所以要是該樹的黑色路徑長度爲N,最長的路徑也不會超過2N。
紅黑樹的刪除:
步驟一:刪除的節點X分兩種狀況
步驟二:刪除的關鍵在於理解下面這張圖,有如下幾點須要注意:
步驟三:如今狀況簡化爲只討論上圖,討論的範圍包括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這兩條路徑須要和原來保持一致的黑色數,變色和旋轉也是很好推導的
下面的圖是上面幾種狀況的可視化總結