学习笔记 AVL树

理想平衡与适度平衡

含有n个节点的二叉树高度以[logn]为上界,若树高恰好为[logn]则称为理想平衡树,完全二叉树就是其中之一。

适度平衡

而实际的二叉树关键码趋近与一侧的较多。在渐进意义下的平衡性才有意义。

局部性

在AVL树中,兄弟节点的高度相差不过1。而且还有:

  1. 经过单次动态修改操作后,至多只有O(1)的局部不再符合限制条件。
  2. 总可在O(logn)时间内,使O(1)处的不满足重新满足限制条件。

    这点很重要,二叉树的顺序性是在中序遍历下确定的,所以只要在中序遍历不变的情况下可以认为两颗二叉树是等价的。

引入旋转调整的概念:

  1. zig
  2. zag

先前在二叉树中提到,孩子高度发生变化,父代很难发现其变化,所以在定义AVL模板类之前,给出关于平衡因子的宏定义。

  • BalFac(v) = height(lc(v))-height(rc(v))
  • |BalFac(v)|<=1
#define BalFac(x) (stature((x).lc)-stature((x).rc))
#define AvlBalanced(x) ((-2<BalFac(x))&&(BalFac(x)<2))
#define Balanced(x) (stature((x).lc)==stature((x).rc))

给出AVL模板类。

#include "BST.h"
template<typename T>class AVL : public BST<T>{
public:
    BinNodePosi(T) insert(const T& e);
    bool remove(const T& e);
    //其余沿用BST接口
}

而插入算法不同于BST的一点就是插入一个新节点之后,历代祖先可能高度会发生变化,一但高度发生变化,平衡就会打破,所以重平衡是主要解决的问题。
由于前面局部性的定义,考察三个节点,v,p=v->parent,g=p->parent。一旦这个局部调整完成,全树的顺序性必然恢复。(这是为什么?)
宏定义

#define tallerChild(x) (stature((x)->lc)<stature((x)->rc)?x->rc:(//左边高
                        stature((x)->rc)<stature((x)->lc)?x->lc:(//右边高
                        IsChild(*(x))?x->lc:x->rc//等高的情况
)
)
)

先给出插入算法。

template<typename T>BinNodePosi(T) AVL<T>::insert(const T& e){
    BinNodePosi(T) x = Search(e);//常规的搜索
    if(x) return x;//如果x不存在则创建
    BinNodePosi(T) xx = new BinNode<T>(e,_hot);
    _size++;
    for(BinNodePosi(T) g =_hot; g ; g = g->parent){//从_hot开始沿parent指针回溯
        if(!AvlBalanced(*g)){//一旦发现不平衡
            FromParentTo(*g)=rotateAt(tallerChild(tallerChild(g)));g->p->v
            break;//局部调整完毕则退出
        }
        else//全树没有不平衡的点
        updateHeight(g);//逐步更新高度
    } 
    return xx;//不论插入的点存不存在,总能返回。
}

而删除算法则不一样,会出现以下的情况

调整之后,树高没有减少,P的某一祖先会有L-subT高度-1,而出现BalFac = -2的情况

template<typename T>bool AVL<T>::remove(const T& e){
    BinNodePosi(T) &x = Search(e);
    if(!x) return false;
    removeAt(x,_hot);_size--;
    //重平衡
    for(BinNodePosi(T) g = _hot;g;g=g->parent){
    //没有办法提前退出
        if(!AvlBalanced(*g)){
            FromParentTo(*g) = rotateAt(tallerChild(tallerChild(g)));
        }
    }
    return true;
}
统一重平衡算法

不论是插入或是删除算法,都需要调整一个子树,即v->p->g的结构,而3个节点构成的完全二叉树则完全可以重新构成一棵AVL树。

称之为“3+4重构”

template<typename T>BinNodePosi(T) BST<T>::connect34(BinNodePosi(T) a,BinNodePosi(T) b,BinNodePosi(T) c
,BinNodePosi(T) T0,BinNodePosi(T) T1,BinNodePosi(T) T2,BinNodePosi(T) T3){
    a->lc = T0; if(T0) T0->parent = a;
    a->rc = T1; if(T1) T1->parent = a;
    updateHeight(a);
    c->lc = T2; if(T2) T2->parent = c;
    c->rc = T3; if(T3) T3->parent = c;
    updateHeight(c);
    b->lc = a;
    b->rc = c;
    updateHeight(b);
    return b;
}

有了3+4重构则可以完成先前zig以及zag旋转调整的思路。

template<typename T>BinNodePosi(T) BST<T>::rotateAt(BinNodePosi(T) v){
    BinNodePosi(T) p = v->parent;
    BinNodePosi(T) g = p->parent;
    //单旋
    if(IsLChild(*p))
        if(IsLChild(*v)){
            //zig操作
            p->parent = g->parent;
            return connect34(v,p,g,v->lv,v->rc,g->lc,g->rc);
        }
        else{
            //双旋
            //zag-zig操作
            v->parent = g->parent;
            return connect34(p,v,g,p->lc,p->rc,g->lc,g->rc);
        }
    else{
        if(IsRChild(*v)){
            //zag操作
            p->parent = g->parent;
            return connect34(g,p,v,g->lc,g->rc,v->lc,v->rc);
        }
        else{
            //zig-zag操作
            v->parent = g->parent;
            return connect34(g,v,p,g->lc,g->rc,p->lc,p->rc);
        }
    }
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值