Splay讲解
来源:互联网 发布:淘宝怎样看自己的评价 编辑:程序博客网 时间:2024/05/17 08:22
伸展树(Splay Tree)是AVL树不错的替代,它有以下几个特点:
(1)它是二叉查找树的改进,所以具有二叉查找树的有序性。
(2)对伸展树的操作的平摊复杂度是O(log2n)。
(3)伸展树的空间要求、编程难度非常低。
提到伸展树,就不得不提到AVL树和Read-Black树,虽然这两种树能够保证各种操作在最坏情况下都为logN,但是两都实现都比较复杂。而在实际情况中,90%的访问发生在10%的数据上。因此,我们可以重构树的结构,使得被经常访问的节点朝树根的方向移动。尽管这会引入额外的操作,但是经常被访问的节点被移动到了靠近根的位置,因此,对于这部分节点,我们可以很快的访问。这样,就能使得平摊复杂度为logN。
1、自底向上的伸展树
伸展操作Splay(x,S)是在保持伸展树有序性的前提下,通过一系列旋转操作将伸展树S中的元素x调整至树的根部的操作。
在旋转的过程中,要分三种情况分别处理:
(1)Zig 或 Zag
(2)Zig-Zig 或 Zag-Zag
(3)Zig-Zag 或 Zag-Zig
1.1、Zig或Zag操作
节点x的父节点y是根节点。
1.2、Zig-Zig或Zag-Zag操作
节点x的父节点y不是根节点,且x与y同时是各自父节点的左孩子或者同时是各自父节点的右孩子。
1.3、Zig-Zag或Zag-Zig操作
节点x的父节点y不是根节点,x与y中一个是其父节点的左孩子而另一个是其父节点的右孩子。
2.以上的操作我们就可以将某一个节点进行相应的旋转,接下来叙述一下如何对于区间进行操作。
首先我们要知道,伸展树是具有有序性的,无论进行如何反转操作,有序性都不会被破坏掉。这样子就对我们的区间操作提供了很大的方便,假设要对于区间【L,R】进行操作,我们先把L-1反转到根节点处,再把R+1节点反转到根的右孩子处,这样很显然的目前R节点的左孩子的子树就是我们要处理的这段区间,由于边界问题,我们经常加入两个虚拟节点,分别是数列的头部和尾部,然后就可以方便的进行操作了,把一棵子树剪切,翻转等操作都可以利用这个性质很好的实现。有时候为了边界问题,我们会添加两个虚节点,分别作为序列的开始和结尾。接下来是我的splay的实现代码,仅供参考。
#define N 500000#define lc (tr[id].c[0])#define rc (tr[id].c[1])struct Tr { int fa, sum, val, c[2], lz;}tr[N];int newtr(int k, int f) {//新建立一个节点 tr[tot].sum = 1, tr[tot].val = k; tr[tot].c[0] = tr[tot].c[1] = -1; tr[tot].lz = 0; tr[tot].fa = f; return tot++;}void Push(int id) { int lsum, rsum; lsum = (lc == -1)?0:tr[lc].sum; rsum = (rc == -1)?0:tr[rc].sum; tr[id].sum = lsum+rsum+1;}void lazy(int id) {//懒操作 if (tr[id].lz) { swap(lc, rc); tr[lc].lz ^= 1, tr[rc].lz ^= 1; tr[id].lz = 0; }}int build(int l, int r, int f) {//建树 if (r < l) return-1; int mid = l+r>>1; int ro = newtr(data[mid], f); tr[ro].c[0] = build(l, mid-1, ro); tr[ro].c[1] = build(mid+1, r, ro); Push(ro); return ro;}void Rotate(int x, int k) { if (tr[x].fa == -1) return; int fa = tr[x].fa, w; lazy(fa), lazy(x); tr[fa].c[!k] = tr[x].c[k]; if (tr[x].c[k] != -1) tr[tr[x].c[k]].fa = fa; tr[x].fa = tr[fa].fa, tr[x].c[k] = fa; if (tr[fa].fa != -1) { w = tr[tr[fa].fa].c[1]==fa; tr[tr[fa].fa].c[w] = x; } tr[fa].fa = x; Push(fa); Push(x);}void Splay(int x, int goal) {//将x节点转到goal的儿子上 if (x == -1) return; lazy(x); while (tr[x].fa != goal) { int y = tr[x].fa; lazy(tr[y].fa), lazy(y), lazy(x); bool w = x==tr[y].c[1]; if (tr[y].fa != goal && w == (y==tr[tr[y].fa].c[1])) Rotate(y, !w); Rotate(x, !w); } if (goal == -1) root = x; Push(x);}int find(int k) {//找到第k哥节点的ID int id = root; while (id != -1) { lazy(id); int lsum = (lc==-1)?0:tr[lc].sum; if (lsum >= k) { id = lc; } else if (lsum+1 == k) break; else { k = k-lsum-1; id = rc; } } return id;}int Index(int l, int r) {//将区间【l+1, r-1】化成一颗子树 Splay(find(l),-1); Splay(find(r),root);}int Getnext(int id) {//寻找后继节点 lazy(id); int p = tr[id].c[1]; if (p == -1) return id; lazy(p); while (tr[p].c[0] != -1) { p = tr[p].c[0]; lazy(p); } return p;}int del(int l, int r) {//将【l,r】切掉,返回切掉子树的根节点 Index(l-1, r+1); int ro = KEY; tr[KEY].fa = -1; KEY = -1; Push(tr[root].c[1]); Push(root); return ro;}void cut(int k, int ro) {//将子树ro接到第k个树之后 Index(k, k+1); KEY = ro; tr[ro].fa = tr[root].c[1]; Push(tr[root].c[1]); Push(root);}void filp(int l, int r) {//对区间【l,r】反转 Index(l-1, r+1); lazy(root), lazy(tr[root].c[1]); tr[KEY].lz ^= 1;}void Add(int l, int r, int d) {//区间【l,r】的数加上d Index(l-1, r+1); tr[KEY].add += d; tr[KEY].mi += d; tr[KEY].val += d; Push(tr[root].c[1]); Push(root);}void Delete(int x) {//删除第x个数 Index(x-1, x+1); tr[KEY].fa = -1; tr[tr[root].c[1]].c[0] = -1; Push(tr[root].c[1]); Push(root);}void Insert(int l, int x) {//在l之后插入x Index(l, l+1); int ro; ro = newtr(x, tr[root].c[1]); KEY = ro; Push(tr[root].c[1]); Push(root);}void Revolve(int l, int r, int d) {//【l, r】整体右移d位 int ro = del(r+1-d, r); cut(l-1, ro);}
- Splay讲解
- splay讲解
- splay tree讲解
- Splay tree讲解+模板
- 平衡树之splay讲解
- 平衡树之splay讲解
- bzoj1500 修改数列 区间splay树讲解
- splay的各种操作与简易讲解
- SPLAY
- splay
- splay
- splay
- Splay
- Splay
- splay
- splay
- splay
- splay
- 二叉树遍历(前序,中序,后序)
- 通过Maven编译Robotium
- 火狐调试Silverlight(原)
- 由HDU 2955引发的有关01背包的思考
- Ubuntu下KVM的安装配置
- Splay讲解
- 网站开发-php开发手机论坛(4)-数据库设计
- 安全通信可以提供使用VPN
- 【Linux入门学习之】Linux连接文件:硬连接和软连接
- maven运行Robotium测试case
- Android联系人数据库全解析-2.0以上
- Android属性之build.prop生成过程分析
- Struts1和Struts2的区别和对比(完整版)
- 转载保存关于ros的一些有用网页