AVL树的实现
1.类的架构
public class AvlTree<T extends Comparable<? super T>> {
private static class AvlNode<T> { 待实现 } // AVL树的节点类
private AvlNode<T> root; // 根节点就代表了一个AVL树
public void makeEmpty(){ root = null; }
public boolean isEmpty(){ return root == null; }
public int height() { return height(root); } // 树的深度
public boolean contains(T t){ return contains(t, root); } // 查找
public void insert(T t){ root = insert(t, root); } // 插入
public void remove(T t){ root = remove(t, root); } // 删除(返回boolean值可以用contains判断)
private int height(AvlNode<T> root){ 待实现 }
private AvlNode<T> contains(T t, AvlNode<T>){ 待实现 }
private AvlNode<T> insert(T t, AvlNode<T>){ 待实现 }
private AvlNode<T> remove(T t, AvlNode<T>){ 待实现 }
private AvlNode<T> balance(AvlNode<T>){ 待实现 }
private AvlNode<T> rotateWithLeft(AvlNode<T>){ 待实现 }
private AvlNode<T> doubleWithLeft(AvlNode<T>){ 待实现 }
private AvlNode<T> rotateWithRight(AvlNode<T>){ 待实现 }
private AvlNode<T> doubleWithRight(AvlNode<T>){ 待实现 }
}
2.static内部类:AvlNode
private static class AvlNode<T> {
T element;
AvlNode<T> left;
AvlNode<T> right;
int height; // 和普通二叉树结点对比,多了高度信息
AvlNode(T t){ this(t,null,null); }
AvlNode(T t, AvlNode<T> le, AvlNode<T> ri){
this.t = t;
left = le; right = ri;
height = 0; // 单个节点是没有高度的,它的高度是改动(插入/删除)时赋值的
}
}
3.方法实现
private int height(AvlNode<T> root){
return root==null?-1:root.height; // null节点高度是-1,树叶节点高度是0
}
private boolean contains(T t, AvlNode<T> root){
if(t == null)
return false;
int result = t.compareTo(root.element);
if(result > 0)
return contains(t, root.right);
else if(result < 0)
return contains(t, root.left);
else
return true;
}
private AvlNode<T> insert(T t, AvlNode<T> root){
if(root == null)
return new AvlNode<T>(t);
int result = t.compareTo(root.element);
if(result > 0)
root.right = insert(t, root.right);
else if(result < 0)
root.left = insert(t, root.left);
else {} // exist. do nothing.
return balance(root); // 先插入再平衡,从低往高做平衡(第一个做平衡的是最深的节点)
}
private AvlNode<T> remove(T t, AvlNode<T> root){
if(root == null)
return null;
int result = t.compareTo(root.element);
if(result > 0)
root.right = remove(t, root.right);
else if(result < 0)
root.left = remove(t, root.left);
else{
if(root.left == null && root.right == null)
return null;
else if(root.left != null && root.right != null){
root.element = findMin(root.right).element;
root.right = remove(root.element, root.right);
} else
root = (root.left==null)?root.right:root.left;
}
return balance(root); // 删除后再平衡一下
}
private BinaryNode<T> findMin(BinaryNode<T> root){
if(root == null)
throw new Exception();
if(root.left != null)
return findMin(root.left);
else
return root;
}
3.平衡节点的方法
private static final int ALLOWED_IMBALANCE = 1; // 允许的不平衡程度
private AvlNode<T> balance(AvlNode<T> root){
if(root == null)
return null;
if( height(root.left) - height(root.right) > ALLOWED_IMBALANCE){
if(height(root.left.left) >= height(root.left.right)) // 单旋转:左单转
// >=是因为删除的时候可能存在的不平衡情况
root = rotateWithLeft(root);
else // 左双旋转
root = doubleWithLeft(root);
} else if(height(root.right) - height(root.left) > ALLOWED_IMBALANCE){
if(height(root.right.right) >= height(root.right.left)) // 单旋转:右单转
root = rotateWithRight(root);
else // 右双旋转
root = doubleWithRight(root);
} else {} // balance.do nothing
root.height = Math.max(height(root.left), height(root.right)) + 1; // 更新高度
// 这个是有必要的,插入操作并没有更新高度,靠的就是balance方法里从低往高更新
return root;
}
private AvlNode<T> rotateWithLeft(AvlNode<T> k1){
AvlNode<T> k2 = k1.left;
k1.left = k2.right;
k2.right = k1;
// 更新高度
k1.height = Math.max(height(k1.left), height(k1.right)) + 1;
k2.height = Math.max(height(k2.left), k1.height) + 1;
return k2;
}
private AvlNode<T> rotateWithRight(AvlNode<T> k1){
AvlNode<T> k2 = k1.right;
k1.right = k2.left;
k2.left = k1;
// 更新高度
k1.height = Math.max(height(k1.left), height(k1.right)) + 1;
k2.height = Math.max(height(k2.right), k1.height) + 1;
return k2;
}
private AvlNode<T> doubleWithLeft(AvlNode<T> k1){
k1.left = rotateWithRight(k1.left);
return rotateWithLeft(k1);
}
private AvlNode<T> doubleWithRight(AvlNode<T> k1){
k1.right = rotateWithLeft(k1.right);
return rotateWithRight(k1);
}
4.总结
AvlNode:有了深度height信息,该信息在balance方法里更新.
--注意高度信息是属于每个Node的属性.而不是Tree的属性.Tree的深度认为是它根节点Node的高度
--null的高度为-1,不是0; 树叶节点的高度是0(符合定义)
--节点高度的赋值都是在balance方法里完成(确实也只有平衡树需要深度信息,普通树不需要),解耦和.
--节点在变化时,注意它的高度也是变化的
Avl树代码分离的思想:将插入操作(删除操作)与平衡操作分离.它的插入操作(分离操作)和普通树一样,但是操作完都要进行平衡操作,变成平衡树.
不平衡的条件:某节点n的左(右)子树比右(左)子树深度大,且超过1
balance:该方法是核心平衡方法,节点n不平衡的原因和平衡方法分为四种:
--节点n左儿子的左儿子高度超了: 节点n左转方法(顺时针)
--节点n右儿子的右儿子高度超了: 节点n右转方法(逆时针)
--节点n左儿子的右儿子高度超了: 双旋转:节点n左儿子先右转,节点n再左转.
--节点n右儿子的左儿子高度超了: 双旋转:节点n右儿子先左转,节点n再右转