《树》之伸展树

Posted

tags:

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

本文介绍什么?

  1. 使用伸展树有什么样的效果;

  2. 伸展树的定义;

  3. 伸展树ADT具体实现过程的描述;

  4. 代码实现。





一、使用伸展树(splay tree)的效果:

              使用伸展树时,对伸展树上任意一次操作的最坏运行时间为 O( N );但是,它保证了连续M次操作花费的最多时间为O(M ㏒N),从而可以推算出对伸展树的每一次操作的摊还时间为O( ㏒N)。




二、伸展树的定义:

        对于一颗二查查找树进行操作时,每访问一个节点,该节点都通过旋转操作被放到根上。这样的一颗二查查找树称为伸展树。




三、伸展树ADT的描述:

        1.伸展树的节点定义与二查查找树节点定义的方法一致,此处不再赘述;

        2.比起二查查找树,伸展树ADT只是对了一个旋转操作。在这里的旋转,我们称之为展开(Splaying)。设节点X为访问的节点,我们通过对节点X进行一系列操作,将节点X移动到根节点。

        3.节点X旋转的情况:

             ⑴节点X为根节点:什么都不做;

             ⑵节点X的父节点为根节点:

                     根节点的左子树=X的右子树;

                     X的右子树=根节点;

             ⑶节点X具有父节点(P)、祖父节点(G),此时有(两类)四种情况需要考虑:

                     ⅰ、( "一" 字形) P是G的左儿子,X是P的左儿子;

                     ⅱ、( "一" 字形)P是G的右儿子,X是P的右儿子;

                     ⅲ、( "之" 字形)P是G的左儿子,X是P的右儿子;

                     ⅳ、( "之" 字形)P是G的右儿子,X是P的左儿子;

        4.节点的删除:

              由于对节点X的每一次访问都需要将X移向根节点,所以懒惰删除在这里显得不太合适,在这里需要进行的直接删除。当进行删除操作时,首先需要访问节点X,节点X被移动到根节点,此时删除X花费的代价是比较小的。在删除节点X的时候,①访问X导致节点X被移向根节点,删除节点X并得到左、右两棵子树(TL、TR);②在右子树TR上访问最小节点Y(该节点一定没有左儿子),将Y移动到右子树的根节点;③令Y的左儿子为左子树TL。

        



四、核心代码实现:

    1.伸展树的伸展实现

         ⅰ、( "一" 字形) P是G的左儿子,X是P的左儿子;

              操作:

                  G的左儿子=P的右儿子;

                  P的右儿子=G;

                  P的左儿子=X的右儿子;

                  X的右儿子=P;

//一字形(左左)

static Position ZigzigLL(Position g)
{
    Position p,x;
    p=g->left;x=p->left;
    
    g->left=p->right;
    p->right=g;
    p->left=x->right;
    x->right=p;
    
    return x;
}


ⅱ、( "一" 字形)P是G的右儿子,X是P的右儿子;

        操作:

            G的右儿子=P的左儿子;

            P的左儿子=G;

            P的右儿子=X的左儿子;

            X的左儿子=P; 

//一字形(右右)

static Position ZigzigRR(Position g)
{
    Position p,x;
    p=g->right;x=p->right;
    
    g->right=p->left;
    p->left=g;
    p->right=x->left;
    x->left=p;
    
    return x;
}

           

ⅲ、( "之" 字形)P是G的左儿子,X是P的右儿子;

        操作:

            G的左儿子=X的右儿子;

            X的右儿子=G;

            P的右儿子=X的左儿子;

            X的左儿子=P;

//一字形(左右)

static Position ZigzigLR(Position g)
{
    Position p,x;
    p=g->left;x=p->right;
    
    g->left=x->right;
    x->right=g;
    p->right=x->left;
    x->left=p;
    
    return x;
}


ⅳ、( "之" 字形)P是G的右儿子,X是P的左儿子;           

        操作:

            G的右儿子=X的左儿子;

            X的左儿子=G;

            P的左儿子=X的右儿子;

            X的右儿子=P;

//一字形(右左)

static Position ZigzigRL(Position g)
{
    Position p,x;
    p=g->right;x=p->left;
    
    g->right=x->left;
    x->left=g;
    p->left=x->right;
    x->right=p;
    
    return x;
}


    3.伸展树的删除操作实现

//删除节点
void Delete(const ElementType x,const sTree st)
{
    if(NULL==st) printf("该树为空树\n");
    else{
        position temp=Find(x,st);
        Position root=FindMin(temp->right);
        root->left=temp->left;
        
        free(temp);
        temp=NULL;
        return ;
    }
}

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

深度解析伸展树

BBST 之伸展树 (Splay Tree)

伸展树

学时总结◆学时·VI◆ SPLAY伸展树

算法学习:伸展树(splay)

伸展树基本概念基本题目