关闭

AVL树笔记(二):maintain,delete

标签: 数据结构
256人阅读 评论(0) 收藏 举报
分类:

先是maintain操作,它可以维护AVLTree的平衡。
有了maintain,AVLTree的insert和delete就可以不马上维护平衡,而是操作完再维护平衡了。

void maintain(int &r)
{
    if(tree[tree[r].lc].h==tree[tree[r].rc].h+2)
    {
        int t=tree[r].lc;
        if(tree[tree[t].lc].h==tree[tree[r].rc].h+1)r=zig(r);
        else if(tree[tree[t].rc].h==tree[tree[r].rc].h+1)r=zagzig(r);
    }
    else if(tree[tree[r].rc].h==tree[tree[r].lc].h+2)
    {
        int t=tree[r].rc;
        if(tree[tree[t].rc].h==tree[tree[r].lc].h+1)r=zag(r);
        else if(tree[tree[t].lc].h==tree[tree[r].lc].h+1)r=zigzag(r);
    }
    tree[r].h=max(tree[tree[r].lc].h,tree[tree[r].rc].h)+1;
}

仔细看会发现和昨天的insert的维护平衡比较相似。
就是这次不能凭借tree[r].v和插入值x来比较x在左子树还是右子树了,要根据h来判断。
然后insert就是二叉查找树的insert了:

int insert(int r,int x)
{
    if(r==0)
    {
        tree[++cnt].v=x;
        tree[cnt].h=1;
        return cnt;
    }
    if(tree[r].v>x)tree[r].lc=insert(tree[r].lc,x);
    else if(tree[r].v<x)tree[r].rc=insert(tree[r].rc,x);
    maintain(r);
    return r;
}

接下来是delete操作:
首先我们要find,find到了再delete。
要delete的点如果是叶子,那么直接删掉,如果只有一个儿子,那么把这个点删掉,把它的父亲直接连到它的儿子。
如果左右儿子都有,就比较麻烦了。
可以找到它的前驱,把这个点的值修改成前驱的值,最后删掉前驱。
可以证明的是,前驱一定不存在有左右2个儿子都有的状况。
可行是因为删掉这个点,前驱就会上来。还不如直接把这个点改成前驱,再删掉以前那个前驱。
实际实现可以参考find。
find到了,如果是前2种状况,那么删掉,如果是第三种,那么递归删去当前点的前驱。
删完记得维护h值。

int del(int &r,int x)
{
    int tv;
    if(x==tree[r].v||(x<tree[r].v&&tree[r].lc==0)||(x>tree[r].v&&tree[r].rc==0))
    {
        if(tree[r].lc==0||tree[r].rc==0)
        {
            tv=tree[r].v;
            r=tree[r].lc+tree[r].rc;
            return tv;
        }
        else tree[r].v=del(tree[r].lc,x);
    }
    else
    {
        if(tree[r].v>x)tv=del(tree[r].lc,x);
        else tv=del(tree[r].rc,x);
    }
    maintain(r);
    return tv;
}

不要直接调用求前驱的函数,貌似时间复杂度会变大= =

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:26697次
    • 积分:855
    • 等级:
    • 排名:千里之外
    • 原创:60篇
    • 转载:1篇
    • 译文:0篇
    • 评论:12条
    最新评论