1. 程式人生 > >JAVA數據結構--AVL樹的實現

JAVA數據結構--AVL樹的實現

oid 非遞歸 max https -a ext 二叉 line 英語

AVL樹的定義

在計算機科學中,AVL樹是最先發明的自平衡二叉查找樹。在AVL樹中任何節點的兩個子樹的高度最大差別為1,所以它也被稱為高度平衡樹。查找、插入和刪除在平均和最壞情況下的時間復雜度都是技術分享圖片。增加和刪除可能需要通過一次或多次樹旋轉來重新平衡這個樹。AVL樹得名於它的發明者G. M. Adelson-Velsky和E. M. Landis,他們在1962年的論文《An algorithm for the organization of information》中發表了它。

節點的平衡因子是它的左子樹的高度減去它的右子樹的高度(有時相反)。帶有平衡因子1、0或 -1的節點被認為是平衡的。帶有平衡因子 -2或2的節點被認為是不平衡的,並需要重新平衡這個樹。平衡因子可以直接存儲在每個節點中,或從可能存儲在節點中的子樹高度計算出來。

技術分享圖片

  上圖是摘自維基百科的AVL樹實現的圖例,比較清晰的解釋了AVL調整平衡的過程。ABCD代表當前節點有子樹。

  我以我個人理解以左右情況為例

  技術分享圖片該例是左右情況,需要將其調整為左左或者右右才能繼續調整。因為節點5是在右,所以3節點(虛線方框內)調整為左為最佳。左旋轉即可使樹變為左左形狀。

AVL樹節點定義

 1 private static class AvlNode<T>{
 2         public AvlNode(T theElement) {
 3             this(theElement, null, null);
 4
} 5 public AvlNode(T theElement,AvlNode<T> lt,AvlNode<T> rt) { 6 element=theElement; 7 left=lt; 8 right=rt; 9 height=0; 10 } 11 T element; 12 AvlNode<T> left; 13 AvlNode<T> right;
14 int height; 15 }

與二叉查找樹的定義類似,不過加入了節點的深度height定義。

AVL節點計算方法

1 private int height(AvlNode<T> t) {
2         return t==null?-1:t.height;
3 }

當banlance()或者旋轉時height都會改變

節點旋轉

 1 /*
 2      * 實現單旋轉
 3      * */
 4     private AvlNode<T> rotateWithLeftChild(AvlNode<T> k2){//單左旋轉
 5         AvlNode<T> k1=k2.left;
 6         k2.left=k1.right;
 7         k1.right=k2;
 8         k2.height=Math.max(height(k2.left), height(k2.right))+1;
 9         k1.height=Math.max(height(k1.left), k2.height)+1;
10         return k1;
11     }
12     private AvlNode<T> rotateWithRightChild(AvlNode<T> k1){//單右旋轉
13         AvlNode<T> k2=k1.right;
14         k1.right=k2.left;
15         k2.left=k1;
16         k2.height=Math.max(height(k1.left), height(k1.right))+1;
17         k1.height=Math.max(height(k2.right), k1.height)+1;
18         return k2;
19     }
20     /*
21      * 實現雙旋轉
22      * 
23      * */
24     private AvlNode<T> doubleWithLeftChild(AvlNode<T> k3){//先右旋轉再左旋轉
25         k3.left=rotateWithRightChild(k3.left);
26         return rotateWithLeftChild(k3);
27     }
28      private AvlNode<T> doubleWithRightChild( AvlNode<T> k1 ){//先左旋轉再右旋轉
29          k1.right = rotateWithLeftChild( k1.right );
30          return rotateWithRightChild( k1 );
31     }

balance()方法的實現

 1 private AvlNode<T> balance(AvlNode<T> t){
 2         if(t==null)
 3             return t;
 4         if(height(t.left)-height(t.right)>ALLOWED_IMBALANCE) {//左子樹高度過高
 5             if(height(t.left.left)>=height(t.left.right))//判斷進行單旋轉還是雙旋轉
 6                 t=rotateWithLeftChild(t);
 7             else
 8                 t=doubleWithLeftChild(t);
 9         }
10         else if (height(t.right)-height(t.left)>ALLOWED_IMBALANCE) {//右子樹高度過高
11             if(height(t.right.right)>=height(t.right.left))
12                 
13                 
14                 
15                 t=rotateWithRightChild(t);
16             else
17                 t=doubleWithRightChild(t);
18         }
19         t.height=Math.max(height(t.left), height(t.right))+1;
20         return t;
21     }

刪除節點方法

 1 private AvlNode<T> remove(T x,AvlNode<T> t){
 2          if(t==null)
 3              return t;
 4          int compareResult=x.compareTo(t.element);
 5          if(compareResult<0)
 6              t.left=remove(x, t.left);//遞歸查找刪除
 7          else if (compareResult>0) {
 8             t.right=remove(x, t.right);
 9         }
10          else if (t.left!=null&&t.right!=null) {//要刪除的節點兩個孩子節點的情況
11              t.element=findMin(t.right).element;//從右子樹中找出最小的節點替換當前要刪除的節點
12              t.right=remove(t.element, t.right);//刪除右子樹中需要拿出替換的節點
13         }
14          else {
15             t=(t.left!=null)?t.left:t.right;//單個子節點的情況
16         }
17          return balance(t);
18      }

