AVL树的删除

冷暖自知 提交于 2019-12-21 02:35:23

本文默认不讲左右旋转和左右结点失衡,总共六种情况的处理

先是AVL树的定义

typedef struct BSTNode {
    ElemType data;
    int bf;
    struct BSTNode* lchild, * rchild;
}BSTNode, *BSTree;

然后是左右旋转

void R_Rotate(BSTree& p)
{
    BSTree lc = p->lchild;
    p->lchild = lc->rchild;
    lc->rchild = p;
    p = lc;
}

void L_Rotate(BSTree& p)
{
    BSTree rc = p->rchild;
    p->rchild = rc->lchild;
    rc->lchild = p;
    p = rc;
}

然后是对左结点和右结点做平衡

void LeftBalance(BSTree& T)
{
    BSTree lc = T->lchild;
    switch (lc->bf) {
    case EH: {
        T->bf = LH;
        lc->bf = RH;
        R_Rotate(T);
        break;
    }
    case LH: {
        T->bf = lc->bf = EH;
        R_Rotate(T);
        break;
    }
    case RH: {
        BSTree rd = lc->rchild;
        switch (rd->bf) {
        case LH: {
            T->bf = RH;
            lc->bf = EH;
            break;
        }
        case EH: {
            T->bf = lc->bf = EH;
            break;
        }
        case RH: {
            T->bf = EH;
            lc->bf = LH;
            break;
        }
        }
        rd->bf = EH;
        L_Rotate(T->lchild);
        R_Rotate(T);
    }
    }
}

void RightBalance(BSTree& T)
{
    BSTree rc = T->rchild;
    switch (rc->bf) {
    case EH: {
        T->bf = RH;
        rc->bf = LH;
        L_Rotate(T);
        break;
    }
    case RH: {
        T->bf = rc->bf = EH;
        L_Rotate(T);
        break;
    }
    case LH: {
        BSTree ld = rc->lchild;
        switch (ld->bf) {
        case RH: {
            T->bf = LH;
            rc->bf = EH;
            break;
        }
        case EH: {
            T->bf = rc->bf = EH;
            break;
        }
        case LH: {
            T->bf = EH;
            rc->bf = RH;
            break;
        }
        }
        ld->bf = EH;
        R_Rotate(T->rchild);
        L_Rotate(T);
    }
    }
}

首先是在递归情况下用isshort来标记是否变短,当isshort为true,且变短的子树在左并且本身是右高,或者变短的子树在右边并且本身是左高,那么直接就对该节点做左结点平衡或右结点平衡

在找到key时有可以分为两种情况

这里把要删除的结点标记为d,d的后继结点标记为s,显然s不可能有左孩子

如果d的右孩子恰好为s,那么情况比较简单,可以直接让s顶替d结点即可,并查看原来d结点的平衡因子做相应的修改即可

如果d的右孩子不是s结点,则情况比较复杂,先看图

假设要删除的结点为d,后继为s,s拿出来后,可能要对s的双亲做平衡,甚至对s的某一个祖先做平衡,很难检查到,于是可以先对原来的右高的结点做处理,容易证明,对右高结点做左旋高度不变,此时有三种情况,如图

左边两种直接做左旋,再调节平衡因子即可,右边这种做左旋会失衡,因此暂时保留,最后递归回来时如果是右高,必然是这种情况,单独做RL型平衡即可

在代码的ClearRH函数中专门做调节,在s结点无右子树时返回一个TRUE,来表示让s的双亲的左孩子调整为NULL,其他递归回去,只需看是等高还是左高即可,一旦遇到等高将isshort变为false,然后不再需要调整,ClearRH代码如下

Status ClearRH(BSTree& T, bool& isshort, BSTree& S)
{
    if (T->lchild == NULL) {
        S = T;
        if(T->rchild) {
            T = T->rchild;
            isshort = true;
            return FALSE;
        }
        isshort = true;
        return TRUE;
    }
    else {
        if (T->bf == RH) {
            switch (T->rchild->bf) {
            case EH: {
                T->bf = EH;
                T->rchild->bf = LH;
                L_Rotate(T);
            }
            case RH: {
                T->bf = LH;
                T->rchild->bf = LH;
                L_Rotate(T);
            }
            }
        }
        if (ClearRH(T->lchild, isshort, S)) {
            T->lchild = NULL;
        }
        if (isshort) {
            if (T->bf == LH) {
                T->bf = EH;
            }
            else if (T->bf == EH) {
                T->bf = RH;
                isshort = false;
            }
            else {
                RightBalance(T);
                isshort = true;
            }
        }
        return FALSE;
    }
}

最后是删除结点后,递归回来情形比较简单和AVL树的插入类似,比较简单,在此不再赘述,代码如下

Status DeleteAVL_v2(BSTree& T, KeyType key, bool& isshort)
{
    if (T == NULL) {
        return FALSE;
    }
    else if (EQ(key, T->data.key)) {
        if (T->lchild == NULL && T->rchild == NULL) {
            free(T);
            T = NULL;
            isshort = true;
            return TRUE;
        }
        else if (T->lchild != NULL && T->rchild == NULL) {
            BSTree temp = T;
            T = T->lchild;
            free(temp);
            isshort = true;
            return TRUE;
        }
        else if (T->rchild != NULL && T->lchild == NULL) {
            BSTree temp = T;
            T = T->rchild;
            free(temp);
            isshort = true;
            return TRUE;
        }
        else {
            if (T->rchild->lchild == NULL) {
                BSTree temp = T;
                T->rchild->lchild = T->lchild;
                T = T->rchild;
                switch (temp->bf) {
                case LH: {
                    if (temp->lchild == EH) {
                        isshort = false;
                    }
                    LeftBalance(T);
                    break;
                }
                case EH:T->bf = LH; isshort = false; break;
                case RH:T->bf = EH; isshort = true; break;
                }
                free(temp);
                return TRUE;
            }
            else {
                BSTree temp = NULL;
                ClearRH(T->rchild, isshort, temp);
                temp->lchild = T->lchild;
                temp->rchild = T->rchild;
                BSTree ST = T;
                T = temp;
                if (isshort) {
                    switch (ST->bf) {
                    case LH: {
                        if (T->lchild->bf == EH) {
                            isshort = false;
                        }
                        LeftBalance(T);
                        break;
                    }
                    case RH:T->bf = EH; break;
                    case EH:T->bf = LH; isshort = false; break;
                    }
                }
                else {
                    T->bf = ST->bf;
                }
                free(ST);
                return TRUE;
            }
        }
    }
    else if (LT(key, T->data.key)) {
        if (DeleteAVL_v2(T->lchild, key, isshort)) {
            if (isshort) {
                switch (T->bf) {
                case LH:T->bf = EH; break;
                case EH:T->bf = RH; isshort = false; break;
                case RH: {
                    if (T->rchild->bf == EH) {
                        isshort = false;
                    }
                    RightBalance(T);
                    break;
                }
                }
            }
            return TRUE;
        }
        return FALSE;
    }
    else {
        if (DeleteAVL_v2(T->rchild, key, isshort)) {
            if (isshort) {
                switch (T->bf) {
                case RH:T->bf = EH; break;
                case EH:T->bf = LH; isshort = false; break;
                case LH: {
                    if (T->lchild->bf == EH) {
                        isshort = false;
                    }
                    LeftBalance(T);
                    break;
                }
                }
            }
            return TRUE;
        }
        return FALSE;
    }
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!