1. 程式人生 > >紅黑樹(二)之 C語言的實現

紅黑樹(二)之 C語言的實現

  1 /**
  2  * C語言實現的紅黑樹(Red Black Tree)
  3  *
  4  * @author skywang
  5  * @date 2013/11/18
  6  */
  7 
  8 #include <stdio.h>
  9 #include <stdlib.h>
 10 #include "rbtree.h"
 11 
 12 #define rb_parent(r)   ((r)->parent)
 13 #define rb_color(r) ((r)->color)
 14 #define rb_is_red(r)   ((r)->color==RED)
 15
#define rb_is_black(r) ((r)->color==BLACK) 16 #define rb_set_black(r) do { (r)->color = BLACK; } while (0) 17 #define rb_set_red(r) do { (r)->color = RED; } while (0) 18 #define rb_set_parent(r,p) do { (r)->parent = (p); } while (0) 19 #define rb_set_color(r,c) do { (r)->color = (c); } while (0) 20
21 /* 22 * 建立紅黑樹,返回"紅黑樹的根"! 23 */ 24 RBRoot* create_rbtree() 25 { 26 RBRoot *root = (RBRoot *)malloc(sizeof(RBRoot)); 27 root->node = NULL; 28 29 return root; 30 } 31 32 /* 33 * 前序遍歷"紅黑樹" 34 */ 35 static void preorder(RBTree tree) 36 { 37 if(tree != NULL)
38 { 39 printf("%d ", tree->key); 40 preorder(tree->left); 41 preorder(tree->right); 42 } 43 } 44 void preorder_rbtree(RBRoot *root) 45 { 46 if (root) 47 preorder(root->node); 48 } 49 50 /* 51 * 中序遍歷"紅黑樹" 52 */ 53 static void inorder(RBTree tree) 54 { 55 if(tree != NULL) 56 { 57 inorder(tree->left); 58 printf("%d ", tree->key); 59 inorder(tree->right); 60 } 61 } 62 63 void inorder_rbtree(RBRoot *root) 64 { 65 if (root) 66 inorder(root->node); 67 } 68 69 /* 70 * 後序遍歷"紅黑樹" 71 */ 72 static void postorder(RBTree tree) 73 { 74 if(tree != NULL) 75 { 76 postorder(tree->left); 77 postorder(tree->right); 78 printf("%d ", tree->key); 79 } 80 } 81 82 void postorder_rbtree(RBRoot *root) 83 { 84 if (root) 85 postorder(root->node); 86 } 87 88 /* 89 * (遞迴實現)查詢"紅黑樹x"中鍵值為key的節點 90 */ 91 static Node* search(RBTree x, Type key) 92 { 93 if (x==NULL || x->key==key) 94 return x; 95 96 if (key < x->key) 97 return search(x->left, key); 98 else 99 return search(x->right, key); 100 } 101 int rbtree_search(RBRoot *root, Type key) 102 { 103 if (root) 104 return search(root->node, key)? 0 : -1; 105 } 106 107 /* 108 * (非遞迴實現)查詢"紅黑樹x"中鍵值為key的節點 109 */ 110 static Node* iterative_search(RBTree x, Type key) 111 { 112 while ((x!=NULL) && (x->key!=key)) 113 { 114 if (key < x->key) 115 x = x->left; 116 else 117 x = x->right; 118 } 119 120 return x; 121 } 122 int iterative_rbtree_search(RBRoot *root, Type key) 123 { 124 if (root) 125 return iterative_search(root->node, key) ? 0 : -1; 126 } 127 128 /* 129 * 查詢最小結點:返回tree為根結點的紅黑樹的最小結點。 130 */ 131 static Node* minimum(RBTree tree) 132 { 133 if (tree == NULL) 134 return NULL; 135 136 while(tree->left != NULL) 137 tree = tree->left; 138 return tree; 139 } 140 141 int rbtree_minimum(RBRoot *root, int *val) 142 { 143 Node *node; 144 145 if (root) 146 node = minimum(root->node); 147 148 if (node == NULL) 149 return -1; 150 151 *val = node->key; 152 return 0; 153 } 154 155 /* 156 * 查詢最大結點:返回tree為根結點的紅黑樹的最大結點。 157 */ 158 static Node* maximum(RBTree tree) 159 { 160 if (tree == NULL) 161 return NULL; 162 163 while(tree->right != NULL) 164 tree = tree->right; 165 return tree; 166 } 167 168 int rbtree_maximum(RBRoot *root, int *val) 169 { 170 Node *node; 171 172 if (root) 173 node = maximum(root->node); 174 175 if (node == NULL) 176 return -1; 177 178 *val = node->key; 179 return 0; 180 } 181 182 /* 183 * 找結點(x)的後繼結點。即,查詢"紅黑樹中資料值大於該結點"的"最小結點"。 184 */ 185 static Node* rbtree_successor(RBTree x) 186 { 187 // 如果x存在右孩子,則"x的後繼結點"為 "以其右孩子為根的子樹的最小結點"。 188 if (x->right != NULL) 189 return minimum(x->right); 190 191 // 如果x沒有右孩子。則x有以下兩種可能: 192 // (01) x是"一個左孩子",則"x的後繼結點"為 "它的父結點"。 193 // (02) x是"一個右孩子",則查詢"x的最低的父結點,並且該父結點要具有左孩子",找到的這個"最低的父結點"就是"x的後繼結點"。 194 Node* y = x->parent; 195 while ((y!=NULL) && (x==y->right)) 196 { 197 x = y; 198 y = y->parent; 199 } 200 201 return y; 202 } 203 204 /* 205 * 找結點(x)的前驅結點。即,查詢"紅黑樹中資料值小於該結點"的"最大結點"。 206 */ 207 static Node* rbtree_predecessor(RBTree x) 208 { 209 // 如果x存在左孩子,則"x的前驅結點"為 "以其左孩子為根的子樹的最大結點"。 210 if (x->left != NULL) 211 return maximum(x->left); 212 213 // 如果x沒有左孩子。則x有以下兩種可能: 214 // (01) x是"一個右孩子",則"x的前驅結點"為 "它的父結點"。 215 // (01) x是"一個左孩子",則查詢"x的最低的父結點,並且該父結點要具有右孩子",找到的這個"最低的父結點"就是"x的前驅結點"。 216 Node* y = x->parent; 217 while ((y!=NULL) && (x==y->left)) 218 { 219 x = y; 220 y = y->parent; 221 } 222 223 return y; 224 } 225 226 /* 227 * 對紅黑樹的節點(x)進行左旋轉 228 * 229 * 左旋示意圖(對節點x進行左旋): 230 * px px 231 * / / 232 * x y 233 * / \ --(左旋)--> / \ # 234 * lx y x ry 235 * / \ / \ 236 * ly ry lx ly 237 * 238 * 239 */ 240 static void rbtree_left_rotate(RBRoot *root, Node *x) 241 { 242 // 設定x的右孩子為y 243 Node *y = x->right; 244 245 // 將 “y的左孩子” 設為 “x的右孩子”; 246 // 如果y的左孩子非空,將 “x” 設為 “y的左孩子的父親” 247 x->right = y->left; 248 if (y->left != NULL) 249 y->left->parent = x; 250 251 // 將 “x的父親” 設為 “y的父親” 252 y->parent = x->parent; 253 254 if (x->parent == NULL) 255 { 256 //tree = y; // 如果 “x的父親” 是空節點,則將y設為根節點 257 root->node = y; // 如果 “x的父親” 是空節點,則將y設為根節點 258 } 259 else 260 { 261 if (x->parent->left == x) 262 x->parent->left = y; // 如果 x是它父節點的左孩子,則將y設為“x的父節點的左孩子” 263 else 264 x->parent->right = y; // 如果 x是它父節點的左孩子,則將y設為“x的父節點的左孩子” 265 } 266 267 // 將 “x” 設為 “y的左孩子” 268 y->left = x; 269 // 將 “x的父節點” 設為 “y” 270 x->parent = y; 271 } 272 273 /* 274 * 對紅黑樹的節點(y)進行右旋轉 275 * 276 * 右旋示意圖(對節點y進行左旋): 277 * py py 278 * / / 279 * y x 280 * / \ --(右旋)--> / \ # 281 * x ry lx y 282 * / \ / \ # 283 * lx rx rx ry 284 * 285 */ 286 static void rbtree_right_rotate(RBRoot *root, Node *y) 287 { 288 // 設定x是當前節點的左孩子。 289 Node *x = y->left; 290 291 // 將 “x的右孩子” 設為 “y的左孩子”; 292 // 如果"x的右孩子"不為空的話,將 “y” 設為 “x的右孩子的父親” 293 y->left = x->right; 294 if (x->right != NULL) 295 x->right->parent = y; 296 297 // 將 “y的父親” 設為 “x的父親” 298 x->parent = y->parent; 299 300 if (y->parent == NULL) 301 { 302 //tree = x; // 如果 “y的父親” 是空節點,則將x設為根節點 303 root->node = x; // 如果 “y的父親” 是空節點,則將x設為根節點 304 } 305 else 306 { 307 if (y == y->parent->right) 308 y->parent->right = x; // 如果 y是它父節點的右孩子,則將x設為“y的父節點的右孩子” 309 else 310 y->parent->left = x; // (y是它父節點的左孩子) 將x設為“x的父節點的左孩子” 311 } 312 313 // 將 “y” 設為 “x的右孩子” 314 x->right = y; 315 316 // 將 “y的父節點” 設為 “x” 317 y->parent = x; 318 } 319 320 /* 321 * 紅黑樹插入修正函式 322 * 323 * 在向紅黑樹中插入節點之後(失去平衡),再呼叫該函式; 324 * 目的是將它重新塑造成一顆紅黑樹。 325 * 326 * 引數說明: 327 * root 紅黑樹的根 328 * node 插入的結點 // 對應《演算法導論》中的z 329 */ 330 static void rbtree_insert_fixup(RBRoot *root, Node *node) 331 { 332 Node *parent, *gparent; 333 334 // 若“父節點存在,並且父節點的顏色是紅色” 335 while ((parent = rb_parent(node)) && rb_is_red(parent)) 336 { 337 gparent = rb_parent(parent); 338 339 //若“父節點”是“祖父節點的左孩子” 340 if (parent == gparent->left) 341 { 342 // Case 1條件:叔叔節點是紅色 343 { 344 Node *uncle = gparent->right; 345 if (uncle && rb_is_red(uncle)) 346 { 347 rb_set_black(uncle); 348 rb_set_black(parent); 349 rb_set_red(gparent); 350 node = gparent; 351 continue; 352 } 353 } 354 355 // Case 2條件:叔叔是黑色,且當前節點是右孩子 356 if (parent->right == node) 357 { 358 Node *tmp; 359 rbtree_left_rotate(root, parent); 360 tmp = parent; 361 parent = node; 362 node = tmp; 363 } 364 365 // Case 3條件:叔叔是黑色,且當前節點是左孩子。 366 rb_set_black(parent); 367 rb_set_red(gparent); 368 rbtree_right_rotate(root, gparent); 369 } 370 else//若“z的父節點”是“z的祖父節點的右孩子” 371 { 372 // Case 1條件:叔叔節點是紅色 373 { 374 Node *uncle = gparent->left; 375 if (uncle && rb_is_red(uncle)) 376 { 377 rb_set_black(uncle); 378 rb_set_black(parent); 379 rb_set_red(gparent); 380 node = gparent; 381 continue; 382 } 383 } 384 385 // Case 2條件:叔叔是黑色,且當前節點是左孩子 386 if (parent->left == node) 387 { 388 Node *tmp; 389 rbtree_right_rotate(root, parent); 390 tmp = parent; 391 parent = node; 392 node = tmp; 393 } 394 395 // Case 3條件:叔叔是黑色,且當前節點是右孩子。 396 rb_set_black(parent); 397 rb_set_red(gparent); 398 rbtree_left_rotate(root, gparent); 399 } 400 } 401 402 // 將根節點設為黑色 403 rb_set_black(root->node); 404 } 405 406 /* 407 * 新增節點:將節點(node)插入到紅黑樹中 408 * 409 * 引數說明: 410 * root 紅黑樹的根 411 * node 插入的結點 // 對應《演算法導論》中的z 412 */ 413 static void rbtree_insert(RBRoot *root, Node *node) 414 { 415 Node *y = NULL; 416 Node *x = root->node; 417 418 // 1. 將紅黑樹當作一顆二叉查詢樹,將節點新增到二叉查詢樹中。 419 while (x != NULL) 420 { 421 y = x; 422 if (node->key < x->key) 423 x = x->left; 424 else 425 x = x->right; 426 } 427 rb_parent(node) = y; 428 429 if (y != NULL) 430 { 431 if (node->key < y->key) 432 y->left = node; // 情況2:若“node所包含的值” < “y所包含的值”,則將node設為“y的左孩子” 433 else 434 y->right = node; // 情況3:(“node所包含的值” >= “y所包含的值”)將node設為“y的右孩子” 435 } 436 else 437 { 438 root->node = node; // 情況1:若y是空節點,則將node設為根 439 } 440 441 // 2. 設定節點的顏色為紅色 442 node->color = RED; 443 444 // 3. 將它重新修正為一顆二叉查詢樹 445 rbtree_insert_fixup(root, node); 446 } 447 448 /* 449 * 建立結點 450 * 451 * 引數說明: 452 * key 是鍵值。 453 * parent 是父結點。 454 * left 是左孩子。 455 * right 是右孩子。 456 */ 457 static Node* create_rbtree_node(Type key, Node *parent, Node *left, Node* right) 458 { 459 Node* p; 460 461 if ((p = (Node *)malloc(sizeof(Node))) == NULL) 462 return NULL; 463 p->key = key; 464 p->left = left; 465 p->right = right; 466 p->parent = parent; 467 p->color = BLACK; // 預設為黑色 468 469 return p; 470 } 471 472 /* 473 * 新建結點(節點鍵值為key),並將其插入到紅黑樹中 474 * 475 * 引數說明: 476 * root 紅黑樹的根 477 * key 插入結點的鍵值 478 * 返回值: 479 * 0,插入成功 480 * -1,插入失敗 481 */ 482 int insert_rbtree(RBRoot *root, Type key) 483 { 484 Node *node; // 新建結點 485 486 // 不允許插入相同鍵值的節點。 487 // (若想允許插入相同鍵值的節點,註釋掉下面兩句話即可!) 488 if (search(root->node, key) != NULL) 489 return -1; 490 491 // 如果新建結點失敗,則返回。 492 if ((node=create_rbtree_node(key, NULL, NULL, NULL)) == NULL) 493 return -1; 494 495 rbtree_insert(root, node); 496 497 return 0; 498 } 499 500 /* 501 * 紅黑樹刪除修正函式 502 * 503 * 在從紅黑樹中刪除插入節點之後(紅黑樹失去平衡),再呼叫該函式; 504 * 目的是將它重新塑造成一顆紅黑樹。 505 * 506 * 引數說明: 507 * root 紅黑樹的根 508 * node 待修正的節點 509 */ 510 static void rbtree_delete_fixup(RBRoot *root, Node *node, Node *parent) 511 { 512 Node *other; 513 514 while ((!node || rb_is_black(node)) && node != root->node) 515 { 516 if (parent->left == node) 517 { 518 other = parent->right; 519 if (rb_is_red(other)) 520 { 521 // Case 1: x的兄弟w是紅色的 522 rb_set_black(other); 523 rb_set_red(parent); 524 rbtree_left_rotate(root, parent); 525 other = parent->right; 526 } 527 if ((!other->left || rb_is_black(other->left)) && 528 (!other->right || rb_is_black(other->right))) 529 { 530 // Case 2: x的兄弟w是黑色,且w的倆個孩子也都是黑色的 531 rb_set_red(other); 532 node = parent; 533 parent = rb_parent(node); 534 } 535 else 536 { 537 if (!other->right || rb_is_black(other->right)) 538 { 539 // Case 3: x的兄弟w是黑色的,並且w的左孩子是紅色,右孩子為黑色。 540 rb_set_black(other->left); 541 rb_set_red(other); 542 rbtree_right_rotate(root, other); 543 other = parent->right; 544 } 545 // Case 4: x的兄弟w是黑色的;並且w的右孩子是紅色的,左孩子任意顏色。 546 rb_set_color(other, rb_color(parent)); 547 rb_set_black(parent); 548 rb_set_black(other->right); 549 rbtree_left_rotate(root, parent); 550 node = root->node; 551 break; 552 } 553 } 554 else 555 { 556 other = parent->left; 557 if (rb_is_red(other)) 558 { 559 // Case 1: x的兄弟w是紅色的 560 rb_set_black(other); 561 rb_set_red(parent); 562 rbtree_right_rotate(root, parent); 563 other = parent->left; 564 } 565 if ((!other->left || rb_is_black(other->left)) && 566 (!other->right || rb_is_black(other->right))) 567 { 568 // Case 2: x的兄弟w是黑色,且w的