平衡二叉樹算法分析


1、平衡二叉樹定義: 

平衡二叉樹(Balanced Binary Tree或Height-Balanced Tree)又稱AVL樹。它或者是一顆空樹,或者是具有下列性質的二叉樹:它的左子樹和右子樹都是平衡二叉樹,且左子樹和右子樹的深度之差的絕對值不超過1。若將二叉樹上結點的平衡因子bf(balance factor)定義為該結點的左子樹的深度減去右子樹的深度,則平衡二叉樹上所有結點的平衡因子只可能為-1、0和1這三個值。

 

2、失去平衡情況分析:

假設結點A是一顆子平衡二叉樹,當在以A為根結點的AVL樹上插入一個新結點時,會出現以下三種情況:

1)如果插入前A—>bf=1(A的左子樹深度比右子樹深度多1),如果插入在A的左子樹上且A的左子樹深度增加了1,則此時A—>bf=2需要對樹進行調整,如圖2.1結點C為新插入的結點,C可以插入到B的左子樹上(如圖2.1(b))或者右子樹上(如圖2.1(c))。

2)如果插入前A—>bf=0(A的左子樹和右子樹深度相等),如果插入在A的左子樹上且A的左子樹深度增加了1,則此時只需要改變A的平衡因子為1即可不需要對樹進行調整。如果插入在A的右子樹上且A的右子樹深度增加了1,則此時只需要改變A的平衡因子為-1即可不需要進行調整。

3)如果插入前A—>bf=-1(A的左子樹深度比右子樹深度少1),如果插入在A的右子樹上且A的右子樹深度增加了1,則此時A—>bf=-2需要對樹進行調整,如圖2.2結點C為新插入的結點,C可以插入在B的左子樹上(如圖2.2(b))或者右子樹上(如圖2.2(c))。

                            

                     圖2.1                                                   圖2.2

            注意:上圖中為了清楚的看到添加結點后失去平衡時的情況,省去了一些子結點,這些結點在下面的分析中會完整畫出來

 

當出現圖2.1(b)中的情況時只需要進行一次右旋轉操作,旋轉后得到如圖2.1(d)所示的平衡二叉樹。

當出現圖2.1(c)中的情況時需要先對A的左子樹B進行左旋操作,然后再進行右旋操作,旋轉后得到如圖2.1(e)所示的平衡二叉樹。

當出現圖2.2(b)中的情況時只需要進行一次右旋轉操作,旋轉后得到如圖2.1(d)所示的平衡二叉樹。

當出現圖2.2(c)中的情況時需要先對A的右子樹B進行右旋,然后再進行左旋操作,旋轉后得到如圖2.2(e)所示的平衡二叉樹。

 

3.求旋轉后各結點的平衡因子:

旋轉后怎么確定各結點的新的平衡因子是平衡二叉樹算法的關鍵點,我們需要按情況來一一推理。

一、當出現圖2.1(b)(c)這兩種情況時,需進行左平衡處理:

1)當新結點插入到B的左子樹上時B—>bf=1,由此可知:deep(C)=deep(E)+1,deep(B)=deep(C)+1;由於插入新結點前A—>bf=1,deep(B)=deep(D)+1則插入新節點后deep(B)=deep(D)+2;圖3.1.1為調整前的二叉樹,圖3.1.2為對A樹進行右旋轉后的AVL樹:

                                              

                圖3.1.1                                                                                                         圖3.1.2

對比圖3.1.1和3.1.2可知旋轉后的新樹中A的左子樹發生了變化,B的右子樹發生了變化,其他結點都沒變;因此只需要重新算出A的平衡因子和B的平衡因子即可證明調整后的樹是否為AVL樹。

由上面的等式deep(B)=deep(D)+2,deep(B)=deep(C)+1,deep(C)=deep(E)+1

可以推出deep(E)=deep(C)-1=deep(B)-1-1=deep(D)+2-1-1=deep(D)可得出A—>bf=0

由調整后deep(E)=deep(D)可推出調整后deep(A)=deep(E)+1=deep(C)-1+1=deep(C)可得出B—>bf=0;

