AVL樹----java,avl----java
AVL樹----java
AVL樹是高度平衡的二叉尋找樹
1.單旋轉LL旋轉
理解記憶:1.在不平衡的節點的左孩子的左孩子插入導致的不平衡,所以叫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.單旋轉RR
理解記憶:1.不平衡節點的右孩子的有孩子插入導致的不平衡,所以叫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;}
3.雙旋轉LR
理解記憶:1.不平衡節點的左孩子的有孩子導致的不平衡,所以叫LR
2.需要先對k1 RR,再對根K3 LL
private AVLTreeNode<T> leftRightRotation(AVLTreeNode<T> k3) { k3.left = rightRightRotation(k3.left); return leftLeftRotation(k3);}
4.雙旋轉RL
理解記憶:1.不平衡節點的右孩子的左孩子導致的不平衡,所以叫RL
2.需要先對k3 LL,在對k1 RR
private AVLTreeNode<T> rightLeftRotation(AVLTreeNode<T> k1) { k1.right = leftLeftRotation(k1.right); return rightRightRotation(k1);}
5.AVL的例子
遍曆,尋找等和二叉尋找樹一樣就不在列出,主要是 插入 和 刪除
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; } } // 建構函式 public AVLTree() { mRoot = null; } /* * 擷取樹的高度 */ private int height(AVLTreeNode<T> tree) { if (tree != null) return tree.height; return 0; } public int height() { return height(mRoot); } /* * 比較兩個值的大小 */ private int max(int a, int b) { return a>b ? a : b; } /* * 前序走訪"AVL樹" */ private void preOrder(AVLTreeNode<T> tree) { if(tree != null) { System.out.print(tree.key+" "); preOrder(tree.left); preOrder(tree.right); } } public void preOrder() { preOrder(mRoot); } /* * 中序遍曆"AVL樹" */ private void inOrder(AVLTreeNode<T> tree) { if(tree != null) { inOrder(tree.left); System.out.print(tree.key+" "); inOrder(tree.right); } } public void inOrder() { inOrder(mRoot); } /* * 後序遍曆"AVL樹" */ private void postOrder(AVLTreeNode<T> tree) { if(tree != null) { postOrder(tree.left); postOrder(tree.right); System.out.print(tree.key+" "); } } public void postOrder() { postOrder(mRoot); } /* * (遞迴實現)尋找"AVL樹x"中索引值為key的節點 */ private AVLTreeNode<T> search(AVLTreeNode<T> x, T key) { if (x==null) return x; int cmp = key.compareTo(x.key); if (cmp < 0) return search(x.left, key); else if (cmp > 0) return search(x.right, key); else return x; } public AVLTreeNode<T> search(T key) { return search(mRoot, key); } /* * (非遞迴實現)尋找"AVL樹x"中索引值為key的節點 */ private AVLTreeNode<T> iterativeSearch(AVLTreeNode<T> x, T key) { while (x!=null) { int cmp = key.compareTo(x.key); if (cmp < 0) x = x.left; else if (cmp > 0) x = x.right; else return x; } return x; } public AVLTreeNode<T> iterativeSearch(T key) { return iterativeSearch(mRoot, key); } /* * 尋找最小結點:返回tree為根結點的AVL樹的最小結點。 */ private AVLTreeNode<T> minimum(AVLTreeNode<T> tree) { if (tree == null) return null; while(tree.left != null) tree = tree.left; return tree; } public T minimum() { AVLTreeNode<T> p = minimum(mRoot); if (p != null) return p.key; return null; } /* * 尋找最大結點:返回tree為根結點的AVL樹的最大結點。 */ private AVLTreeNode<T> maximum(AVLTreeNode<T> tree) { if (tree == null) return null; while(tree.right != null) tree = tree.right; return tree; } public T maximum() { AVLTreeNode<T> p = maximum(mRoot); if (p != null) return p.key; return null; } /* * 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; } /* * 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; } /* * LR:左右對應的情況(左雙旋轉)。 * * 傳回值:旋轉後的根節點 */ private AVLTreeNode<T> leftRightRotation(AVLTreeNode<T> k3) { k3.left = rightRightRotation(k3.left); return leftLeftRotation(k3); } /* * RL:右左對應的情況(右雙旋轉)。 * * 傳回值:旋轉後的根節點 */ private AVLTreeNode<T> rightLeftRotation(AVLTreeNode<T> k1) { k1.right = leftLeftRotation(k1.right); return rightRightRotation(k1); } /* * 將結點插入到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); } /* * 刪除結點(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樹 */ private void destroy(AVLTreeNode<T> tree) { if (tree==null) return ; if (tree.left != null) destroy(tree.left); if (tree.right != null) destroy(tree.right); tree = null; } public void destroy() { destroy(mRoot); } /* * 列印"二叉尋找樹" * * key -- 節點的索引值 * direction -- 0,表示該節點是根節點; * -1,表示該節點是它的父結點的左孩子; * 1,表示該節點是它的父結點的右孩子。 */ private void print(AVLTreeNode<T> tree, T key, int direction) { if(tree != null) { if(direction==0) // tree是根節點 System.out.printf("%2d is root\n", tree.key, key); else // tree是分支節點 System.out.printf("%2d is %2d's %6s child\n", tree.key, key, direction==1?"right" : "left"); print(tree.left, tree.key, -1); print(tree.right,tree.key, 1); } } public void print() { if (mRoot != null) print(mRoot, mRoot.key, 0); }}
文章大量參考:http://www.cnblogs.com/skywang12345/p/3577479.html
AVL樹所有的java遞迴演算法
www.doc88.com/p-292361550358.html
我有JAVA基礎可以參加海同科技的Java培訓
選擇匯才同飛教育JAVA快車培訓的理由:
一、實在:java培訓小班授課每班最多25人,每人一台專用電腦,每周學習六天。
二、實用:java培訓專職老師專業、敬業,具備三年以上一線開發經驗,java培訓課程的每個階段都會安排相關JAVA培訓項目練習,java培訓學習過程中積累實踐工作經驗。
三、實惠:java培訓收費相當優惠,報JAVA班贈安卓培訓課程。以JAVA就業工資水平為口碑,是性價比最高的JAVA培訓機構。