1. 程式人生 > >紅黑樹(五)之 Java的實現

紅黑樹(五)之 Java的實現

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