数据结构-平衡二叉树Java实现
1,Node.java
1 package com.cnblogs.mufasa.BalanceBinaryTree; 2 3 public class Node { 4 Node parent; 5 Node leftChild; 6 Node rightChild; 7 int val; 8 public Node(Node parent, Node leftChild, Node rightChild,int val) { 9 super(); 10 this.parent = parent; 11 this.leftChild = leftChild; 12 this.rightChild = rightChild; 13 this.val = val; 14 } 15 16 public Node(int val){ 17 this(null,null,null,val); 18 } 19 20 public Node(Node node,int val){ 21 this(node,null,null,val); 22 } 23 }
图1 Node.java结构图
2,BalanceBinaryTree.java
1 package com.cnblogs.mufasa.BalanceBinaryTree; 2 3 import java.util.LinkedList; 4 import java.util.Queue; 5 6 public class BalanceBinaryTree { 7 private final static int LEFT=0; 8 private final static int RIGHT=1; 9 private Node root; 10 private int size; 11 public BalanceBinaryTree(){ 12 super(); 13 } 14 15 //LL型非平衡树,右旋转 16 public Node rightRotation(Node node){ 17 System.out.println(node.val+"右旋"); 18 if(node != null){ 19 Node leftChild = node.leftChild;// 用变量存储node节点的左子节点 20 node.leftChild = leftChild.rightChild;// 将leftChild节点的右子节点赋值给node节点的左节点 21 if(leftChild.rightChild != null){// 如果leftChild的右节点存在,则需将该右节点的父节点指给node节点 22 leftChild.rightChild.parent = node; 23 } 24 leftChild.parent = node.parent; 25 if(node.parent == null){// 即表明node节点为根节点 26 this.root = leftChild; 27 }else if(node.parent.rightChild == node){// 即node节点在它原父节点的右子树中 28 node.parent.rightChild = leftChild; 29 }else if(node.parent.leftChild == node){ 30 node.parent.leftChild = leftChild; 31 } 32 leftChild.rightChild = node; 33 node.parent = leftChild; 34 return leftChild; 35 } 36 return null; 37 } 38 39 //RR型非平衡树,左旋 40 public Node leftRotation(Node node){ 41 System.out.println(node.val+"左旋"); 42 if(node != null){ 43 Node rightChild = node.rightChild; 44 node.rightChild = rightChild.leftChild; 45 if(rightChild.leftChild != null){ 46 rightChild.leftChild.parent = node; 47 } 48 rightChild.parent = node.parent; 49 if(node.parent == null){ 50 this.root = rightChild; 51 }else if(node.parent.rightChild == node){ 52 node.parent.rightChild = rightChild; 53 }else if(node.parent.leftChild == node){ 54 node.parent.leftChild = rightChild; 55 } 56 rightChild.leftChild = node; 57 node.parent = rightChild; 58 59 } 60 return null; 61 } 62 63 //添加新元素 64 public boolean put(int val){ 65 return putVal(root,val); 66 } 67 private boolean putVal(Node node,int val){ 68 if(node == null){// 初始化根节点 69 node = new Node(val); 70 root = node; 71 size++; 72 return true; 73 } 74 Node temp = node; 75 Node p; 76 int t; 77 /** 78 * 通过do while循环迭代获取最佳节点, 79 */ 80 do{ 81 p = temp; 82 t = temp.val-val; 83 if(t > 0){ 84 temp = temp.leftChild; 85 }else if(t < 0){ 86 temp = temp.rightChild; 87 }else{ 88 temp.val = val;//插入数值有相同数据,不符合要求 89 return false; 90 } 91 }while(temp != null); 92 93 Node newNode = new Node(p, val); 94 if(t > 0){ 95 p.leftChild = newNode; 96 }else if(t < 0){ 97 p.rightChild = newNode; 98 } 99 rebuild(p);// 使二叉树平衡的方法,优化平衡 100 size++; 101 return true; 102 } 103 104 //平衡二叉树优化节点 105 private void rebuild(Node p){ 106 while(p != null){ 107 if(calcNodeBalanceValue(p) == 2){// 说明左子树高,需要右旋或者 先左旋后右旋 108 fixAfterInsertion(p,LEFT);// 调整操作 109 }else if(calcNodeBalanceValue(p) == -2){// 说明右子树高 110 fixAfterInsertion(p,RIGHT); 111 } 112 p = p.parent; 113 } 114 } 115 116 //计算二叉树平衡因子① 117 private int calcNodeBalanceValue(Node node){ 118 if(node != null){ 119 return getHeightByNode(node); 120 } 121 return 0; 122 } 123 124 //计算二叉树平衡因子② 125 public int getHeightByNode(Node node){ 126 if(node == null){//多余 127 return 0; 128 } 129 return getChildDepth(node.leftChild)-getChildDepth(node.rightChild); 130 } 131 132 // 计算node节点的高度,递归调用 133 public int getChildDepth(Node node){ 134 if(node == null){ 135 return 0; 136 } 137 return 1+Math.max(getChildDepth(node.leftChild),getChildDepth(node.rightChild)); 138 } 139 140 /** 141 * 调整树结构,先后顺序需要换一下,先判断LR型和RL型进行二次旋转 142 * @param p 143 * @param type 144 */ 145 private void fixAfterInsertion(Node p, int type) { 146 if(type == 0){//需要右旋或者 先左旋后右旋 147 final Node leftChild = p.leftChild; 148 if(leftChild.rightChild != null){// 先左旋后右旋 149 leftRotation(leftChild); 150 rightRotation(p); 151 }else if(leftChild.leftChild != null){//右旋 152 rightRotation(p); 153 } 154 155 }else{ 156 final Node rightChild = p.rightChild; 157 if(rightChild.leftChild != null){// 先右旋,后左旋 158 rightRotation(p); 159 leftRotation(rightChild); 160 }else if(rightChild.rightChild != null){// 左旋 161 leftRotation(p); 162 } 163 } 164 } 165 166 //删除元素 167 public boolean delete(int val){ 168 Node node = getNode(val);//搜索这个节点的数值 169 if(node == null){ 170 return false; 171 } 172 boolean flag = false; 173 Node p = null; 174 Node parent = node.parent; 175 Node leftChild = node.leftChild; 176 Node rightChild = node.rightChild; 177 //以下所有父节点为空的情况,则表明删除的节点是根节点 178 if(leftChild == null && rightChild == null){//没有子节点 179 if(parent != null){ 180 if(parent.leftChild == node){ 181 parent.leftChild = null; 182 }else if(parent.rightChild == node){ 183 parent.rightChild = null; 184 } 185 }else{//不存在父节点,则表明删除节点为根节点 186 root = null; 187 } 188 p = parent; 189 node = null; 190 flag = true; 191 }else if(leftChild == null && rightChild != null){// 只有右节点 192 if(parent != null && parent.val > val){// 存在父节点,且node位置为父节点的左边 193 parent.leftChild = rightChild; 194 }else if(parent != null && parent.val < val){// 存在父节点,且node位置为父节点的右边 195 parent.rightChild = rightChild; 196 }else{ 197 root = rightChild; 198 } 199 p = parent; 200 node = null; 201 flag = true; 202 }else if(leftChild != null && rightChild == null){// 只有左节点 203 if(parent != null && parent.val > val){// 存在父节点,且node位置为父节点的左边 204 parent.leftChild = leftChild; 205 }else if(parent != null && parent.val < val){// 存在父节点,且node位置为父节点的右边 206 parent.rightChild = leftChild; 207 }else{ 208 root = leftChild; 209 } 210 p = parent; 211 flag = true; 212 }else if(leftChild != null && rightChild != null){// 两个子节点都存在 213 Node successor = getSuccessor(node);// 这种情况,一定存在后继节点 214 int temp = successor.val; 215 boolean delete = delete(temp); 216 if(delete){ 217 node.val = temp; 218 } 219 p = successor; 220 successor = null; 221 flag = true; 222 } 223 if(flag){ 224 rebuild(p); 225 } 226 return flag; 227 } 228 229 /** 230 * 搜索节点 231 * @param val 232 * @return 233 */ 234 public Node getNode(int val){ 235 Node temp = root; 236 int t; 237 do{//直接使用循环遍历的方法 238 t = temp.val-val; 239 if(t > 0){ 240 temp = temp.leftChild; 241 }else if(t < 0){ 242 temp = temp.rightChild; 243 }else{ 244 return temp; 245 } 246 }while(temp != null); 247 return null; 248 } 249 250 //获取后继节点 251 private Node getSuccessor(Node node){ 252 if(node.rightChild != null){ 253 Node rightChild = node.rightChild; 254 while(rightChild.leftChild != null){ 255 rightChild = rightChild.leftChild; 256 } 257 return rightChild; 258 } 259 Node parent = node.parent; 260 while(parent != null && (node == parent.rightChild)){ 261 node = parent; 262 parent = parent.parent; 263 } 264 return parent; 265 } 266 267 /** 268 * 平衡二叉树节点遍历 269 * @param type 0前序,1中序,2后续,3层序 270 */ 271 public void print(int type){ 272 if(type==0){//前序 273 printPre(root); 274 }else if(type==1){ 275 printMid(root); 276 }else if(type==2){ 277 printEnd(root); 278 }else if(type==3){ 279 printLevel(root); 280 } 281 } 282 283 //前序遍历 284 private void printPre(Node root){ 285 if(root != null){ 286 System.out.println(root.val);// 位置在中间,则中序,若在前面,则为先序,否则为后续 287 printPre(root.leftChild); 288 printPre(root.rightChild); 289 } 290 } 291 292 //中序遍历 293 private void printMid(Node root){ 294 if(root != null){ 295 printMid(root.leftChild); 296 System.out.println(root.val);// 位置在中间,则中序,若在前面,则为先序,否则为后续 297 printMid(root.rightChild); 298 } 299 } 300 301 //后序遍历 302 private void printEnd(Node root){ 303 if(root != null){ 304 printEnd(root.leftChild); 305 printEnd(root.rightChild); 306 System.out.println(root.val);// 位置在中间,则中序,若在前面,则为先序,否则为后续 307 } 308 } 309 310 //层次遍历 311 private void printLevel(Node root){ 312 if(root == null){ 313 return; 314 } 315 Queue<Node> queue = new LinkedList<>(); 316 Node temp = null; 317 queue.add(root); 318 while(!queue.isEmpty()){ 319 temp = queue.poll(); 320 System.out.print("节点值:"+temp.val+",平衡值:"+calcNodeBalanceValue(temp)+"\n"); 321 if(temp.leftChild != null){ 322 queue.add(temp.leftChild); 323 } 324 if(temp.rightChild != null){ 325 queue.add(temp.rightChild); 326 } 327 } 328 } 329 }
图2,BalanceBinaryTree.java结构图
3,JavaDemo.java
1 package com.cnblogs.mufasa.BalanceBinaryTree; 2 3 public class JavaDemo { 4 public static void main(String[] args) { 5 BalanceBinaryTree bbt=new BalanceBinaryTree(); 6 // bbt.put(10); 7 // bbt.put(9); 8 // bbt.put(11); 9 // bbt.put(7); 10 // bbt.put(12); 11 // bbt.put(8); 12 // bbt.put(38); 13 // bbt.put(24); 14 // bbt.put(17); 15 // bbt.put(4); 16 // bbt.put(3); 17 18 bbt.put(11); 19 bbt.put(7); 20 bbt.put(15); 21 bbt.put(4); 22 bbt.put(9); 23 bbt.put(10); 24 bbt.print(3); 25 } 26 }
4,特别鸣谢
探究未知是最大乐趣