splay简单入门

照刘汝佳黑书学了下$splay$, 简单总结一下.

$splay$每次操作不保证复杂度, 但均摊每次是$O(logn)$的.

$splay$基本思想是每个结点被访问时, 使用$AVL$的旋转操作把它移动到根.$splay$的旋转与$AVL$的区别主要是由于$splay$的旋转是自底向上的, 所以需要设置父亲指针, 而不像$AVL$树那样以儿子为轴旋转.

$splay$核心是函数$splay(x,S)$. 它的作用是保证splay结构的情况将$x$旋转到根, 旋转过程要分三种情况讨论.

1, 节点$x$是的父结点$y$是根节点.

这时, 若$x$是$y$的左儿子则右旋, 若$x$是$y$的右儿子则左旋.

2, 节点$x$的父节点$y$不是根节点, 且$x$与$y$同时是各自父节点的左孩子或者同时是各自父节点的右儿子.

这时, 同时右旋两次, 或者左旋两次.

3, 节点$x$的父节点$y$不是根节点, 且$x$与$y$一个是其父节点的左儿子, 另一个为父节点的右儿子.

这时, 先右旋后左旋, 或者先左旋后右旋

void splay(int& x, int& s) {
    int p; 
    while (father[x]) {
        p = father[x]; 
        if (!father[p]) {
            if(x == left[p]) RightRotate(x);
            else LeftRotate(x);
            break;
        }
        if (x == left[p]) {
            if(p == left[father[p]]) {
                RightRotate(p);
                RightRotate(x);
            }
            else { 
                RightRotate(x);
                LeftRotate(x);
            }
        }
        else {
            if(p == right[father[p]]) {
                LeftRotate(p);
                LeftRotate(x);
            } 
            else {
                LeftRotate(x);
                RightRotate(x);
            }                                                       
        }
    }
    s = x;
}

猜你喜欢

转载自www.cnblogs.com/uid001/p/10428709.html