完整代碼如下(不含遍歷),github地址

技術分享圖片
  1 package Tree;
  2 public class AvlTree <T extends Comparable<? super T>>{
  3     private static class AvlNode<T>{
  4         public AvlNode(T theElement) {
  5             this(theElement, null, null);
  6         }
  7         public AvlNode(T theElement,AvlNode<T> lt,AvlNode<T> rt) {
  8             element=theElement;
  9             left=lt;
 10             right=rt;
 11             height=0;
 12         }
 13         T element;
 14         AvlNode<T> left;
 15         AvlNode<T> right;
 16         int height;
 17     }
 18     private AvlNode<T> root;//定義根節點
 19     public AvlTree() {
 20         root=null;
 21     }
 22     public int height() {
 23         return height(root);
 24     }
 25     public void insert(T x) {
 26         insert(x, root);
 27     }
 28     public void remove(T x) {
 29         root=remove(x,root);
 30     }
 31     private int height(AvlNode<T> t) {
 32         return t==null?-1:t.height;
 33     }
 34     private AvlNode<T> insert(T x,AvlNode<T> t){
 35         if(t==null)
 36             return new AvlNode<T>(x, null, null);
 37         int compareResult=x.compareTo(t.element);
 38         if(compareResult<0) {
 39             t.left=insert(x, t.left);
 40         }
 41         else if(compareResult>0){
 42             t.right=insert(x, t.right);
 43         }
 44         else {
 45             
 46         }
 47         return balance(t);
 48         
 49     }
 50     private AvlNode<T> balance(AvlNode<T> t){
 51         if(t==null)
 52             return t;
 53         if(height(t.left)-height(t.right)>ALLOWED_IMBALANCE) {//左子樹高度過高
 54             if(height(t.left.left)>=height(t.left.right))//判斷進行單旋轉還是雙旋轉
 55                 t=rotateWithLeftChild(t);
 56             else
 57                 t=doubleWithLeftChild(t);
 58         }
 59         else if (height(t.right)-height(t.left)>ALLOWED_IMBALANCE) {//右子樹高度過高
 60             if(height(t.right.right)>=height(t.right.left))
 61                 
 62                 
 63                 
 64                 t=rotateWithRightChild(t);
 65             else
 66                 t=doubleWithRightChild(t);
 67         }
 68         t.height=Math.max(height(t.left), height(t.right))+1;
 69         return t;
 70     }
 71     /*
 72      * 實現單旋轉
 73      * */
 74     private AvlNode<T> rotateWithLeftChild(AvlNode<T> k2){//單左旋轉
 75         AvlNode<T> k1=k2.left;
 76         k2.left=k1.right;
 77         k1.right=k2;
 78         k2.height=Math.max(height(k2.left), height(k2.right))+1;
 79         k1.height=Math.max(height(k1.left), k2.height)+1;
 80         return k1;
 81     }
 82     private AvlNode<T> rotateWithRightChild(AvlNode<T> k1){//單右旋轉
 83         AvlNode<T> k2=k1.right;
 84         k1.right=k2.left;
 85         k2.left=k1;
 86         k2.height=Math.max(height(k1.left), height(k1.right))+1;
 87         k1.height=Math.max(height(k2.right), k1.height)+1;
 88         return k2;
 89     }
 90     /*
 91      * 實現雙旋轉
 92      * 
 93      * */
 94     private AvlNode<T> doubleWithLeftChild(AvlNode<T> k3){//先右旋轉再左旋轉
 95         k3.left=rotateWithRightChild(k3.left);
 96         return rotateWithLeftChild(k3);
 97     }
 98      private AvlNode<T> doubleWithRightChild( AvlNode<T> k1 ){//先左旋轉再右旋轉
 99          k1.right = rotateWithLeftChild( k1.right );
100          return rotateWithRightChild( k1 );
101     }
102      private AvlNode<T> remove(T x,AvlNode<T> t){
103          if(t==null)
104              return t;
105          int compareResult=x.compareTo(t.element);
106          if(compareResult<0)
107              t.left=remove(x, t.left);//遞歸查找刪除
108          else if (compareResult>0) {
109             t.right=remove(x, t.right);
110         }
111          else if (t.left!=null&&t.right!=null) {//要刪除的節點兩個孩子節點的情況
112              t.element=findMin(t.right).element;//從右子樹中找出最小的節點替換當前要刪除的節點
113              t.right=remove(t.element, t.right);//刪除右子樹中需要拿出替換的節點
114         }
115          else {
116             t=(t.left!=null)?t.left:t.right;//單個子節點的情況
117         }
118          return balance(t);
119      }
120      private AvlNode<T> findMin(AvlNode<T> t){
121             //非遞歸寫法
122             if(t!=null)
123                 while(t.left!=null)
124                     t=t.left;
125             return t;
126             //遞歸寫法
127             /*if(t==null)
128                 return null;
129             else if (t.left==null) {
130                 return t;
131             }
132             return findMin(t.left);*/
133         }
134     private static final int ALLOWED_IMBALANCE=1;
135     
136 }
View Code

JAVA數據結構--AVL樹的實現