數據結構-平衡二叉樹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 }
View Code

 

 

圖1 Node.java結構圖html

 

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結構圖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,特別鳴謝

http://www.javashuo.com/article/p-hzujqugu-a.htmlnode

相關文章
相關標籤/搜索