前面分別介紹了AVL樹"C語言版本"和"C++版本",本章介紹AVL樹的Java實現版本,它的算法與C語言和C++版本同樣。內容包括:
1. AVL樹的介紹
2. AVL樹的Java實現
3. AVL樹的Java測試程序html
轉載請註明出處:http://www.cnblogs.com/skywang12345/p/3577479.htmljava
更多內容: 數據結構與算法系列 目錄 node
(01) AVL樹(一)之 圖文解析 和 C語言的實現
(02) AVL樹(二)之 C++的實現
(03) AVL樹(三)之 Java的實現算法
AVL樹是高度平衡的而二叉樹。它的特色是:AVL樹中任何節點的兩個子樹的高度最大差異爲1。 數據結構
上面的兩張圖片,左邊的是AVL樹,它的任何節點的兩個子樹的高度差異都<=1;而右邊的不是AVL樹,由於7的兩顆子樹的高度相差爲2(以2爲根節點的樹的高度是3,而以8爲根節點的樹的高度是1)。ide
1. 節點函數
1.1 節點定義post
public class AVLTree<T extends Comparable<T>> { private AVLTreeNode<T> mRoot; // 根結點 // AVL樹的節點(內部類) class AVLTreeNode<T extends Comparable<T>> { T key; // 關鍵字(鍵值) int height; // 高度 AVLTreeNode<T> left; // 左孩子 AVLTreeNode<T> right; // 右孩子 public AVLTreeNode(T key, AVLTreeNode<T> left, AVLTreeNode<T> right) { this.key = key; this.left = left; this.right = right; this.height = 0; } } ...... }
AVLTree是AVL樹對應的類,而AVLTreeNode是AVL樹節點,它是AVLTree的內部類。AVLTree包含了AVL樹的根節點,AVL樹的基本操做也定義在AVL樹中。AVLTreeNode包括的幾個組成對象:
(01) key -- 是關鍵字,是用來對AVL樹的節點進行排序的。
(02) left -- 是左孩子。
(03) right -- 是右孩子。
(04) height -- 是高度。測試
1.2 樹的高度this
/* * 獲取樹的高度 */ private int height(AVLTreeNode<T> tree) { if (tree != null) return tree.height; return 0; } public int height() { return height(mRoot); }
關於高度,有的地方將"空二叉樹的高度是-1",而本文采用維基百科上的定義:樹的高度爲最大層次。即空的二叉樹的高度是0,非空樹的高度等於它的最大層次(根的層次爲1,根的子節點爲第2層,依次類推)。
1.3 比較大小
/* * 比較兩個值的大小 */ private int max(int a, int b) { return a>b ? a : b; }
2. 旋轉
若是在AVL樹中進行插入或刪除節點後,可能致使AVL樹失去平衡。這種失去平衡的能夠歸納爲4種姿態:LL(左左),LR(左右),RR(右右)和RL(右左)。下面給出它們的示意圖:
上圖中的4棵樹都是"失去平衡的AVL樹",從左往右的狀況依次是:LL、LR、RL、RR。除了上面的狀況以外,還有其它的失去平衡的AVL樹,以下圖:
上面的兩張圖都是爲了便於理解,而列舉的關於"失去平衡的AVL樹"的例子。總的來講,AVL樹失去平衡時的狀況必定是LL、LR、RL、RR這4種之一,它們都由各自的定義:
(1) LL:LeftLeft,也稱爲"左左"。插入或刪除一個節點後,根節點的左子樹的左子樹還有非空子節點,致使"根的左子樹的高度"比"根的右子樹的高度"大2,致使AVL樹失去了平衡。
例如,在上面LL狀況中,因爲"根節點(8)的左子樹(4)的左子樹(2)還有非空子節點",而"根節點(8)的右子樹(12)沒有子節點";致使"根節點(8)的左子樹(4)高度"比"根節點(8)的右子樹(12)"高2。
(2) LR:LeftRight,也稱爲"左右"。插入或刪除一個節點後,根節點的左子樹的右子樹還有非空子節點,致使"根的左子樹的高度"比"根的右子樹的高度"大2,致使AVL樹失去了平衡。
例如,在上面LR狀況中,因爲"根節點(8)的左子樹(4)的左子樹(6)還有非空子節點",而"根節點(8)的右子樹(12)沒有子節點";致使"根節點(8)的左子樹(4)高度"比"根節點(8)的右子樹(12)"高2。
(3) RL:RightLeft,稱爲"右左"。插入或刪除一個節點後,根節點的右子樹的左子樹還有非空子節點,致使"根的右子樹的高度"比"根的左子樹的高度"大2,致使AVL樹失去了平衡。
例如,在上面RL狀況中,因爲"根節點(8)的右子樹(12)的左子樹(10)還有非空子節點",而"根節點(8)的左子樹(4)沒有子節點";致使"根節點(8)的右子樹(12)高度"比"根節點(8)的左子樹(4)"高2。
(4) RR:RightRight,稱爲"右右"。插入或刪除一個節點後,根節點的右子樹的右子樹還有非空子節點,致使"根的右子樹的高度"比"根的左子樹的高度"大2,致使AVL樹失去了平衡。
例如,在上面RR狀況中,因爲"根節點(8)的右子樹(12)的右子樹(14)還有非空子節點",而"根節點(8)的左子樹(4)沒有子節點";致使"根節點(8)的右子樹(12)高度"比"根節點(8)的左子樹(4)"高2。
若是在AVL樹中進行插入或刪除節點後,可能致使AVL樹失去平衡。AVL失去平衡以後,能夠經過旋轉使其恢復平衡,下面分別介紹"LL(左左),LR(左右),RR(右右)和RL(右左)"這4種狀況對應的旋轉方法。
2.1 LL的旋轉
LL失去平衡的狀況,能夠經過一次旋轉讓AVL樹恢復平衡。以下圖:
圖中左邊是旋轉以前的樹,右邊是旋轉以後的樹。從中能夠發現,旋轉以後的樹又變成了AVL樹,並且該旋轉只須要一次便可完成。
對於LL旋轉,你能夠這樣理解爲:LL旋轉是圍繞"失去平衡的AVL根節點"進行的,也就是節點k2;並且因爲是LL狀況,即左左狀況,就用手抓着"左孩子,即k1"使勁搖。將k1變成根節點,k2變成k1的右子樹,"k1的右子樹"變成"k2的左子樹"。
LL的旋轉代碼
/* * LL:左左對應的狀況(左單旋轉)。 * * 返回值:旋轉後的根節點 */ private AVLTreeNode<T> leftLeftRotation(AVLTreeNode<T> k2) { AVLTreeNode<T> k1; k1 = k2.left; k2.left = k1.right; k1.right = k2; k2.height = max( height(k2.left), height(k2.right)) + 1; k1.height = max( height(k1.left), k2.height) + 1; return k1; }
2.2 RR的旋轉
理解了LL以後,RR就至關容易理解了。RR是與LL對稱的狀況!RR恢復平衡的旋轉方法以下:
圖中左邊是旋轉以前的樹,右邊是旋轉以後的樹。RR旋轉也只須要一次便可完成。
RR的旋轉代碼
/* * RR:右右對應的狀況(右單旋轉)。 * * 返回值:旋轉後的根節點 */ private AVLTreeNode<T> rightRightRotation(AVLTreeNode<T> k1) { AVLTreeNode<T> k2; k2 = k1.right; k1.right = k2.left; k2.left = k1; k1.height = max( height(k1.left), height(k1.right)) + 1; k2.height = max( height(k2.right), k1.height) + 1; return k2; }
2.3 LR的旋轉
LR失去平衡的狀況,須要通過兩次旋轉才能讓AVL樹恢復平衡。以下圖:
第一次旋轉是圍繞"k1"進行的"RR旋轉",第二次是圍繞"k3"進行的"LL旋轉"。
LR的旋轉代碼
/* * LR:左右對應的狀況(左雙旋轉)。 * * 返回值:旋轉後的根節點 */ private AVLTreeNode<T> leftRightRotation(AVLTreeNode<T> k3) { k3.left = rightRightRotation(k3.left); return leftLeftRotation(k3); }
2.4 RL的旋轉
RL是與LR的對稱狀況!RL恢復平衡的旋轉方法以下:
第一次旋轉是圍繞"k3"進行的"LL旋轉",第二次是圍繞"k1"進行的"RR旋轉"。
RL的旋轉代碼
/* * RL:右左對應的狀況(右雙旋轉)。 * * 返回值:旋轉後的根節點 */ private AVLTreeNode<T> rightLeftRotation(AVLTreeNode<T> k1) { k1.right = leftLeftRotation(k1.right); return rightRightRotation(k1); }
3. 插入
插入節點的代碼
/* * 將結點插入到AVL樹中,並返回根節點 * * 參數說明: * tree AVL樹的根結點 * key 插入的結點的鍵值 * 返回值: * 根節點 */ private AVLTreeNode<T> insert(AVLTreeNode<T> tree, T key) { if (tree == null) { // 新建節點 tree = new AVLTreeNode<T>(key, null, null); if (tree==null) { System.out.println("ERROR: create avltree node failed!"); return null; } } else { int cmp = key.compareTo(tree.key); if (cmp < 0) { // 應該將key插入到"tree的左子樹"的狀況 tree.left = insert(tree.left, key); // 插入節點後,若AVL樹失去平衡,則進行相應的調節。 if (height(tree.left) - height(tree.right) == 2) { if (key.compareTo(tree.left.key) < 0) tree = leftLeftRotation(tree); else tree = leftRightRotation(tree); } } else if (cmp > 0) { // 應該將key插入到"tree的右子樹"的狀況 tree.right = insert(tree.right, key); // 插入節點後,若AVL樹失去平衡,則進行相應的調節。 if (height(tree.right) - height(tree.left) == 2) { if (key.compareTo(tree.right.key) > 0) tree = rightRightRotation(tree); else tree = rightLeftRotation(tree); } } else { // cmp==0 System.out.println("添加失敗:不容許添加相同的節點!"); } } tree.height = max( height(tree.left), height(tree.right)) + 1; return tree; } public void insert(T key) { mRoot = insert(mRoot, key); }
4. 刪除
刪除節點的代碼
/* * 刪除結點(z),返回根節點 * * 參數說明: * tree AVL樹的根結點 * z 待刪除的結點 * 返回值: * 根節點 */ private AVLTreeNode<T> remove(AVLTreeNode<T> tree, AVLTreeNode<T> z) { // 根爲空 或者 沒有要刪除的節點,直接返回null。 if (tree==null || z==null) return null; int cmp = z.key.compareTo(tree.key); if (cmp < 0) { // 待刪除的節點在"tree的左子樹"中 tree.left = remove(tree.left, z); // 刪除節點後,若AVL樹失去平衡,則進行相應的調節。 if (height(tree.right) - height(tree.left) == 2) { AVLTreeNode<T> r = tree.right; if (height(r.left) > height(r.right)) tree = rightLeftRotation(tree); else tree = rightRightRotation(tree); } } else if (cmp > 0) { // 待刪除的節點在"tree的右子樹"中 tree.right = remove(tree.right, z); // 刪除節點後,若AVL樹失去平衡,則進行相應的調節。 if (height(tree.left) - height(tree.right) == 2) { AVLTreeNode<T> l = tree.left; if (height(l.right) > height(l.left)) tree = leftRightRotation(tree); else tree = leftLeftRotation(tree); } } else { // tree是對應要刪除的節點。 // tree的左右孩子都非空 if ((tree.left!=null) && (tree.right!=null)) { if (height(tree.left) > height(tree.right)) { // 若是tree的左子樹比右子樹高; // 則(01)找出tree的左子樹中的最大節點 // (02)將該最大節點的值賦值給tree。 // (03)刪除該最大節點。 // 這相似於用"tree的左子樹中最大節點"作"tree"的替身; // 採用這種方式的好處是:刪除"tree的左子樹中最大節點"以後,AVL樹仍然是平衡的。 AVLTreeNode<T> max = maximum(tree.left); tree.key = max.key; tree.left = remove(tree.left, max); } else { // 若是tree的左子樹不比右子樹高(即它們相等,或右子樹比左子樹高1) // 則(01)找出tree的右子樹中的最小節點 // (02)將該最小節點的值賦值給tree。 // (03)刪除該最小節點。 // 這相似於用"tree的右子樹中最小節點"作"tree"的替身; // 採用這種方式的好處是:刪除"tree的右子樹中最小節點"以後,AVL樹仍然是平衡的。 AVLTreeNode<T> min = maximum(tree.right); tree.key = min.key; tree.right = remove(tree.right, min); } } else { AVLTreeNode<T> tmp = tree; tree = (tree.left!=null) ? tree.left : tree.right; tmp = null; } } return tree; } public void remove(T key) { AVLTreeNode<T> z; if ((z = search(mRoot, key)) != null) mRoot = remove(mRoot, z); }
完整的實現代碼
AVL樹的實現文件(AVRTree.java)
1 /** 2 * Java 語言: AVL樹 3 * 4 * @author skywang 5 * @date 2013/11/07 6 */ 7 8 public class AVLTree<T extends Comparable<T>> { 9 private AVLTreeNode<T> mRoot; // 根結點 10 11 // AVL樹的節點(內部類) 12 class AVLTreeNode<T extends Comparable<T>> { 13 T key; // 關鍵字(鍵值) 14 int height; // 高度 15 AVLTreeNode<T> left; // 左孩子 16 AVLTreeNode<T> right; // 右孩子 17 18 public AVLTreeNode(T key, AVLTreeNode<T> left, AVLTreeNode<T> right) { 19 this.key = key; 20 this.left = left; 21 this.right = right; 22 this.height = 0; 23 } 24 } 25 26 // 構造函數 27 public AVLTree() { 28 mRoot = null; 29 } 30 31 /* 32 * 獲取樹的高度 33 */ 34 private int height(AVLTreeNode<T> tree) { 35 if (tree != null) 36 return tree.height; 37 38 return 0; 39 } 40 41 public int height() { 42 return height(mRoot); 43 } 44 45 /* 46 * 比較兩個值的大小 47 */ 48 private int max(int a, int b) { 49 return a>b ? a : b; 50 } 51 52 /* 53 * 前序遍歷"AVL樹" 54 */ 55 private void preOrder(AVLTreeNode<T> tree) { 56 if(tree != null) { 57 System.out.print(tree.key+" "); 58 preOrder(tree.left); 59 preOrder(tree.right); 60 } 61 } 62 63 public void preOrder() { 64 preOrder(mRoot); 65 } 66 67 /* 68 * 中序遍歷"AVL樹" 69 */ 70 private void inOrder(AVLTreeNode<T> tree) { 71 if(tree != null) 72 { 73 inOrder(tree.left); 74 System.out.print(tree.key+" "); 75 inOrder(tree.right); 76 } 77 } 78 79 public void inOrder() { 80 inOrder(mRoot); 81 } 82 83 /* 84 * 後序遍歷"AVL樹" 85 */ 86 private void postOrder(AVLTreeNode<T> tree) { 87 if(tree != null) { 88 postOrder(tree.left); 89 postOrder(tree.right); 90 System.out.print(tree.key+" "); 91 } 92 } 93 94 public void postOrder() { 95 postOrder(mRoot); 96 } 97 98 /* 99 * (遞歸實現)查找"AVL樹x"中鍵值爲key的節點 100 */ 101 private AVLTreeNode<T> search(AVLTreeNode<T> x, T key) { 102 if (x==null) 103 return x; 104 105 int cmp = key.compareTo(x.key); 106 if (cmp < 0) 107 return search(x.left, key); 108 else if (cmp > 0) 109 return search(x.right, key); 110 else 111 return x; 112 } 113 114 public AVLTreeNode<T> search(T key) { 115 return search(mRoot, key); 116 } 117 118 /* 119 * (非遞歸實現)查找"AVL樹x"中鍵值爲key的節點 120 */ 121 private AVLTreeNode<T> iterativeSearch(AVLTreeNode<T> x, T key) { 122 while (x!=null) { 123 int cmp = key.compareTo(x.key); 124 125 if (cmp < 0) 126 x = x.left; 127 else if (cmp > 0) 128 x = x.right; 129 else 130 return x; 131 } 132 133 return x; 134 } 135 136 public AVLTreeNode<T> iterativeSearch(T key) { 137 return iterativeSearch(mRoot, key); 138 } 139 140 /* 141 * 查找最小結點:返回tree爲根結點的AVL樹的最小結點。 142 */ 143 private AVLTreeNode<T> minimum(AVLTreeNode<T> tree) { 144 if (tree == null) 145 return null; 146 147 while(tree.left != null) 148 tree = tree.left; 149 return tree; 150 } 151 152 public T minimum() { 153 AVLTreeNode<T> p = minimum(mRoot); 154 if (p != null) 155 return p.key; 156 157 return null; 158 } 159 160 /* 161 * 查找最大結點:返回tree爲根結點的AVL樹的最大結點。 162 */ 163 private AVLTreeNode<T> maximum(AVLTreeNode<T> tree) { 164 if (tree == null) 165 return null; 166 167 while(tree.right != null) 168 tree = tree.right; 169 return tree; 170 } 171 172 public T maximum() { 173 AVLTreeNode<T> p = maximum(mRoot); 174 if (p != null) 175 return p.key; 176 177 return null; 178 } 179 180 /* 181 * LL:左左對應的狀況(左單旋轉)。 182 * 183 * 返回值:旋轉後的根節點 184 */ 185 private AVLTreeNode<T> leftLeftRotation(AVLTreeNode<T> k2) { 186 AVLTreeNode<T> k1; 187 188 k1 = k2.left; 189 k2.left = k1.right; 190 k1.right = k2; 191 192 k2.height = max( height(k2.left), height(k2.right)) + 1; 193 k1.height = max( height(k1.left), k2.height) + 1; 194 195 return k1; 196 } 197 198 /* 199 * RR:右右對應的狀況(右單旋轉)。 200 * 201 * 返回值:旋轉後的根節點 202 */ 203 private AVLTreeNode<T> rightRightRotation(AVLTreeNode<T> k1) { 204 AVLTreeNode<T> k2; 205 206 k2 = k1.right; 207 k1.right = k2.left; 208 k2.left = k1; 209 210 k1.height = max( height(k1.left), height(k1.right)) + 1; 211 k2.height = max( height(k2.right), k1.height) + 1; 212 213 return k2; 214 } 215 216 /* 217 * LR:左右對應的狀況(左雙旋轉)。 218 * 219 * 返回值:旋轉後的根節點 220 */ 221 private AVLTreeNode<T> leftRightRotation(AVLTreeNode<T> k3) { 222 k3.left = rightRightRotation(k3.left); 223 224 return leftLeftRotation(k3); 225 } 226 227 /* 228 * RL:右左對應的狀況(右雙旋轉)。 229 * 230 * 返回值:旋轉後的根節點 231 */ 232 private AVLTreeNode<T> rightLeftRotation(AVLTreeNode<T> k1) { 233 k1.right = leftLeftRotation(k1.right); 234 235 return rightRightRotation(k1); 236 } 237 238 /* 239 * 將結點插入到AVL樹中,並返回根節點 240 * 241 * 參數說明: 242 * tree AVL樹的根結點 243 * key 插入的結點的鍵值 244 * 返回值: 245 * 根節點 246 */ 247 private AVLTreeNode<T> insert(AVLTreeNode<T> tree, T key) { 248 if (tree == null) { 249 // 新建節點 250 tree = new AVLTreeNode<T>(key, null, null); 251 if (tree==null) { 252 System.out.println("ERROR: create avltree node failed!"); 253 return null; 254 } 255 } else { 256 int cmp = key.compareTo(tree.key); 257 258 if (cmp < 0) { // 應該將key插入到"tree的左子樹"的狀況 259 tree.left = insert(tree.left, key); 260 // 插入節點後,若AVL樹失去平衡,則進行相應的調節。 261 if (height(tree.left) - height(tree.right) == 2) { 262 if (key.compareTo(tree.left.key) < 0) 263 tree = leftLeftRotation(tree); 264 else 265 tree = leftRightRotation(tree); 266 } 267 } else if (cmp > 0) { // 應該將key插入到"tree的右子樹"的狀況 268 tree.right = insert(tree.right, key); 269 // 插入節點後,若AVL樹失去平衡,則進行相應的調節。 270 if (height(tree.right) - height(tree.left) == 2) { 271 if (key.compareTo(tree.right.key) > 0) 272 tree = rightRightRotation(tree); 273 else 274 tree = rightLeftRotation(tree); 275 } 276 } else { // cmp==0 277 System.out.println("添加失敗:不容許添加相同的節點!"); 278 } 279 } 280 281 tree.height = max( height(tree.left), height(tree.right)) + 1; 282 283 return tree; 284 } 285 286 public void insert(T key) { 287 mRoot = insert(mRoot, key); 288 } 289 290 /* 291 * 刪除結點(z),返回根節點 292 * 293 * 參數說明: 294 * tree AVL樹的根結點 295 * z 待刪除的結點 296 * 返回值: 297 * 根節點 298 */ 299 private AVLTreeNode<T> remove(AVLTreeNode<T> tree, AVLTreeNode<T> z) { 300 // 根爲空 或者 沒有要刪除的節點,直接返回null。 301 if (tree==null || z==null) 302 return null; 303 304 int cmp = z.key.compareTo(tree.key); 305 if (cmp < 0) { // 待刪除的節點在"tree的左子樹"中 306 tree.left = remove(tree.left, z); 307 // 刪除節點後,若AVL樹失去平衡,則進行相應的調節。 308 if (height(tree.right) - height(tree.left) == 2) { 309 AVLTreeNode<T> r = tree.right; 310 if (height(r.left) > height(r.right)) 311 tree = rightLeftRotation(tree); 312 else 313 tree = rightRightRotation(tree); 314 } 315 } else if (cmp > 0) { // 待刪除的節點在"tree的右子樹"中 316 tree.right = remove(tree.right, z); 317 // 刪除節點後,若AVL樹失去平衡,則進行相應的調節。 318 if (height(tree.left) - height(tree.right) == 2) { 319 AVLTreeNode<T> l = tree.left; 320 if (height(l.right) > height(l.left)) 321 tree = leftRightRotation(tree); 322 else 323 tree = leftLeftRotation(tree); 324 } 325 } else { // tree是對應要刪除的節點。 326 // tree的左右孩子都非空 327 if ((tree.left!=null) && (tree.right!=null)) { 328 if (height(tree.left) > height(tree.right)) { 329 // 若是tree的左子樹比右子樹高; 330 // 則(01)找出tree的左子樹中的最大節點 331 // (02)將該最大節點的值賦值給tree。 332 // (03)刪除該最大節點。 333 // 這相似於用"tree的左子樹中最大節點"作"tree"的替身; 334 // 採用這種方式的好處是:刪除"tree的左子樹中最大節點"以後,AVL樹仍然是平衡的。 335 AVLTreeNode<T> max = maximum(tree.left); 336 tree.key = max.key; 337 tree.left = remove(tree.left, max); 338 } else { 339 // 若是tree的左子樹不比右子樹高(即它們相等,或右子樹比左子樹高1) 340 // 則(01)找出tree的右子樹中的最小節點 341 // (02)將該最小節點的值賦值給tree。 342 // (03)刪除該最小節點。 343 // 這相似於用"tree的右子樹中最小節點"作"tree"的替身; 344 // 採用這種方式的好處是:刪除"tree的右子樹中最小節點"以後,AVL樹仍然是平衡的。 345 AVLTreeNode<T> min = maximum(tree.right); 346 tree.key = min.key; 347 tree.right = remove(tree.right, min); 348 } 349 } else { 350 AVLTreeNode<T> tmp = tree; 351 tree = (tree.left!=null) ? tree.left : tree.right; 352 tmp = null; 353 } 354 } 355 356 return tree; 357 } 358 359 public void remove(T key) { 360 AVLTreeNode<T> z; 361 362 if ((z = search(mRoot, key)) != null) 363 mRoot = remove(mRoot, z); 364 } 365 366 /* 367 * 銷燬AVL樹 368 */ 369 private void destroy(AVLTreeNode<T> tree) { 370 if (tree==null) 371 return ; 372 373 if (tree.left != null) 374 destroy(tree.left); 375 if (tree.right != null) 376 destroy(tree.right); 377 378 tree = null; 379 } 380 381 public void destroy() { 382 destroy(mRoot); 383 } 384 385 /* 386 * 打印"二叉查找樹" 387 * 388 * key -- 節點的鍵值 389 * direction -- 0,表示該節點是根節點; 390 * -1,表示該節點是它的父結點的左孩子; 391 * 1,表示該節點是它的父結點的右孩子。 392 */ 393 private void print(AVLTreeNode<T> tree, T key, int direction) { 394 if(tree != null) { 395 if(direction==0) // tree是根節點 396 System.out.printf("%2d is root\n", tree.key, key); 397 else // tree是分支節點 398 System.out.printf("%2d is %2d's %6s child\n", tree.key, key, direction==1?"right" : "left"); 399 400 print(tree.left, tree.key, -1); 401 print(tree.right,tree.key, 1); 402 } 403 } 404 405 public void print() { 406 if (mRoot != null) 407 print(mRoot, mRoot.key, 0); 408 } 409 }
AVL樹的測試程序(AVLTreeTest.java)
1 /** 2 * Java 語言: AVL樹 3 * 4 * @author skywang 5 * @date 2013/11/07 6 */ 7 8 public class AVLTreeTest { 9 private static int arr[]= {3,2,1,4,5,6,7,16,15,14,13,12,11,10,8,9}; 10 11 public static void main(String[] args) { 12 int i; 13 AVLTree<Integer> tree = new AVLTree<Integer>(); 14 15 System.out.printf("== 依次添加: "); 16 for(i=0; i<arr.length; i++) { 17 System.out.printf("%d ", arr[i]); 18 tree.insert(arr[i]); 19 } 20 21 System.out.printf("\n== 前序遍歷: "); 22 tree.preOrder(); 23 24 System.out.printf("\n== 中序遍歷: "); 25 tree.inOrder(); 26 27 System.out.printf("\n== 後序遍歷: "); 28 tree.postOrder(); 29 System.out.printf("\n"); 30 31 System.out.printf("== 高度: %d\n", tree.height()); 32 System.out.printf("== 最小值: %d\n", tree.minimum()); 33 System.out.printf("== 最大值: %d\n", tree.maximum()); 34 System.out.printf("== 樹的詳細信息: \n"); 35 tree.print(); 36 37 i = 8; 38 System.out.printf("\n== 刪除根節點: %d", i); 39 tree.remove(i); 40 41 System.out.printf("\n== 高度: %d", tree.height()); 42 System.out.printf("\n== 中序遍歷: "); 43 tree.inOrder(); 44 System.out.printf("\n== 樹的詳細信息: \n"); 45 tree.print(); 46 47 // 銷燬二叉樹 48 tree.destroy(); 49 } 50 }
AVL樹的測試程序運行結果以下:
== 依次添加: 3 2 1 4 5 6 7 16 15 14 13 12 11 10 8 9 == 前序遍歷: 7 4 2 1 3 6 5 13 11 9 8 10 12 15 14 16 == 中序遍歷: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 == 後序遍歷: 1 3 2 5 6 4 8 10 9 12 11 14 16 15 13 7 == 高度: 5 == 最小值: 1 == 最大值: 16 == 樹的詳細信息: 7 is root 4 is 7's left child 2 is 4's left child 1 is 2's left child 3 is 2's right child 6 is 4's right child 5 is 6's left child 13 is 7's right child 11 is 13's left child 9 is 11's left child 8 is 9's left child 10 is 9's right child 12 is 11's right child 15 is 13's right child 14 is 15's left child 16 is 15's right child == 刪除根節點: 8 == 高度: 5 == 中序遍歷: 1 2 3 4 5 6 7 9 10 11 12 13 14 15 16 == 樹的詳細信息: 7 is root 4 is 7's left child 2 is 4's left child 1 is 2's left child 3 is 2's right child 6 is 4's right child 5 is 6's left child 13 is 7's right child 11 is 13's left child 9 is 11's left child 10 is 9's right child 12 is 11's right child 15 is 13's right child 14 is 15's left child 16 is 15's right child
下面,咱們對測試程序的流程進行分析!
1. 新建AVL樹
2. 依次添加"3,2,1,4,5,6,7,16,15,14,13,12,11,10,8,9" 到AVL樹中。
2.01 添加3,2
添加3,2都不會破壞AVL樹的平衡性。
2.02 添加1
添加1以後,AVL樹失去平衡(LL),此時須要對AVL樹進行旋轉(LL旋轉)。旋轉過程以下:
2.03 添加4
添加4不會破壞AVL樹的平衡性。
2.04 添加5
添加5以後,AVL樹失去平衡(RR),此時須要對AVL樹進行旋轉(RR旋轉)。旋轉過程以下:
2.05 添加6
添加6以後,AVL樹失去平衡(RR),此時須要對AVL樹進行旋轉(RR旋轉)。旋轉過程以下:
2.06 添加7
添加7以後,AVL樹失去平衡(RR),此時須要對AVL樹進行旋轉(RR旋轉)。旋轉過程以下:
2.07 添加16
添加16不會破壞AVL樹的平衡性。
2.08 添加15
添加15以後,AVL樹失去平衡(RR),此時須要對AVL樹進行旋轉(RR旋轉)。旋轉過程以下:
2.09 添加14
添加14以後,AVL樹失去平衡(RL),此時須要對AVL樹進行旋轉(RL旋轉)。旋轉過程以下:
2.10 添加13
添加13以後,AVL樹失去平衡(RR),此時須要對AVL樹進行旋轉(RR旋轉)。旋轉過程以下:
2.11 添加12
添加12以後,AVL樹失去平衡(LL),此時須要對AVL樹進行旋轉(LL旋轉)。旋轉過程以下:
2.12 添加11
添加11以後,AVL樹失去平衡(LL),此時須要對AVL樹進行旋轉(LL旋轉)。旋轉過程以下:
2.13 添加10
添加10以後,AVL樹失去平衡(LL),此時須要對AVL樹進行旋轉(LL旋轉)。旋轉過程以下:
2.14 添加8
添加8不會破壞AVL樹的平衡性。
2.15 添加9
可是添加9以後,AVL樹失去平衡(LR),此時須要對AVL樹進行旋轉(LR旋轉)。旋轉過程以下:
3. 打印樹的信息
輸出下面樹的信息:
前序遍歷: 7 4 2 1 3 6 5 13 11 9 8 10 12 15 14 16
中序遍歷: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
後序遍歷: 1 3 2 5 6 4 8 10 9 12 11 14 16 15 13 7
高度: 5
最小值: 1
最大值: 16
4. 刪除節點8
刪除操做並不會形成AVL樹的不平衡。
刪除節點8以後,再打印該AVL樹的信息。
高度: 5
中序遍歷: 1 2 3 4 5 6 7 9 10 11 12 13 14 15 16