2)當新結點插入到B的右子樹上時B—>bf=-1,由此可知:deep(C)=deep(E)-1,deep(B)=deep(E)+1;由於插入新結點前A—>bf=1,deep(B)=deep(D)+1則插入新節點后deep(B)=deep(D)+2圖3.2.1為調整前的二叉樹,圖3.2.2為先對B樹進行左旋然后對A樹進行右旋后的AVL樹:

                                                      

                  圖3.2.1                                                                                                                                 圖3.2.2

對比圖3.2.1和3.2.2可知調整后的新樹中A的左子樹發生了變化,B的右子樹發生了變化,E的左右子樹都發生了變化,其他結點都沒變,因此只需要重新算出A的平衡因子、B的平衡因子以及E的平衡因子即可證明調整后的樹是否為AVL樹。

此時由於調整后的B和A結點的平衡因子與E的左右子樹EL和ER有關,因此需要根據E的平衡因子的不同來進行分析:

由上面的分析可得到deep(B)=deep(D)+2,deep(B)=deep(E)+1,deep(C)=deep(E)-1

1、當E—>bf=1時:deep(E)=deep(EL)+1,deep(ER)=deep(EL)-1

deep(C)=deep(E)-1=deep(EL)+1-1=deep(EL)可得B—>bf=0

deep(D)=deep(B)-2=deep(E)+1-2=deep(ER)+1+1+1-2=deep(ER)+1可得A—>bf=-1

由於deep(EL)=deep(ER)+1所以E—>bf=0

2、當E—>bf=0時:deep(E)=deep(EL)+1,deep(ER)=deep(EL)

deep(C)=deep(E)-1=deep(EL)+1-1=deep(EL)可得B—>bf=0

deep(D)=deep(B)-2=deep(E)+1-2=deep(ER)+1+1-2=deep(ER)可得A—>bf=0

由於B—>bf=0,A—>bf=0所以E—>bf=0

3、當E—>bf=-1時:deep(E)=deep(ER)+1,deep(ER)=deep(EL)+1

deep(C)=deep(E)-1=deep(EL)+1+1-1=deep(EL)+1可得B—>bf=1

deep(D)=deep(B)-2=deep(E)+1-2=deep(ER)+1+1-2=deep(ER)可得A—>bf=0

由於deep(EL)=deep(ER)-1所以E—>bf=0

二、當出現圖2.2(b)(c)這兩種情況時,需進行右平衡處理:

1)當新結點插入到C的左子樹上時C—>bf=1,由此可知:deep(C)=deep(E)+1,deep(D)=deep(E)-1;由於插入新結點前A—>bf=-1,deep(B)=deep(C)-1則插入新節點后deep(B)=deep(C)-2圖3.3.1為調整前的二叉樹,圖3.3.2為先對C樹進行右旋然后對A樹進行左旋后的AVL樹:

                                                    

                  圖3.3.1                                                                                                           圖3.3.2 

對比圖3.3.1和3.3.2可知調整后的新樹中A的右子樹發生了變化,C的左子樹發生了變化,E的左右子樹都發生了變化,其他結點都沒變,因此只需要重新算出A的平衡因子、B的平衡因子以及E的平衡因子即可證明調整后的樹是否為AVL樹。

此時由於調整后的A和C結點的平衡因子與E的左右子樹EL和ER有關,因此需要根據E的平衡因子的不同來進行分析:

由上面的分析可得到deep(B)=deep(C)-2,deep(C)=deep(E)+1,deep(D)=deep(E)-1

1、當E—>bf=1時:deep(E)=deep(EL)+1,deep(ER)=deep(EL)-1

deep(B)=deep(C)-2=deep(EL)+1+1-2=deep(EL)可得A—>bf=0

deep(D)=deep(E)-1=deep(ER)+1+1-1=deep(ER)+1可得C—>bf=-1

由於deep(EL)=deep(ER)+1所以E—>bf=0

2、當E—>bf=0時:deep(E)=deep(EL)+1,deep(ER)=deep(EL)

deep(B)=deep(E)+1-2=deep(EL)+1+1-2=deep(EL)可得A—>bf=0

