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