学习笔记 AVL树

来源:互联网 发布:上海民族一厂淘宝官网 编辑:程序博客网 时间:2024/05/16 03:51

理想平衡与适度平衡

含有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);        }    }}
原创粉丝点击