deep(D)=deep(E)-1=deep(ER)+1-1=deep(ER)可得C—>bf=0

由於A—>bf=0,C—>bf=0所以E—>bf=0

3、當E—>bf=-1時:deep(E)=deep(ER)+1,deep(ER)=deep(EL)+1

deep(B)=deep(C)-2=deep(E)+1-2=deep(EL)+1+1+1-2=deep(EL)+1可得A—>bf=1

deep(D)=deep(E)-1=deep(ER)+1-1=deep(ER)可得C—>bf=0

由於deep(EL)=deep(ER)-1所以E—>bf=0

 

2)當新結點插入到C的右子樹上時C—>bf=-1,由此可知:deep(C)=deep(D)+1,deep(D)=deep(E)+1;由於插入新結點前A—>bf=-1,deep(B)=deep(C)-1則插入新節點后deep(B)=deep(C)-2圖3.4.1為調整前的二叉樹,圖3.4.2為進行左旋后的AVL樹:

                                                   

                           圖3.4.1                                                      圖3.4.2

對比圖3.4.1和3.4.2可知調整后的新樹中A的右子樹發生了變化,C的左子樹發生了變化,其他結點都沒變,因此只需要重新算出A的平衡因子和C的平衡因子即可證明調整后的樹是否為AVL樹。

由上面的等式deep(B)=deep(C)-2,deep(C)=deep(D)+1,deep(D)=deep(E)+1

可以推出deep(B)=deep(C)-2=deep(D)+1-2=deep(E)+1+1-2=deep(E)可得出A—>bf=0

由A—>bf=0調整后deep(A)=deep(E)+1=deep(D)-1+1=deep(D)可得出C—>bf=0;

