数据结构-平衡二叉树

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 }
View Code

 

图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 }
View Code

图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 }
View Code

4,特别鸣谢

https://www.cnblogs.com/qm-article/p/9349681.html

猜你喜欢

转载自www.cnblogs.com/Mufasa/p/11294145.html