AVL树叫做自平衡二叉查找树,是带有平衡条件的二叉查找树。这个平衡条件必须要保持,而且它保证树的深度是O(logN).一般情况的下的平衡条件是要求每个节点左子树的高度和右子树的高度最多不能超过1.
作为一个自平衡二叉查找树,所以在插入和删除时,我们都需要保持该树的平衡条件,即每一个节点两边子节点的高度差不能大于1.为了方便和快速,我们可以只在插入时作平衡操作,在删除时可以将该节点标识为无效(也叫懒惰删除),一来增加了删除的速度,二来如果下次有同样的元素插入,可以避免再次作平衡操作。在这里我们暂时只实现了插入操作。
当平衡条件失去时,肯定是插入点到根节点的其中一个节点失去了平衡。所以插入可以分为四种情况:
①在失衡点左儿子的左子树进行插入,
②在失衡点左儿子的右子树进行插入,
③在失衡点右儿子的左子树进行插入,
④在失衡点右儿子的右子树进行插入,
①和④归为一类,这类为外侧插入失衡,②和③归为一类,这类为内侧插入失衡。
先来讨论第一类,外侧插入失衡:
这种情况的失衡我们可以采取一种叫单旋转的方法
当插入1后,3节点失衡,进行一次单旋转。
第二类,内侧插入失衡:
这种情况需要采用双旋转
我们可以看到如果采用单旋转,还是失衡状态,所以需要进行两次单旋转,也就是双旋转。
接下来就是写代码
package com.creat.avl;
/**
* Created by Administrator on 2017/8/12 0012.
*/
public class AvlTree<E extends Comparable<? super E>> {
private AvlNode<E> root;
//节点结构
private static class AvlNode<E>{
E element;
AvlNode<E> left;
AvlNode<E> right;
int height;
AvlNode(E element){
this.element = element;
this.right = null;
this.left = null;
this.height = 0;
}
AvlNode(E element, AvlNode<E> left, AvlNode<E> right){
this.element = element;
this.right = right;
this.left = left;
this.height = 0;
}
}
public void insert(E element){
root = insert(element,root);
}
private AvlNode<E> insert(E element, AvlNode<E> node){
if(node == null){
return new AvlNode<E>(element);
}
int compareResult = element.compareTo(node.element);
if(compareResult > 0){
node.right = insert(element,node.right);
if(getHeight(node.right) - getHeight(node.left) == 2){
if(element.compareTo(node.right.element) > 0){
node = rotateWithRightChild(node);
}else {
node = doubleWithRightChild(node);
}
}
}else if( compareResult < 0 ){
node.left = insert(element,node.left);
if(getHeight(node.left) - getHeight(node.right) == 2){
if(element.compareTo(node.left.element) < 0){
node = rotateWithLeftChild(node);
}else {
node = doubleWithLeftChild(node);
}
}
}else {
;
}
node.height = Math.max(getHeight(node.right),getHeight(node.left))+1;
return node;
}
private int getHeight(AvlNode<E> node){
return (node == null) ? -1 : node.height;
}
//单旋转
private AvlNode<E> rotateWithLeftChild(AvlNode<E> node){
AvlNode<E> l = node.left;
node.left = l.right;
l.right = node;
node.height = Math.max(getHeight(node.left),getHeight(node.right))+1;
l.height = Math.max(getHeight(l.left),node.height)+1;
return l;
}
private AvlNode<E> rotateWithRightChild(AvlNode<E> node){
AvlNode<E> r = node.right;
node.right = r.left;
r.left = node;
node.height = Math.max(getHeight(node.right),getHeight(node.left))+1;
r.height = Math.max(getHeight(r.right),node.height)+1;
return r;
}
//双旋转
private AvlNode<E> doubleWithLeftChild(AvlNode<E> node){
node.left = rotateWithRightChild(node.left);
return rotateWithLeftChild(node);
}
private AvlNode<E> doubleWithRightChild(AvlNode<E> node){
node.right = rotateWithLeftChild(node.right);
return rotateWithRightChild(node);
}
public void printTree(){
printTree(root);
}
private void printTree(AvlNode<E> node){
if(node != null){
printTree(node.left);
System.out.println(node.element+":height=:"+getHeight(node));
printTree(node.right);
}
}
}
测试结果:
package com.creat.avl;
/**
* Created by whz on 2017/8/12 0012.
*/
public class Client {
public static void main(String[] args){
AvlTree<Integer> avlTree = new AvlTree<Integer>();
avlTree.insert(5);
avlTree.insert(50);
avlTree.insert(5000);
avlTree.insert(500);
avlTree.insert(1);
avlTree.printTree();
}
}
结果:
1:height=:0
5:height=:1
50:height=:2
500:height=:0
5000:height=:1
声明:以上图片摘自《数据结构与算法分析(java描述)》