AVLTree
- 是一种自平衡的二叉查找树,平衡表示其每个节点的左右子树的高度差最多为一,可以减少检索是由于极端情况产生的消耗
- 实现的过程中需注意在插入和删除的过程维持平衡
- 维持平衡的情况
- 双旋转
- 单旋转
package com.ccy.tree;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
public class MyAvlTree <E extends Comparable<E>>{
/**
* 节点类
* @author ccy
*
* @param <E>
*/
private static class TreeNode<E>{
E value; //数据
TreeNode<E> left; //左子节点
TreeNode<E> right; //右子节点
int height; //高度
public TreeNode(E value,TreeNode left,TreeNode right) {
this.left = left;
this.right = right;
this.value = value;
}
public TreeNode(E value) {
this.left = null;
this.right = null;
this.value = value;
}
}
private static final int ALLOW_IMBALANCE = 1;
//定义根结点
private TreeNode<E> root = null;
/**
* 返回一个根结点为空的树
*/
public MyAvlTree(){
root=null;
}
/**
* 判断是否为空
* @return 空为true,非空为false
*/
public boolean isEmpty() {
return root == null;
}
public void insert(E value) {
root = insert(value, root);
}
/**
* 添加节点
* @param value 想要添加到树中的数据
*/
private TreeNode<E> insert(E value,TreeNode<E> treeNode) {
if(treeNode==null)
return new TreeNode<>(value);
if(value.compareTo(treeNode.value)>0)
treeNode.right = insert(value, treeNode.right);
else if(value.compareTo(treeNode.value)<0)
treeNode.left = insert(value, treeNode.left);
return balance(treeNode);
}
/**
* 建立平衡
* @param treeNode
* @return
*/
private TreeNode<E> balance(TreeNode<E> treeNode){
if(treeNode == null)
return treeNode;
if(height(treeNode.left)-height(treeNode.right)>ALLOW_IMBALANCE) {
if(height(treeNode.left.left)>=height(treeNode.left.right))
treeNode = rotateWithLeft(treeNode);
else {
treeNode = doubleWithLeft(treeNode);
}
}
else if(height(treeNode.right)-height(treeNode.left)>ALLOW_IMBALANCE) {
if(height(treeNode.right.right)>=height(treeNode.right.left))
treeNode = rotateWithRight(treeNode);
else {
treeNode = doubleWithRight(treeNode);
}
}
treeNode.height = Math.max(height(treeNode.left), height(treeNode.right))+1;
return treeNode;
}
private int height(TreeNode<E> treeNode) {
return treeNode==null?-1:treeNode.height;
}
/**
* 将左子树一次单旋上提
*
* @param treeNode 需维持部分的部分树的根
* @return 单旋转后该部分树的根
*/
private TreeNode<E> rotateWithLeft(TreeNode<E> treeNode){
TreeNode<E> tmpNode = treeNode.left;
treeNode.left = tmpNode.right;
tmpNode.right = treeNode;
//重新对高赋值
treeNode.height = Math.max(height(treeNode.left), height(treeNode.right))+1;
tmpNode.height = Math.max(height(tmpNode.left), treeNode.height)+1;
return tmpNode;
}
/**
* 将右子树一次单旋上提
*
* @param treeNode 需维持部分的部分树的根
* @return 单旋转后该部分树的根
*/
private TreeNode<E> rotateWithRight(TreeNode<E> treeNode){
TreeNode<E> tmpNode = treeNode.right;
treeNode.right = tmpNode.left;
tmpNode.left = treeNode;
//重新对高赋值
treeNode.height = Math.max(height(treeNode.left), height(treeNode.right))+1;
tmpNode.height = Math.max(height(tmpNode.right), treeNode.height)+1;
return tmpNode;
}
/**
*
* @param treeNode
* @return
*/
private TreeNode<E> doubleWithLeft(TreeNode<E> treeNode) {
treeNode.left = rotateWithRight(treeNode.left);
return rotateWithLeft(treeNode);
}
private TreeNode<E> doubleWithRight(TreeNode<E> treeNode) {
treeNode.right = rotateWithLeft(treeNode.right);
return rotateWithRight(treeNode);
}
public void remove(E value) {
root = remove(value, root);
}
/**
* 从AVLTree中移除一个元素
* 思想:
* 1. 先定位到该元素,若无该元素,直接返回
* 2. 从该元素的右子树中找出一个最小值顶替该元素,而后从其右子树中删除该最小值
* 3. 过程中应注意保持平衡
*
* @param value
* @param treeNode
* @return
*/
private TreeNode<E> remove(E value,TreeNode<E> treeNode){
if(treeNode == null)
return treeNode;
if(value.compareTo(treeNode.value)<0)
treeNode.left = remove(value, treeNode.left);
else if(value.compareTo(treeNode.value)>0)
treeNode.right = remove(value, treeNode.right);
else if(null != treeNode.left && null != treeNode.right) {
treeNode.value = findMin(treeNode.right).value;
treeNode.right = remove(treeNode.value, treeNode.right);
}else
treeNode = treeNode.left == null? treeNode.right:treeNode.left;
return balance(treeNode);
}
private TreeNode<E> findMin(TreeNode<E> treeNode) {
if(treeNode == null)
return null;
if(treeNode.left == null)
return treeNode;
return findMin(treeNode.left);
}
/**
* 广度优先遍历整棵avl树
*
*/
public void print() {
Queue<TreeNode> queue = new ArrayBlockingQueue<MyAvlTree.TreeNode>(20);
queue.add(root);
while(!queue.isEmpty()) {
TreeNode<E> tmpNode = queue.remove();
System.out.println(tmpNode.value);
if(tmpNode.left!=null)
queue.add(tmpNode.left);
if(tmpNode.right!=null)
queue.add(tmpNode.right);
}
}
}