紅黑樹插入操作原理及java實現


紅黑樹是一種二叉平衡查找樹,每個結點上有一個存儲位來表示結點的顏色,可以是RED或BLACK。紅黑樹具有以下性質:

(1) 每個結點是紅色或是黑色

(2) 根結點是黑色的

(3) 如果一個結點是紅色的,則它的兩個兒子都是黑色的

(4) 對於每個結點,從該結點到其子孫結點的所有路徑上包含相同數目的黑結點

通過紅黑樹的性質,可以保證所有基於紅黑樹的實現都能保證操作的運行時間為對數級別(范圍查找除外。它所需的額外時間和返回的鍵的數量成正比)。

Java的TreeMap就是通過紅黑樹實現的。

紅黑樹的操作如果不畫圖很容易搞糊塗,下面通過圖示來說明紅黑樹的插入操作。

插入一個紅色的節點到紅黑樹中之后,會有6種情況:圖示中N表示插入的節點,P表示父節點,U表示叔叔節點,G表示祖父節點,X表示當前操作節點

 

代碼如下:

  1 public class RedBlackBST<Key extends Comparable<Key>, Value> {
  2     private Node root;
  3     private static final boolean RED = true;
  4     private static final boolean BLACK = false;
  5     private class Node{
  6         private Key key; //
  7         private Value val; //
  8         private Node left, right, parent; //左右子樹和父節點
  9         private boolean color; //由其父節點指向它的鏈接的顏色
 10         
 11         public Node(Key key, Value val,Node parent, boolean color){
 12             this.key = key;
 13             this.val = val;
 14             this.color = color;
 15         }
 16     }
 17     
 18     public Value get(Key key){
 19         Node x = root;
 20         while(x!=null){
 21             int cmp = key.compareTo(x.key);
 22             if(cmp < 0 ) x = x.left;
 23             else if(cmp > 0) x = x.right;
 24             else return x.val;
 25         }
 26         return null;
 27     }
 28     
 29     public void put(Key key, Value val){
 30         if(root==null) { //如果是根節點,就將節點新建為黑色
 31             root = new Node(key,val,null,BLACK);
 32             return;
 33         }
 34         //尋找合適的插入位置
 35         Node parent = null;
 36         Node cur = root;
 37         while(cur!=null) {
 38             parent = cur;
 39             if(key.compareTo(cur.key)>0) cur=cur.right;
 40             else cur = cur.left;
 41         }
 42         Node n = new Node(key,val,parent,RED); //普通的新建節點為紅色
 43         //將新節點插入parent下
 44         if(key.compareTo(parent.key) > 0) parent.right = n;
 45         else parent.left = n;
 46         //插入新節點后要調整樹中部分節點的顏色和屬性來保證紅黑樹的特征不被破壞
 47         fixAfterInsertion(n); 
 48     }
 49     private Node parentOf(Node x) {
 50         return (x==null ? null : x.parent);
 51     }
 52     private boolean colorOf(Node x) {
 53         return (x==null ? BLACK : x.color);
 54     }
 55     private Node leftOf(Node x) {
 56         return (x==null ? null : x.left);
 57     }
 58     private Node rightOf(Node x) {
 59         return(x==null ? null : x.right);
 60     }
 61     private void setColor(Node x, boolean color) {
 62         if(x!=null)
 63             x.color = color;
 64     }
 65     
 66     private void fixAfterInsertion(Node x) {
 67         while(x!=null && colorOf(parentOf(x)) == RED) {
 68             Node grandPa = parentOf(parentOf(x));
 69             Node parent = parentOf(x);
 70             if(parent == leftOf(grandPa)) {//case 1 || case2 || case3
 71                 Node uncle = rightOf(grandPa);
 72                 if(colorOf(uncle) == RED) {//case1, uncle is red
 73                     setColor(parent,BLACK);    //父節點置黑
 74                     setColor(uncle, BLACK);    //叔叔節點置黑
 75                     setColor(grandPa,RED);    //祖父節點置紅
 76                     x = grandPa; //因為祖父節點由黑轉紅,故要重新調整父節點及其祖先的紅黑屬性
 77                 }else {//case2 || case3,uncle is black
 78                     if(x==rightOf(parent)) { //case2
 79                         x = parent;
 80                         rotateLeft(x);
 81                     }
 82                     //case3
 83                     setColor(parent,BLACK);
 84                     setColor(grandPa, RED);
 85                     rotateRight(grandPa);
 86                 }
 87                 
 88             }else {//case4 || case 5 || case6
 89                 Node uncle = leftOf(grandPa);
 90                 if(colorOf(uncle) == RED) { //case4 || case5 || case6
 91                     setColor(parent,BLACK);
 92                     setColor(uncle, BLACK);
 93                     setColor(grandPa,RED);
 94                     x = grandPa;
 95                 }else{ //case5 || case6, uncle is black
 96                     if(x==leftOf(parent)) { //case5
 97                         x = parent;
 98                         rotateRight(x);
 99                     }
100                     //case6
101                     setColor(parent,BLACK);
102                     setColor(grandPa, RED);
103                     rotateLeft(grandPa);
104                 }
105             }
106         }
107     }
108     private void rotateLeft(Node x) {
109         if(x==null) return;
110         Node y = x.right;
111         x.right = y.left;
112         if(y.left!=null)
113             y.left.parent = x;
114         y.left = x;
115         y.parent = x.parent;
116         if(x.parent == null) {
117             root = y;
118         }
119         else if(x.parent.left == x) {
120             x.parent.left = y;
121         }else {
122             x.parent.right = y;
123         }
124         x.parent = y;
125     }
126     private void rotateRight(Node x) {
127         if(x==null) return;
128         Node y = x.left;
129         x.left = y.right;
130         if(y.right != null)
131             y.right.parent = x;
132         y.right = x;
133         y.parent = x.parent;
134         if(x.parent == null) {
135             root = y;
136         }else if(x.parent.left==x) {
137             x.parent.left = y;
138         }else {
139             x.parent.right=y;
140         }
141         x.parent = y;
142     }
143     
144 }

上面的rotateLeft和rotateRight有必要畫個圖示:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM