十、紅黑樹
阿新 • • 發佈:2020-10-11
一、程式碼
1 package rbtree; 2 3 public class RBTree<K extends Comparable<K>, V> { 4 private static final boolean RED = true; 5 private static final boolean BLACK = false; 6 private RBNode root;//根節點 7 8 9 //尋找當前節點的父節點parentOf() 10 private RBNode parentOf(RBNode node) {11 if (node != null) { 12 return node.parent; 13 } 14 return null; 15 } 16 17 //判斷當前節點是否為紅色 18 private boolean isRed(RBNode node) { 19 if (node != null) { 20 return node.color == RED; 21 } 22 return false;23 } 24 25 //判斷當前節點是否為黑色 26 private boolean isBlack(RBNode node) { 27 if (node != null) { 28 return node.color == BLACK; 29 } 30 return false; 31 } 32 33 //設定節點成紅色 34 private void setRed(RBNode node) { 35 if (node != null) {36 node.color = RED; 37 } 38 } 39 40 //設定節點成黑色 41 private void setBlack(RBNode node) { 42 if (node != null) { 43 node.color = BLACK; 44 } 45 } 46 47 //中序遍歷 48 public void inOrderPrint() { 49 inOrderPrint(this.root); 50 } 51 52 //內部中序遍歷 53 private void inOrderPrint(RBNode node) { 54 if (node != null) { 55 inOrderPrint(node.left); 56 System.out.println("key:" + node.key + ",value:" + node.value); 57 inOrderPrint(node.right); 58 } 59 } 60 61 //左旋 62 63 /** 64 * p p 65 * | | 66 * x y 67 * / \ --> / \ 68 * lx y x ry 69 * / \ / \ 70 * ly ry lx ly 71 * <p> 72 * 1.將ly設定成x的右子節點 73 * 2.將x的父節點設定成y的父節點 74 * 3.將y的左子節點設定成x 75 */ 76 private void leftRotate(RBNode x) { 77 if (x != null) { 78 RBNode y = x.right; 79 //1. 80 if (y != null) { 81 x.right = y.left; 82 RBNode ly = y.left; 83 if (ly != null) { 84 ly.parent = x; 85 } 86 //2. 87 if (x.parent != null) { 88 y.parent = x.parent; 89 if (x.parent.left == x) { 90 x.parent.left = y; 91 } else { 92 x.parent.right = y; 93 } 94 } else { 95 this.root = y; 96 } 97 //3. 98 y.left = x; 99 x.parent = y; 100 } else { 101 return; 102 } 103 } else { 104 return; 105 } 106 } 107 108 //右旋 109 110 /** 111 * p p 112 * | | 113 * x y 114 * / \ --> / \ 115 * y lx ly x 116 * / \ / \ 117 * ly ry ry lx 118 * <p> 119 * 1.將ry設定成x的右子節點 120 * 2.將x的父節點設定成y的父節點 121 * 3.將y的右子節點設定成x 122 */ 123 private void rightRotate(RBNode x) { 124 if (x == null) { 125 return; 126 } else { 127 RBNode y = x.left; 128 if (y == null) { 129 return; 130 } else { 131 //1. 132 RBNode ry = y.right; 133 x.left = ry; 134 if (ry != null) { 135 ry.parent = x; 136 } 137 //2. 138 if (x.parent != null) { 139 y.parent = x.parent; 140 if (x.parent.left == x) { 141 x.parent.left = y; 142 } else { 143 x.parent.right = y; 144 } 145 } else { 146 this.root = y; 147 } 148 //3. 149 y.right = x; 150 x.parent = y; 151 } 152 } 153 } 154 155 //外部插入方法 156 public void insert(K key, V value) { 157 //將key和value封裝成一個node物件 158 RBNode node = new RBNode(); 159 node.setKey(key); 160 node.setValue(value); 161 node.setColor(RED); 162 insert(node); 163 } 164 165 //內部插入方法 166 private void insert(RBNode node) { 167 RBNode parent = null; 168 RBNode temp = this.root;//臨時變數,為找到當前node的父節點 169 while (temp != null) { 170 parent = temp; 171 int cmp = node.key.compareTo(temp.key); 172 if (cmp > 0) {//當前node.key比parent大 173 temp = temp.right; 174 } else if (cmp == 0) {//當前node.key等於parent,直接更新parent的value值 175 temp.setValue(node.getValue()); 176 return; 177 } else {//當前node.key比parent小 178 temp = temp.left; 179 } 180 } 181 node.parent = parent; 182 if (parent != null) { 183 int cmp = node.key.compareTo(parent.key); 184 if (cmp > 0) { 185 parent.right = node;//node插入到右面 186 } else { 187 parent.left = node;//node插入到左面 188 } 189 } else { 190 this.root = node; 191 } 192 193 //插入後會破壞紅黑樹的平衡,需要呼叫修復平衡的方法insertFixup() 194 195 196 } 197 198 199 /** 200 * 插入後修復紅黑樹的方法 201 * |--情景1:紅黑樹為空樹,將根節點染色為黑色 202 * |--情景2:插入節點的key已經存在,不需要處理 203 * |--情景3:插入節點的父節點為黑色,因為所插入的路徑上的黑色節點沒有變化,所以不用處理 204 * |--情景4:插入節點的父節點為紅色,需要我們處理: 205 * |--4.1:叔叔節點存在,並且為紅色(父-叔 雙紅),將爸爸和叔叔染色為黑色,再將爺爺染色為紅色,並且再以 206 * 爺爺為當前節點,進行下一輪的處理 207 * |--4.2:叔叔節點不存在,或者為黑色,父節點為爺爺節點的左子樹 208 * |--4.2.1:插入節點為其父節點的左子節點(LL情況),將爸爸染色為黑色,將爺爺染色為紅色,然後以爺爺節點右旋,就完成了 209 * |--4.2.2:插入節點為其父節點的右子節點(LR情況),以爸爸節點進行一次左旋,得到4.2.1的情況 210 * 然後以爸爸節點為當前節點,進行下一輪操作 211 * |--4.3:叔叔節點不存在,或者為黑色,父節點為爺爺節點的右子樹 212 * |--4.3.1:插入節點為其父節點的右子節點(RR情況),將爸爸染色為黑色,將爺爺染色為紅色,然後以爺爺節點左旋,就完成了 213 * |--4.3.2:插入節點為其父節點的左子節點(Rl情況),以爸爸節點進行一次右旋,得到4.2.1的情況 214 * * 然後以爸爸節點為當前節點,進行下一輪操作 215 */ 216 private void insertFixUp(RBNode node) { 217 218 } 219 220 static class RBNode<K extends Comparable<K>, V> { 221 private RBNode parent; 222 private RBNode left; 223 private RBNode right; 224 private boolean color; 225 private K key; 226 private V value; 227 228 public RBNode() { 229 } 230 231 public RBNode(RBNode parent, RBNode left, RBNode right, boolean color, K key, V value) { 232 this.parent = parent; 233 this.left = left; 234 this.right = right; 235 this.color = color; 236 this.key = key; 237 this.value = value; 238 } 239 240 public RBNode getParent() { 241 return parent; 242 } 243 244 public void setParent(RBNode parent) { 245 this.parent = parent; 246 } 247 248 public RBNode getLeft() { 249 return left; 250 } 251 252 public void setLeft(RBNode left) { 253 this.left = left; 254 } 255 256 public RBNode getRight() { 257 return right; 258 } 259 260 public void setRight(RBNode right) { 261 this.right = right; 262 } 263 264 public boolean isColor() { 265 return color; 266 } 267 268 public void setColor(boolean color) { 269 this.color = color; 270 } 271 272 public K getKey() { 273 return key; 274 } 275 276 public void setKey(K key) { 277 this.key = key; 278 } 279 280 public V getValue() { 281 return value; 282 } 283 284 public void setValue(V value) { 285 this.value = value; 286 } 287 } 288 289 }