照刘汝佳黑书学了下$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;
}
原文:https://www.cnblogs.com/uid001/p/10428709.html