package com.learn.tree.demo2;

/**
* AVL树又叫做平衡二叉树。 AVL树的前提是二叉树(BST或叫做二叉搜索树)
* 由于在生成BST树的过程中可能会出现线性树结构。比如插入的顺序是:1,2,3,4,5,6n
* 二叉搜索树就会退化为链表(线性机构),此时所搜的时间复杂度是O(n)。我们知道理想情况下即每个左子树和右子树的高度相等, 搜索时间复杂度log(N).
*
* 现在我们要做的事就是让BST在创建的过程中不要向线性发展。方法就是让其在添加新节点的时候,不断调整树的平衡 状态.
* 定义:它是一颗空树或它的左右两个树的高度差的绝对值不超过1,并且左右两个子树都是一颗平衡二叉树
*
*/
public class AVLTree<T extends Comparable<T>> {

private Node<T> root;// 根节点

public AVLTree() {
root = null;
}

/**
* 获取树的高度
*
* @param tree
* @return
*/
private int height(Node<T> tree) {
if (tree != null)
return tree.height;
return 0;
}

public int height() {
return height(root);
}

/**
* 获取较大值
*
* @param a
* @param b
* @return
*/
private int max(int a, int b) {
return a > b ? a : b;
}

/**
* 获得较小值
*
* @param a
* @param b
* @return
*/
private T min(T a, T b) {
return a.compareTo(b) < 0 ? a : b;
}

/**
* 前序遍历
*/
public void preOrder() {
preOrder(root);
}

private void preOrder(Node<T> node) {
if (node != null) {
System.out.print(node.key + " ");
preOrder(node.left);
preOrder(node.right);
}
}

/**
* 中序遍历二叉搜索树 得到从小到大序列
*/
public void inOrder() {
inOrder(root);
}

private void inOrder(Node<T> node) {
if (node != null) {
inOrder(node.left);
System.out.print(node.key + " ");
inOrder(node.right);
}
}

/**
* 后序遍历
*/
public void postOrder() {
postOrder(root);
}

private void postOrder(Node<T> node) {
if (node != null) {
postOrder(node.left);
postOrder(node.right);
System.out.print(node.key + " ");
}
}

/**
* 根据键查找节点
*
* @param key
* @return
*/
public Node<T> search(T key) {
return search(root, key);
}

private Node<T> search(Node<T> node, T key) {
if (node == null)
return node;
if (key.compareTo(node.key) > 0)
return search(node.right, key);
else if (key.compareTo(node.key) < 0)
return search(node.left, key);
else
return node;
}

/**
* 迭代法实现查找节点依据key
*
* @param key
* @return
*/
public Node<T> iteratvieSearch(T key) {
return iterativeSearch(root, key);
}

private Node<T> iterativeSearch(Node<T> node, T key) {
while (node != null) {
if (key.compareTo(node.key) > 0)
node = node.left;
else if (key.compareTo(node.key) < 0)
node = node.right;
else
return node;
}
return node;
}

/**
* 获取avl树中最小的节点
*
* @return
*/
public T minimum() {
Node<T> node = mininum(root);
if (node != null)
return node.key;
return null;
}

private Node<T> mininum(Node<T> node) {
if (node == null)
return null;
while (node.left != null)
node = node.left;
return node;
}

/**
* 获取avl树中最大值
*
* @return
*/
public T maxinum() {
Node<T> node = maxinum(root);
if (node != null)
return node.key;
return null;
}

private Node<T> maxinum(Node<T> node) {
if (node == null)
return null;
while (node.right != null)
node = node.right;
return node;
}

/**
* LL:左左对应的情况(左单旋转) LL:LeftLeft,也称为"左左"。插入或删除一个节点后,根节点的左子树的左子树还有非空子节点,
* 导致"根的左子树的高度"比"根的右子树的高度"大2,导致AVL树失去了平衡 返回值:旋转后的根节点
*
* @param k2
* @return
*/
private Node<T> leftLeftRotation(Node<T> k2) {
Node<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:RightRight,称为"右右"。插入或删除一个节点后,根节点的右子树的右子树还有非空子节点,
* 导致"根的右子树的高度"比"根的左子树的高度"大2,导致AVL树失去了平衡。
*
* @return
*/

private Node<T> rightRightRotation(Node<T> k2) {
Node<T> k1;
k1 = k2.right;
k2.right = k1.left;
k1.left = k2;
k1.height = max(height(k1.left), height(k1.right)) + 1;
k2.height = max(height(k2.right), k1.height) + 1;
return k1;
}

/**
*
* LR:LeftRight,也称为"左右"。插入或删除一个节点后,根节点的左子树的右子树还有非空子节点
* ,导致"根的左子树的高度"比"根的右子树的高度"大2,导致AVL树失去了平衡。
*
* @param k
* @return
*/
private Node<T> leftRightRotation(Node<T> k) {
k.left = rightRightRotation(k.left);
return leftLeftRotation(k);
}

/**
* RL:RightLeft,称为"右左"。插入或删除一个节点后,根节点的右子树的左子树还有非空子节点,
* 导致"根的右子树的高度"比"根的左子树的高度"大2,导致AVL树失去了平衡。
*
* @param <T>
*/

private Node<T> rightLeftRotation(Node<T> k) {
k.right = leftLeftRotation(k.right);
return rightRightRotation(k);
}

public void insert(T key) {
root = insert(root, key);
}

/**
* 将节点插入到avl树中,并返回根节点
*
* @param tree
* @param key
* @return
*/

private Node<T> insert(Node<T> tree, T key) {
if (tree == null) {
// 新建节点
tree = new Node<T>(key, null, null);
} else {
int cmp = key.compareTo(tree.key);
if (cmp < 0) {
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);
if (height(tree.right) - height(tree.left) == 0) {
if (key.compareTo(tree.right.key) > 0)
tree = rightRightRotation(tree);
else
tree = rightLeftRotation(tree);
}
} else {
// cmp=0
throw new RuntimeException("添加失败:不允许添加相同的节点!");
}

}
tree.height = max(height(tree.left), height(tree.right)) + 1;
return tree;
}

public void remove(T key) {
Node<T> z;
if ((z = search(root, key)) != null)
root = remove(root, z);
}

private Node<T> remove(Node<T> tree, Node<T> z) {
// 根为空 或者 没有删除的节点,直接返回null
if (tree == null || z == null)
return null;
int cmp = z.key.compareTo(tree.key);
if (cmp < 0) {
tree.left = remove(tree.left, z);
// 删除节点后,若avl树失去平衡,直接返回null
if (height(tree.right) - height(tree.left) == 2) {
Node<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);
if (height(tree.left) - height(tree.right) == 2) {
Node<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)) {
Node<T> node = maxinum(tree.left);
tree.key = node.key;
tree.left = remove(tree.left, node);
} else {
Node<T> min = mininum(tree.left);
tree.key = min.key;
tree.right = remove(tree.right, min);
}
} else {
Node<T> tmp = tree;
tree = (tree.left != null) ? tree.left : tree.right;
tmp = null;
}
}
return tree;
}

