《树》之AVL树

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《树》之AVL树相关的知识,希望对你有一定的参考价值。

本文简介:

  1. AVL树的简单介绍

  2. AVL树几种实现方法的对比

  3. AVL树删除节点的分析

  4. AVL树插入节点的分析

  5. AVL树ADT的简单实现




一、简介

    定义:    AVL(Adlson-Velskii和Landis)树是带有平衡条件的二查查找树。对于AVL树来说,其平衡条件有两点限制:

        ⑴易于保持;

        ⑵保证树的深度为O(log N)。


二、AVL树几种实现方法的对比


几种平衡条件的讨论

        ⑴树上每个节点都必须要有相同高度的左子树和右子树;

                在该平衡条件下,记根节点的高度为0,则高度为K的AVL树,其节点个数为2^k-1;此时该AVL树也是一颗满二查树。虽然该条件实现了AVL树,但是过于严格,难以满足普遍数据,所以在这里不采用。

        ⑵树上每个节点的左子树高度与右子树高度之差的绝对值不大于1;

                满足该平衡条件时,节点左、右子树的高度差的绝对值有0,1两种情况。

                    ①当所有节点的左、右子树的高度相等时,该AVL树的节点个数最大,为2^k-1;

                    ②当所有非叶节点的左、右子树的高度差的绝对值为1时,该AVL树的节点个数最小,数量可以用递推关系式:S(h)=S(h-1)+S(h-2)+1 (h>=2)得到;其中,h=0时,S(h)=1;h=1时,S(h)=2。此函数与斐波那契数列密切相关。


三、AVL树的节点删除


        AVL树需要保持其平衡条件,所以对于可能破坏AVL树平衡条件的操作,需要特别的注意。在对AVL树上的元素进行删除时,可能会破坏树上某些节点的平衡;被破坏的节点可以通过简单的修正来实现,这种修正被称作旋转(rotation)。基于AVL树可以保存大量数据的特性,在删除操作较少的时候,执行懒惰删除更加方便,在这里只考虑懒惰删除。


四、AVL树的节点插入


        插入节点时,有四种操作会破坏平衡条件。假设插入新节点后,树中的 α 节点必须被重新平衡。这四种情况分别为:

            ⑴对 α 的左儿子的左子树进行一次插入;

            ⑵对 α 的右儿子的右子树进行一次插入;

            ⑶对 α 的左儿子的右子树进行一次插入;

            ⑷对 α 的右儿子的左子树进行一次插入;

        其中前两种情况为一类,通过进行一次单旋转即可重新实现平衡;后两种情况为另一类,通过进行一次双旋转即可重新实现平衡。


五、AVL树ADT的简单实现


AVL树的ADT声明

#ifndef AVLTree_H
#define AVLTree_H

typedef int ElementType;
struct avLNode;
typedef struct avLNode *Position;
typedef struct avLNode *avLTree;

avLTree MakeEmpty(avLTree avlt);                                          //构造空树
Position Find(const ElementType x,const avLTree avlt);       //查找值为x的节点
Position FindMin(const avLTree avlt);                                      //查找AVL树上的最小元素节点
Position FindMax(const avLTree avlt);                                     //查找AVL树上的最大元素节点
Position Insert(const ElementType x,avLTree avlt);               //插入值为x的节点
avLTree Delete(ELementType x,avltree avlt);                        //删除值为x的节点
ElementType reTrieve(const ElementType x,Position p);      //把位置p处的值改为x
int GetHeight(const Position p);                                                 //获得位置p处的节点高度    
#endif  /*AVLTree_H AVL树ADT的声明*/

//定义树节点
struct avLNode{
    ElementType data;
    avLTree left;
    avLTree right;
    int height;
};



  1. 构造空树算法、三种查找算法

        AVL树是二查查找树的一种变形,所以对二查查找树的构造空树操作、查找操作同样适应于AVL树,所以这里不再赘述。


  2. 获得高度算法

        因为节点的高度不可能小于0,所以,用-1来表示空节点和已删除的节点。

int GetHeight(const Position p)
{
    if(p==null) return -1;
    else return p->height;
}

   

    3.插入值为x的节点,算法的详细步骤分析在上面给出。

Position Insert(const ElementType x,avLTree avlt)
{
    if(NULL==avlt){
        int lh=0,rh=0;
        avlt=new struct avLNode;
        if(NULL==avlt) ;
        else {
            avlt->data=x;avlt->height=-1;
            avlt->left=avlt->right=NULL;
        }
    }
    else if(x<(avlt->data)){
        avlt->left=Insert(x,avlt->left);
        if(GetHeight(avlt->left)-GetHeight(avlt->right)==2)
            if(x<(avlt->left->data))
                avlt=singleWithLL(avlt);//在左儿子的左子树上插入
            else
                avlt=doubleWithLR(avlt);//在左儿子的右子树上插入
    }else if(x>(avlt->data)){
        avlt->right=Insert(x,avlt->right);
        if(GetHeight(avlt->left)-GetHeight(avlt->right)==2)
            if(x>(avlt->right->data))
                avlt=singleWithRR(avlt);//在右儿子的右子树上插入
            else
                avlt=doubleWithRL(valt);//在右儿子的左子树上插入
    }
    lh=GetHeight(valt->left);rh=GetHeight(valt->right);
    valt->height=lh>rh?lh:rh;
    return valt;
}


4.四种旋转的详细介绍和实现

    ⑴在 α 的左儿子的左子树上插入(左左型)

static Position singleWithLL(Position k1)
{
    vlTree k2;
    k2 = k1->left;
    k1->left = k2->right;
    k2->right = k1;
    
    k1->height=(GetHeight(k1->left)>GetHeight(k1->Right)?GetHeight(k1->left):GetHeight(k1->right)) + 1;
    k2->height=(GetHeight(k2->left)>k1->height?GetHeight(k2->keft):k1->height)+1;
    
    return k2;
}


    ⑵在 α 的右儿子的右子树上插入(右右型)

static Position singleWithRR(Position k1)
{
    vlTree k2;
    k2=k1->right;
    k1=k2->left;
    k2->keft=k1;
    
    k1->height=(GetHeight(k1->left)>GetHeight(k1->Right)?GetHeight(k1->left):GetHeight(k1->right)) + 1;
    k2->height=(GetHeight(k2->right)>k1->height?GetHeight(k2->right):k1->height)+1;
    
    return k2;
}


    ⑶在 α 的左子树的右子树上插入(左右型)

static Position doubleRotateWithLR(Position k3)
{
    k3->right=singleWithLL(k3->right);
    
    return singleWithRR(k3);
}


    ⑷在 α 的右子树的左子树上插入(右左型)

static Position doubleRotateWithRL(Position k3)
{
    k3->left=singleWithRR(k3->left);
    
    return singleWithLL(k3);
}


以上是关于《树》之AVL树的主要内容,如果未能解决你的问题,请参考以下文章

树结构实际应用之平衡二叉树(AVL 树)

0042数据结构之AVL树

数据结构之AVL树

图解数据结构树之AVL树

初识C++之AVL树

算法小讲堂之平衡二叉树|AVL树(超详细~)