zoukankan      html  css  js  c++  java
  • AVL树的插入删除查找算法实现和分析-1

    至于什么是AVL树和AVL树的一些概念问题在这里就不多说了,下面是我写的代码,里面的注释非常详细地说明了实现的思想和方法。


    因为在操作时真正需要的是子树高度的差,所以这里采用-1,0,1来表示左子树和右子树的高度差,而没有使用记录树的高度的方法。

    代码如下:

    typedef struct AVLNode
    {
        DataType cData;
        int nBf;        //结点的平衡因子,-1表示右子树的深度比左子树高1
                        //0表示左子树与右子树深度相等
                        //1表示左子树的深度比右子树高1
        struct AVLNode *LChild;
        struct AVLNode *RChild;
    }AVLNode,*AVLTree;


    typedef int BOOL;

    enum enumHight{LH = 1, EH = 0, RH = -1} eHight;
    enum enumBool{FALSE = 0, TRUE = 1} eBool;


    void R_Rotate(AVLTree *pAT)
    {
        //对以*pAT为根的二叉树作右旋转处理,处理之后pAT指向新的树根结点
        //即旋转处理之前的左子树的根结点
        AVLTree lc = (*pAT)->LChild;
        (*pAT)->LChild = lc->RChild;
        lc->RChild = *pAT;
        *pAT = lc;
    }
    void L_Rotate(AVLTree *pAT)
    {
        //对以*pAT为根的二叉树作左旋转处理,处理之后pAT指向新的树根结点
        //即旋转处理之前的右子树的根结点
        AVLTree rc = (*pAT)->RChild;
        (*pAT)->RChild = rc->LChild;
        rc->LChild = *pAT;
        *pAT = rc;
    }
    void LeftBalance(AVLTree *pAT)
    {
        //对以指针pAT所指结点为根的二叉树作左平衡旋转处理,
        //本算法结束时指针pAT指向新的结点
        AVLTree lc = (*pAT)->LChild;    //lc指向*pAT的左子树根结点
        AVLTree rd = NULL;
        if(lc)
        switch(lc->nBf)     //检查*pAT的左子树的平衡度,并作相应平衡处理
        {
            case LH:    //新结点插入在*pAT的左孩子的左子树上,要作单右旋转处理
                (*pAT)->nBf = lc->nBf = EH;
                R_Rotate(pAT);
                break;
            case RH:    //新结点插入在*pAT的左孩子的右子树上,要作双旋转处理
                rd = lc->RChild;
                switch(rd->nBf) //修改*pAT及其左孩子的平衡因子
                {
                    case LH:
                        (*pAT)->nBf = RH;
                        lc->nBf = EH;
                        break;
                    case EH:
                        (*pAT)->nBf = lc->nBf = EH;
                        break;
                    case RH:
                        (*pAT)->nBf = EH;
                        lc->nBf = LH;
                        break;
                    default:;
                }
                rd->nBf = EH;
                L_Rotate(&(*pAT)->LChild);  //对*pAT的左子树作左平衡处理
                R_Rotate(pAT);      //对*pAT作右平衡处理
                break;
            default:;
        }
    }
    void RightBalance(AVLTree *pAT)
    {
        //对以指针pAT所指结点为根的二叉树作右平衡旋转处理,
        //本算法结束时指针pAT指向新的结点
        AVLTree rc = (*pAT)->RChild;
        AVLTree rd = NULL;
        if(rc)
        switch(rc->nBf)
        {
            case RH:
                (*pAT)->nBf = rc->nBf = EH;
                L_Rotate(pAT);
                break;
            case LH:
                rd = rc->LChild;
                switch(rd->nBf)
                {
                    case LH:
                        (*pAT)->nBf = EH;
                        rc->nBf = RH;
                        break;
                    case EH:
                        (*pAT)->nBf = rc->nBf = EH;
                        break;
                    case RH:
                        (*pAT)->nBf = LH;
                        rc->nBf = EH;
                        break;
                }
                rd->nBf = EH;
                R_Rotate(&(*pAT)->RChild);
                L_Rotate(pAT);
            default:;
        }
    }
    BOOL InsertATNode(AVLTree *pAT, DataType c)
    {
        //若在平衡的二叉树pAT中不存在和c相同的关键字结点,
        //则插入一个以c为数据元素的新结点,并返回1,否则返回0
        //若因插入而使二叉排序树失去平衡,则作平衡旋转处理
        static int taller = FALSE;  //反映pAT树是否长高
        if(!(*pAT))
        {
            //插入新结点,树长高,taller为TRUE;
            (*pAT) = (AVLTree)malloc(sizeof(AVLNode));
            (*pAT)->cData = c;
            (*pAT)->LChild = (*pAT)->RChild = NULL;
            (*pAT)->nBf = EH;
            taller = TRUE;
        }
        else
        {
            if((*pAT)->cData == c)
            {
                //树中已存在和e相同关键字的结点,不插入
                taller = FALSE;
                return 0;
            }
            if(c < (*pAT)->cData)
            {
                //应该在*pAT的左子树中进行搜索
                if(!InsertATNode(&(*pAT)->LChild, c))   //未插入
                    return 0;
                if(taller)  //已插入到树pAT并且左子树长高
                {
                    switch((*pAT)->nBf) //检查*pAT的平衡因子
                    {
                        case LH:    //原本左子树比右子树高,作左平衡处理
                            LeftBalance(pAT);
                            taller = FALSE;
                            break;
                        case EH:    //原本左右子树等高,现左子树比右子树高1
                            (*pAT)->nBf = LH;
                            taller = TRUE;
                            break;
                        case RH:    //原本右子树比左子树高,现左右子树等高
                            (*pAT)->nBf = EH;
                            taller = FALSE;
                            break;
                    }
                }
            }
            else
            {
                //应该在*pAT的右子树中进行搜索
                if(!InsertATNode(&(*pAT)->RChild, c))   //未插入
                    return 0;
                if(taller)  //已插入到树pAT并且右子树长高
                {
                    switch((*pAT)->nBf) //检查*pAT的平衡因子
                    {
                        case LH:    //原本左子树比右子树高,现左右子树等高
                            (*pAT)->nBf = EH;
                            taller = FALSE;
                            break;
                        case EH:    //原本左右子树等高,现右子树比左子树高1
                            (*pAT)->nBf = RH;
                            taller = TRUE;
                            break;
                        case RH:    //原本右子树比左子树高,作右平衡处理
                            RightBalance(pAT);
                            taller = FALSE;
                            break;
                    }
                }
            }
        }
        return 1;
    }
    BOOL DeleteNode(AVLTree *pAT, DataType c)
    {
        //若在平衡的二叉树pAT中存在和c相同的关键字结点,
        //则删除一个以c为数据元素的结点,并返回1,否则返回0
        //若因删除而使二叉排序树失去平衡,则作平衡旋转处理
        static int lower = FALSE;   //反映pAT树是否变矮
        if(!(*pAT))     //树为空或结点不存在返回0
            return 0;
        if(c == (*pAT)->cData)
        {
            //存在要删除的结点
            //查找用作替换的结点
            AVLTree Min = FindMin((*pAT)->RChild);
            if(Min != NULL) //存在右子树
            {
                //找到可以用作替换的点
                (*pAT)->cData = Min->cData;
                if(Min != (*pAT)->RChild)
                {
                    AVLTree Parent = GetParent((*pAT)->RChild, Min->cData);
                    Parent->LChild = Min->RChild;
                }
                else
                {
                    (*pAT)->RChild = Min->RChild;
                }


                free(Min);
            }
            else //不存在右子树
            {
                //找不到删除的结点
                Min = *pAT;
                *pAT = (*pAT)->LChild;
                free(Min);
            }
            lower = TRUE;
        }
        else if(c < (*pAT)->cData)
        {
            //应该在*pAT的左子树中进行搜索
            if(!DeleteNode(&(*pAT)->LChild, c)) //未删除
                return 0;


            if(lower)   //树变矮
            {
                switch((*pAT)->nBf)
                {
                    case LH:    //原本左子树比右子树高,现在等高
                        (*pAT)->nBf = EH;
                        lower = TRUE;
                        break;
                    case EH:    //原本左右子树等高,现右子树比左子树高1
                        (*pAT)->nBf = RH;
                        lower = FALSE;
                        break;
                    case RH:    //原本右子树比左子树高,则作右平衡处理
                        RightBalance(pAT);
                        lower = TRUE;
                        break;
                }
            }


        }
        else if(c > (*pAT)->cData)
        {
            //应该在*pAT的右子树中进行搜索
            if(!DeleteNode(&(*pAT)->RChild, c))
                return 0;
            if(lower)
            {
                switch((*pAT)->nBf)
                {
                    case LH:    //原本左子树比右子树高,则作左平衡处理
                        LeftBalance(pAT);
                        lower = TRUE;
                        break;
                    case EH:    //原本左右子树等高,现左子树比右子树高1
                        (*pAT)->nBf = LH;
                        lower = FALSE;
                        break;
                    case RH:    //原本右子树比左子树高,现左左子树等高
                        (*pAT)->nBf = EH;
                        lower = TRUE;
                        break;
                }
            }
        }


        return 1;
    }
    AVLTree FindMin(AVLTree AT)
    {
        //查找AT中最小的元素
        while(AT && AT->LChild)
        {
            AT = AT->LChild;
        }
        return AT;
    }
    AVLTree GetParent(AVLTree AT, DataType c)
    {
        if(!AT || AT->cData == c)
            return NULL;
        if((AT->LChild && AT->LChild->cData == c) ||
                (AT->RChild && AT->RChild->cData == c))
            return AT;
        else if((AT->LChild && c < AT->LChild->cData))
            return GetParent(AT->LChild, c);
        else
            return GetParent(AT->RChild, c);
    }

    AVLTree FindATNode(AVLTree AT, DataType c)
    {
        if(!AT)
            return NULL;
        else if(AT->cData == c)
            return AT;
        else if(c < AT->cData)
        {
            return FindATNode(AT->LChild, c);
        }
        else
        {
            return FindATNode(AT->RChild, c);
        }
    }

    现在对这种实现方法作一点小小的分析。

    1、至于时间复杂度的分析就不必多说了,所有的算法的时间复杂度都为log2N。

    2、从代码的数量可以看出这并不是一种好的实现方法,因为它的思路不太清晰和直观,操作实现比较复杂,还要用到二重指针,增加了程序出错的机会。

    3、导致复杂的原因主要有两个,

    1)第一个就是在高度信息储存方法上,不是采用每个结点保存自己作为一棵树的深度,而是保存着左右子树之差(左子树的深度 - 右子树的深度),从而产生了大量的判断和switch语句,让人眼花瞭乱,并且影响程序的效率和易读性,难以维护,所以用一个变量记录树的高度会让程序思路更清晰。

    2)再者,在这里的旋转、插入的删除操作都要调节结点并改变指向结点的指针变量的值,在C语言中是没有引用的(C++有),所以就要用到双重指针,这无疑加大了程序的复杂度,而且使程序更容易出错。而避免这样的情况的做法是很简单的,只需要做一个简单的修改。就是让旋转插入等操作的返回值为指向结点的指针,而不是一个标志操作是否成功的状态值。而且这样做还有一个好处,就是通常最后插入的数据总是最先被访问,这样就可以根据返回的结点的指针马上访问该结点,而不用再在整棵树中查找。


    算法如有错误,还请各位读者指出,谢谢!

    改进后的算法会在下一篇的博客中给出。

  • 相关阅读:
    iOS 谁说程序猿不懂浪漫之 爱心
    iOS 星星评价视图 3行搞定
    iOS 柱状图的定制
    iOS 跑马灯 一句话集成
    代理的使用
    发送的网络请求中含有中文 转码的实现
    杂记
    使用纯代码实现UICollectionView(UITableView)需要注册
    NSASSert的使用
    iOS进阶第三节 数据处理之CoreData
  • 原文地址:https://www.cnblogs.com/dyllove98/p/3146850.html
Copyright © 2011-2022 走看看