JAVA數據結構--AVL樹的實現
阿新 • • 發佈:2017-11-28
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樹的實現