平衡二叉树是在二叉搜索树的基础上增加了结构变换,理解起来费劲不少。
四种转换类型:LL、RR、RL、LR
要理解这四种类型,需要先说明一个概念:
平衡系数:Balance Fate(以下简称BF)
算法是:拿到一个节点,求这个节点左子树与右子树的深度差的绝对值。
对于平衡二叉树有3种情况:0、1、2,其中2就代表失衡状态,需要转换结构。
从BF为2的节点向下追踪2层,朝着深度深的方向追。就出现了4种情况:
高能预警:
LL:BFnode - BFnode.leftchild - BFnode.leftchild.leftchild (左左)
处理方式:交换BFnode和BFnode.leftchild
RR:BFnode - BFnode.rightchild - BFnode.rightchild.rightchild (右右)
处理方式:交换BFnode和BFnode.rightchild
LR:BFnode - BFnode.leftchild - BFnode.leftchild.rightchild (左右)
处理方式:交换BFnode和BFnode.leftchild.rightchild
RL:BFnode - BFnode.rightchild - BFnode.rightchild.leftchild (右左)
处理方式:交换BFnode和BFnode.rightchild.leftchild
添加元素的思路:
将元素添加到对应位置,向上追溯到根节点,判断当前节点的BF,如果等于2就判断类型,并根据类型进行转换。
删除元素的思路:
找到要删除的节点,再找到删除元素左子树的最右节点(可能不是叶子节点),用最右节点替换要删除的节点,并从最右节点的父节点向上追溯到根节点,判断当前节点的BF,如果等于2就判断类型,并根据类型进行转换。
上代码:(并未经过严格测试,参考网上资料,基于个人理解,供学习使用)
1 package collections; 2 3 public class AVLTree { 4 5 private AVLNode root; 6 7 // delete node 8 public void delete(int val) { 9 if (root == null) { 10 return; 11 } 12 AVLNode delNode = get(val); 13 if (delNode == null) { 14 return; 15 } 16 AVLNode replaceNode = findRightLeaf(delNode.leftChild); 17 AVLNode tracebackNode; 18 // delete node self 19 // null means left child is null 20 // contain leaf condition 21 if (replaceNode == null) { 22 AVLNode rightChild = delNode.rightChild; 23 setChild(setParent(rightChild, delNode), delNode, rightChild); 24 tracebackNode = delNode; 25 } else { 26 tracebackNode = replaceDeleteNode(delNode, replaceNode); 27 } 28 // trace back to root 29 tracebackAndConvert(tracebackNode); 30 // clear delete node 31 delNode.parent = null; 32 delNode.leftChild = null; 33 delNode.rightChild = null; 34 } 35 36 // check weather the tree has val 37 public boolean contain(int val) { 38 return get(val) != null; 39 } 40 41 // get node by value 42 public AVLNode get(int val) { 43 if (root == null) { 44 return null; 45 } 46 return get(val, root); 47 } 48 49 // add value 50 public void add(int val) { 51 if (root == null) { 52 root = new AVLNode(val); 53 return; 54 } 55 AVLNode insertNode = new AVLNode(val); 56 AVLNode node = root; 57 while (true) { 58 if (val <= node.val) { 59 if (node.leftChild == null) { 60 insertNode.parent = node; 61 node.leftChild = insertNode; 62 break; 63 } 64 node = node.leftChild; 65 } else { 66 if (node.rightChild == null) { 67 insertNode.parent = node; 68 node.rightChild = insertNode; 69 break; 70 } 71 node = node.rightChild; 72 } 73 } 74 tracebackAndConvert(insertNode); 75 } 76 77 // degree left right print 78 public void showDLR() { 79 iteratorDLR(root); 80 } 81 82 // left degree right print 83 public void showLDR() { 84 iteratorLDR(root); 85 } 86 87 // left right degree print 88 public void showLRD() { 89 iteratorLRD(root); 90 } 91 92 // check empty 93 public boolean isEmpty() { 94 return getDepth(root) == 0; 95 } 96 97 // get tree depth 98 public int depth() { 99 return getDepth(root); 100 } 101 102 // trace back to root and convert structure 103 private void tracebackAndConvert(AVLNode tracebackNode) { 104 while (true) { 105 if (getBF(tracebackNode) == 2) { 106 // convert structure 107 convert(tracebackNode); 108 } 109 if (tracebackNode == root) { 110 break; 111 } 112 tracebackNode = tracebackNode.parent; 113 } 114 } 115 116 // convert structure 117 private void convert(AVLNode convertNode) { 118 StringBuilder sign = new StringBuilder(); 119 AVLNode node = getNodeAndRotateType(convertNode, sign); 120 switch (sign.toString()) { 121 case "ll": 122 rotateLL(convertNode); 123 break; 124 case "rr": 125 rotateRR(convertNode); 126 break; 127 case "lr": 128 rotateLR(node, convertNode); 129 break; 130 case "rl": 131 rotateRL(node, convertNode); 132 break; 133 } 134 } 135 136 // get node and rotate type 137 private AVLNode getNodeAndRotateType(AVLNode node, StringBuilder sign) { 138 for (int i = 0; i < 2; i++) { 139 // means left child lose balance 140 if (getDepth(node.leftChild) > getDepth(node.rightChild)) { 141 sign.append('l'); 142 node = node.leftChild; 143 } 144 // means right child lose balance 145 if (getDepth(node.rightChild) > getDepth(node.leftChild)) { 146 sign.append('r'); 147 node = node.rightChild; 148 } 149 } 150 return node; 151 } 152 153 // replace delete node 154 private AVLNode replaceDeleteNode(AVLNode deleteNode, AVLNode replaceNode) { 155 AVLNode replaceNodeParent = replaceNode.parent; 156 AVLNode replaceNodeLeftChild = replaceNode.leftChild; 157 if (replaceNodeParent.leftChild == replaceNode) { 158 replaceNodeParent.leftChild = replaceNodeLeftChild; 159 } else { 160 replaceNodeParent.rightChild = replaceNodeLeftChild; 161 } 162 if (replaceNodeLeftChild != null) { 163 replaceNodeLeftChild.parent = replaceNodeParent; 164 } 165 AVLNode deleteParent = deleteNode.parent; 166 AVLNode tracebackNode = replaceNode.parent; 167 replaceNode.parent = deleteParent; 168 if (deleteParent.leftChild == deleteNode) { 169 deleteParent.leftChild = replaceNode; 170 } else { 171 deleteParent.rightChild = replaceNode; 172 } 173 // the replace node is the left child of delete node 174 if (deleteNode.leftChild == replaceNode) { 175 replaceNode.leftChild = null; 176 } else { 177 replaceNode.leftChild = deleteNode.leftChild; 178 } 179 replaceNode.rightChild = deleteNode.rightChild; 180 return tracebackNode; 181 } 182 183 // find the right leaf which should replace the removed node 184 private AVLNode findRightLeaf(AVLNode node) { 185 if (node == null) { 186 return null; 187 } 188 if (node.rightChild == null) { 189 return node; 190 } 191 return findRightLeaf(node.rightChild); 192 } 193 194 private AVLNode get(int val, AVLNode node) { 195 if (node == null) { 196 return null; 197 } 198 if (val < node.val) { 199 return get(val, node.leftChild); 200 } else if (val > node.val) { 201 return get(val, node.rightChild); 202 } else { 203 return node; 204 } 205 } 206 207 private void iteratorDLR(AVLNode node) { 208 if (node == null) { 209 return; 210 } 211 System.out.print(node.val + ","); 212 iteratorDLR(node.leftChild); 213 iteratorDLR(node.rightChild); 214 } 215 216 private void iteratorLDR(AVLNode node) { 217 if (node == null) { 218 return; 219 } 220 iteratorLDR(node.leftChild); 221 System.out.print(node.val + ","); 222 iteratorLDR(node.rightChild); 223 } 224 225 private void iteratorLRD(AVLNode node) { 226 if (node == null) { 227 return; 228 } 229 iteratorLRD(node.leftChild); 230 iteratorLRD(node.rightChild); 231 System.out.print(node.val + ","); 232 } 233 234 // ll rotate 235 private void rotateLL(AVLNode convertNode) { 236 AVLNode node = convertNode.leftChild; 237 setChild(setParent(node, convertNode), convertNode, node); 238 convertNode.leftChild = node.rightChild; 239 node.rightChild = convertNode; 240 convertNode.parent = node; 241 } 242 243 // rr rotate 244 private void rotateRR(AVLNode convertNode) { 245 AVLNode node = convertNode.rightChild; 246 setChild(setParent(node, convertNode), convertNode, node); 247 convertNode.rightChild = node.leftChild; 248 node.leftChild = convertNode; 249 convertNode.parent = node; 250 } 251 252 // rl rotate 253 private void rotateRL(AVLNode node, AVLNode convertNode) { 254 setChild(setParent(node, convertNode), convertNode, node); 255 AVLNode rightChild = convertNode.rightChild; 256 rightChild.parent = node; 257 rightChild.leftChild = null; 258 node.leftChild = convertNode; 259 node.rightChild = rightChild; 260 convertNode.parent = node; 261 convertNode.rightChild = null; 262 } 263 264 // lr rotate 265 private void rotateLR(AVLNode node, AVLNode convertNode) { 266 setChild(setParent(node, convertNode), convertNode, node); 267 AVLNode leftChild = convertNode.leftChild; 268 leftChild.parent = node; 269 leftChild.rightChild = null; 270 node.leftChild = leftChild; 271 node.rightChild = convertNode; 272 convertNode.parent = node; 273 convertNode.leftChild = null; 274 } 275 276 private AVLNode setParent(AVLNode node, AVLNode convertNode) { 277 AVLNode parent = convertNode.parent; 278 if (node != null) { 279 node.parent = parent; 280 } 281 return parent; 282 } 283 284 private void setChild(AVLNode parent, AVLNode originChild, AVLNode newChild) { 285 if (parent == null) { 286 root = newChild; 287 return; 288 } 289 if (parent.leftChild == originChild) { 290 parent.leftChild = newChild; 291 } else { 292 parent.rightChild = newChild; 293 } 294 } 295 296 // get balance fate 297 private int getBF(AVLNode node) { 298 if (node == null) { 299 return 0; 300 } 301 return Math.abs(getDepth(node.leftChild) - getDepth(node.rightChild)); 302 } 303 304 // get node depth 305 private int getDepth(AVLNode node) { 306 if (node == null) { 307 return 0; 308 } 309 return 1 + Math.max(getDepth(node.leftChild), getDepth(node.rightChild)); 310 } 311 312 public static void main(String[] args) { 313 AVLTree tree = new AVLTree(); 314 tree.add(25); 315 tree.add(30); 316 tree.add(35); 317 tree.add(45); 318 tree.add(40); 319 tree.add(50); 320 tree.add(47); 321 tree.showDLR(); 322 System.out.println(); 323 tree.delete(47); 324 tree.showDLR(); 325 System.out.println(); 326 tree.add(20); 327 tree.showDLR(); 328 } 329 330 } 331 332 class AVLNode { 333 AVLNode parent; 334 AVLNode leftChild; 335 AVLNode rightChild; 336 int val; 337 338 public AVLNode(AVLNode parent, AVLNode leftChild, AVLNode rightChild, int val) { 339 this.parent = parent; 340 this.leftChild = leftChild; 341 this.rightChild = rightChild; 342 this.val = val; 343 } 344 345 public AVLNode(int val) { 346 this.parent = null; 347 this.leftChild = null; 348 this.rightChild = null; 349 this.val = val; 350 } 351 352 }