• Splay算法旋转操作的模拟


    Splay算法旋转操作的模拟

    本篇随笔简单讲解一下Splay算法维护平衡树时的旋转操作。重点集中在如何模拟旋转。

    对Splay没有概念的同学请移步:

    Splay详解

    先上图再讲:

    1596012176397

    这是右旋。

    针对一个节点,我们需要维护它的父亲、两个儿子、值和子树大小这些信息。在本文中用以下符号表示:

    ch[x][0],ch[x][1]//x的左右儿子
    fa[x]//x的爹
    val[x]//x的值
    size[x]//x的子树大小
    

    我们观察旋转后的东西,发现对于全部节点来讲,他们的值都是没有变的(...)。所以我们不用修改值。

    然后我们发现对于部分节点(D,C),它们的爹和儿子包括子树大小都没有任何变化。这俩点就不用管。

    那么对于其他点来讲,我们需要按照上面这个图来进行模拟,修改它们的儿子、父亲和子树大小信息。怎么改呢?

    改的时候要遵循几个规则:

    首先,就是被赋值的信息,以后不能再被调用(因为已经被覆盖掉了),也就是变化的顺序问题。

    比如如果上面的右旋,我们先把B的右儿子改成A,再把A的左儿子改成E。我们发现做不到,因为当B的右儿子变成A之后,E就被覆盖掉了,换句话说,我们找不到E了,自然就没办法把A的左儿子改成E了。

    但是,如果先把A的左儿子改成E,再把B的右儿子改成A,因为B是我们要操作的节点,所以它无论如何是可以被找到的。这样我们就可以完成这个旋转的操作了。

    别忘了还要更新父亲的信息和子树信息。

    最后,还要特判,因为我们的Splay旋转还有单旋和双旋的区分,也就是说,虽然我们是三个点在旋转,但是在最后(马上到根节点)的情况下,是会出现只有两个点旋转的情况的,所以要特殊判断z节点(x节点的祖父节点)是否存在,存在的话才嫩更新其儿子,不存在的话没有儿子可以更新。

    所以,代码就是:

    void rotate(int x)
    {
    	int y=fa[x],z=fa[y];
    	int k=get(x);//get(x)查询x是y的什么儿子。
    	ch[y][k]=ch[x][k^1],ch[x][k^1]=y;
    	fa[y]=x,fa[x]=z,fa[ch[y][k]]=y;
    	if(z)
    		ch[z][ch[z][1]==y]=x;
    	maintain(y),maintain(x);
    }
    
  • 相关阅读:
    MyEclipse中选择一行的快捷键
    myeclipse选中一行的内容,快速移动复制到某一行。
    为什么做java的web开发我们会使用struts2,springMVC和spring这样的框架?
    webpack-dev-server
    webpack-clean-webpack-plugin
    --save-dev和--save的区别
    extract-text-webpack-plugin 的使用及安装
    this 指向详细解析(箭头函数)
    CSS三:CSS的三种引入方式
    Webpack中的css-loader 和style-loader
  • 原文地址:https://www.cnblogs.com/fusiwei/p/13403918.html
Copyright © 2020-2023  润新知