照刘汝佳黑书学了下$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
时间: 2024-10-27 14:35:14