public void print() {
if (root != null)
print(root, root.key, 0);
}

/*
* 打印"二叉查找树"
*
* key -- 节点的键值 direction -- 0,表示该节点是根节点; -1,表示该节点是它的父结点的左孩子;
* 1,表示该节点是它的父结点的右孩子。
*/
private void print(Node<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);
}
}
/*
* 销毁AVL树
*/
private void destroy(Node<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(root);
}
private class Node<T extends Comparable<T>> {
private T key;
private int height;
private Node<T> left;
private Node<T> right;

@SuppressWarnings("unused")
public Node(T key, Node<T> left, Node<T> right) {
this.key = key;
this.left = left;
this.right = right;
this.height = 0;
}

}

}

---------------------------------------AVLTree测试类

package com.learn.tree.demo2;

public class AVLTest {
private static int arr[]= {3,2,1,4,5,6,7,16,15,14,13,12,11,10,8,9};
public static void main(String[] args) {

int i;
AVLTree<Integer> tree = new AVLTree<Integer>();

System.out.printf("== 依次添加: ");
for(i=0; i<arr.length; i++) {
System.out.printf("%d ", arr[i]);
tree.insert(arr[i]);
}

System.out.printf("\n== 前序遍历: ");
tree.preOrder();

System.out.printf("\n== 中序遍历: ");
tree.inOrder();

System.out.printf("\n== 后序遍历: ");
tree.postOrder();
System.out.printf("\n");

System.out.printf("== 高度: %d\n", tree.height());
System.out.printf("== 最小值: %d\n", tree.minimum());
System.out.printf("== 最大值: %d\n", tree.maxinum());
System.out.printf("== 树的详细信息: \n");


tree.print();

i = 8;
System.out.printf("\n== 删除根节点: %d", i);

tree.remove(i);
tree.remove(2);
System.out.printf("\n== 中序遍历: ");
tree.inOrder();

System.out.printf("\n== 高度: %d", tree.height());
System.out.printf("\n== 中序遍历: ");
tree.inOrder();
System.out.printf("\n== 树的详细信息: \n");
tree.print();



}

}

 

posted on 2018-02-06 15:15  蔡苗  阅读(214)  评论(0编辑  收藏  举报