算法与数据结构 其六 Avl平衡树

Avl平衡树

接下来要介绍的树都是从二叉树演变而来的,Avl平衡树当然不例外。

何谓平衡?

原目标是树的所有左右子数的高度都相等,但是实际操作起来不现实,所以给的平衡条件是
树的每个节点的左子树和右子树的高度最多差1

那么Avl平衡树就是树的每个节点的左子树和右子树的高度最多差1 的二叉查找树。由于一科满二叉树的高度是O(logN),平衡二叉树的高度仅仅稍微大于 O(logN),所以对于我们 CRUD速度是很快的。但是在操作中有一点需要注意:

为了保持树的平衡,每次增删时判断树时对树的平衡加以控制

所以Avl树比普通二叉查找树多了一部,就是保持平衡,我们称它为旋转

旋转分为两种类型:单旋转(左旋转,单右旋转);双旋转(先左旋后右旋,先右旋后左旋)。后者是建立在前者之上。下面讲讲旋转

单旋转(右旋转)

这里写图片描述

当树的左右子树高度相差2的时候,我们将 K1的左子树挂在K2的左子树,而K1称为这个子树的根节点,保持了平衡

实际例子

这里写图片描述

这样,非常简单明了。(左旋转和这里类似,所以不做介绍)

双旋转(先右后左)

由于会出现单旋转不能解决的类型,例如下面
这里写图片描述

那么我们需要使用双旋转进行修复
这里写图片描述

实际例子
这里写图片描述

只要理解了这个概念就可以了,因为其他的是和查找二叉树

使用java代码实现AVL树

因为无论插入还是删除都可能对平衡造成影响,所以我们要记录下树的高度,用来判断是否需要旋转

//这是树的节点,height是节点下树的高度
private static class AvlNode<E>{
        public AvlNode(E theElement){
            this(theElement,null,null);
        }

        public AvlNode(E theElement, AvlNode<E> lt, AvlNode<E> rt) {
            this.theElement = theElement;
            this.lt = lt;
            this.rt = rt;
            height=0;
        }

        E theElement;
        AvlNode<E> lt;
        AvlNode<E> rt;
        int height;

        @Override
        public String toString() {
            return theElement+"";
        }
    }

单旋转代码

private AvlNode<E> rotateWidthLeftChild(AvlNode<E> a1) {
        //这里进行旋转
        AvlNode<E> a2 = a1.lt;
        a1.lt=a2.rt;
        a2.rt = a1;
        //计算旋转后两个子树的高度
        a1.height = Math.max(height(a1.rt),height(a1.lt))+1;
        a2.height = Math.max(height(a2.lt),a1.height)+1;
        return a2;
}

双旋转代码(先右后左)

private AvlNode<E>  doubleRotateWidthLeftChild(AvlNode<E> avlNode) {
        //右旋转
        avlNode.lt = rotateWidthRightChild(avlNode.lt);
        //左旋转
        AvlNode<E>  node = rotateWidthLeftChild(avlNode);
        return node;
}

插入元素的代码

public boolean insert(E theElement){
        root = insert(theElement,root);
        return true;
}
private AvlNode<E> insert(E theElement,AvlNode<E> avlNode){

        if(avlNode==null||theElement==null)
            return new AvlNode<E>(theElement);

        int compareResult = theElement.compareTo(avlNode.theElement);

        if(compareResult<0){
            avlNode.lt = insert(theElement,avlNode.lt);
            if(height(avlNode.lt)-height(avlNode.rt)==2){
                if(theElement.compareTo(avlNode.lt.theElement)<0){
                    avlNode = rotateWidthLeftChild(avlNode);
                }else{
                    avlNode = doubleRotateWidthLeftChild(avlNode);
                }
            }
        }else if(compareResult>0){
            avlNode.rt = insert(theElement,avlNode.rt);
            if(height(avlNode.rt)-height(avlNode.lt)==2){
                if(theElement.compareTo(avlNode.rt.theElement)>0){
                    avlNode = rotateWidthRightChild(avlNode);
                }else{
                    avlNode = doubleRotateWidthRightChild(avlNode);
                }
            }
        }else;
        avlNode.height = Math.max(height(avlNode.lt),height(avlNode.rt))+1;
        return avlNode;
}

删除元素代码

private AvlNode<E> remove(E theElement, AvlNode<E> avlNode) {
        if(avlNode==null||theElement==null)
            return null;


        int compateTo = theElement.compareTo(avlNode.theElement);
        if(compateTo<0){
            avlNode.lt = remove(theElement,avlNode.lt);
            //删除之后进行旋转
            if(height(avlNode.lt)-height(avlNode.rt)==2){
                if(theElement.compareTo(avlNode.lt.theElement)<0){
                    avlNode = rotateWidthLeftChild(avlNode);
                }else{
                    avlNode = doubleRotateWidthLeftChild(avlNode);
                }
            }
        }else if(compateTo>0){
            avlNode.rt = remove(theElement,avlNode.rt);
            //删除之后进行旋转
            if(height(avlNode.rt)-height(avlNode.lt)==2){
                if(theElement.compareTo(avlNode.rt.theElement)>0){
                    avlNode = rotateWidthRightChild(avlNode);
                }else{
                    avlNode = doubleRotateWidthRightChild(avlNode);
                }
            }
        }else if(compateTo==0){
            if(avlNode.lt!=null && avlNode.rt!=null){
                //如果左子树的高度 大于右子树
                if(height(avlNode.lt)>height(avlNode.rt)){
                    //找左子树最大的点
                    AvlNode<E> avl =findMax(avlNode.lt);
                    avlNode.theElement = avl.theElement;
                    //该保持还是要保持
                    avlNode.lt = remove(avl.theElement,avlNode.lt);
                }else{
                    //如果左子树的高度 小于右子树
                    //找右子树最小的点
                    AvlNode<E> avl = findMin(avlNode.rt);
                    avlNode.theElement = avl.theElement;
                    //
                    avlNode.rt = remove(avl.theElement,avlNode.rt);
                }
            }else{
                AvlNode<E> avl = avlNode;
                if(avlNode.lt!=null){
                    //整个左子树向上移了
                    avlNode = avlNode.lt;
                }else if(avlNode.rt!=null){
                    //整个右子树向上移了
                    avlNode = avlNode.rt;
                }
                avl=null;
            }
        }
        return avlNode;
}

注意这里,因为删除和插入也是需要一定的开销,所以建议如果在数据量大,插入和删除操作很少的情况下,可以使用惰性删除(删除元素而不删除节点)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值