4.Java實現代碼:

 1 package org.algorithms.tree;  2 
 3 import java.util.concurrent.ConcurrentLinkedQueue;  4 
 5 
 6 public class BalanceBiTree<T> {  7 
 8     private Node root;  9     
 10     private int size;  11     
 12     public void insert(T t){  13         if(root==null){  14             root = new Node();  15             root.bf = 0;  16             root.data = t;  17             size++;  18             return;  19  }  20  addNode(root,t);  21  }  22     
 23     private boolean addNode(Node nd,T t){  24         boolean taller = false;  25         Comparable<T> cp = (Comparable<T>)nd.data;  26         int i = cp.compareTo(t);  27         if(i==0){  28             return false;  29         }else if(i>0){  30             if(nd.lChild==null){  31                 Node child = new Node();  32                 child.bf = 0;  33                 child.data = t;  34                 child.parent = nd;  35                 nd.lChild = child;  36                 size++;  37                 if(nd.bf==0){  38                     nd.bf = 1;  39                     return true;  40  }  41                 nd.bf = 0;  42             }else{  43                 taller = addNode(nd.lChild, t);  44                 if(taller){  45                     if(nd.bf==1){  46  leftBalance(nd);  47                         taller = false;  48                     }else if(nd.bf==0){  49                         nd.bf = 1;  50                         taller = true;  51                     }else{  52                         nd.bf = 0;  53                         taller = false;  54  }  55  }  56  }  57         }else{  58             if(nd.rChild==null){  59                 Node child = new Node();  60                 child.bf = 0;  61                 child.data = t;  62                 child.parent = nd;  63                 nd.rChild = child;  64                 size++;  65                 if(nd.bf==0){  66                     nd.bf = -1;  67                     return true;  68  }  69                 nd.bf = 0;  70             }else{  71                 taller = addNode(nd.rChild, t);  72                 if(taller){  73                     if(nd.bf==1){  74                         nd.bf = 0;  75                         taller = false;  76                     }else if(nd.bf==0){  77                         nd.bf = -1;  78                         taller = true;  79                     }else{  80  rightBalance(nd);  81                         taller = false;  82  }  83  }  84  }  85  }  86         return taller;  87  }  88     
 89     public int getSize(){  90         return size;  91  }  92     
 93     private void leftBalance(Node nd){  94         Node leftChild = nd.lChild;  95         if(leftChild.bf==1){  96             nd.bf = 0;  97             leftChild.bf = 0;  98  rightRotate(nd);  99         }else if(leftChild.bf==-1){ 100             Node rd = leftChild.rChild; 101             switch (rd.bf) { 102             case 1: 103                 leftChild.bf=0;nd.bf = -1; 104                 break; 105             case 0: 106                 leftChild.bf=0;nd.bf = 0; 107                 break; 108             case -1: 109                 leftChild.bf = 1;nd.bf = 0; 110                 break; 111  } 112             rd.bf = 0 ; 113  leftRotate(leftChild); 114  rightRotate(nd); 115  } 116  } 117     
118     private void rightBalance(Node nd){ 119         Node rightChild = nd.rChild; 120         if(rightChild.bf==1){ 121             Node ld = rightChild.lChild; 122             switch (ld.bf) { 123             case 1: 124                 rightChild.bf= -1; nd.bf = 0; 125                 break; 126             case 0: 127                 rightChild.bf=0;nd.bf = 0; 128                 break; 129             case -1: 130                 rightChild.bf = 0;nd.bf = 1; 131                 break; 132  } 133             ld.bf = 0 ; 134  rightRotate(rightChild); 135  leftRotate(nd); 136         }else if(rightChild.bf==-1){ 137             nd.bf = 0; 138             rightChild.bf = 0; 139  leftRotate(nd); 140  } 141         
142  } 143     
144     private void leftRotate(Node nd){ 145         Node top = nd.rChild; 146         nd.rChild = top.lChild; 147         if(top.lChild!=null) 148             top.lChild.parent = nd; 149         top.lChild = nd; 150         top.parent = nd.parent; 151         if(nd.parent!=null){ 152             if(nd.parent.lChild == nd) 153                 nd.parent.lChild = top; 154             else
155                 nd.parent.rChild = top; 156         }else{ 157             root = top; 158  } 159         nd.parent = top; 160  } 161     
162     private void rightRotate(Node nd){ 163         Node top = nd.lChild; 164         nd.lChild = top.rChild; 165         if(top.rChild!=null) 166             top.rChild.parent = nd; 167         top.rChild = nd; 168         top.parent = nd.parent; 169         if(nd.parent!=null){ 170             if(nd.parent.lChild == nd) 171                 nd.parent.lChild = top; 172             else
173                 nd.parent.rChild = top; 174         }else{ 175             root = top; 176  } 177         nd.parent = top; 178  } 179     
180     public void printTree(){ 181         ConcurrentLinkedQueue<Node> queue = new ConcurrentLinkedQueue<Node>(); 182         ConcurrentLinkedQueue<Node> tempQueue = new ConcurrentLinkedQueue<Node>(); 183  queue.add(root); 184         int offset= 0; 185         int counter=2; 186         for(int i=0;i<50;i++) 187             System.out.print(" "); 188         while(queue.peek()!=null){ 189             Node node = queue.poll(); 190             String side = "L"; 191             if(node.parent!=null&&node.parent.rChild==node) 192                 side = "R"; 193             System.out.print(node.data+"("+(node.parent==null?"":node.parent.data)+" "+side+")"); 194             if(node.parent!=null&&node.parent.rChild!=node) 195                 for(int i=0;i<counter;i++) 196                     System.out.print(" "); 197             if(node.lChild!=null) 198  tempQueue.add(node.lChild); 199             if(node.rChild!=null) 200  tempQueue.add(node.rChild); 201             if(queue.isEmpty()){ 202                 offset += 3; 203                 //counter--;
204  copyQueue(tempQueue,queue); 205  System.out.println(); 206                 for(int i=0;i<50-offset;i++) 207                     System.out.print(" "); 208  } 209  } 210         
211  } 212     
213     private void copyQueue(ConcurrentLinkedQueue<Node> source, 214             ConcurrentLinkedQueue<Node> target){ 215         while(source.peek()!=null){ 216  target.add(source.poll()); 217  } 218  } 219     
220     private class Node{ 221         
222         public T data; 223         
224         public Node lChild; 225         
226         public Node rChild; 227         
228         public Node parent; 229         
230         public int bf; 231  } 232 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM