Splay Tree 伸展树
2010-04-20 19:19
260 查看
写在前面:我是巨菜……代码巨丑~请各种大牛不要鄙视……
Splay也就是传说中的伸展树~以前很想学,但是因为旋转比较晕,所以一直没学~这回因为决定学了,所以就看了看,写了写。经历了3个小时的摸索……终于写出来了……
首先说我用的题,是一道专门测平衡树的题:
给出N(N<=1000000)个操作,然后有N行,每行两个数,ch和k
ch=1表示插入一个值为k的数
ch=2表示查询第k小的数
ch=3表示删除值为k的数(k一定存在)
我之前的平衡树速度测试和学习都用的这道题(P.s.据说是陈启峰神牛的数据)。Splay是所以神奇就是因为它的灵活,我还是按照我的习惯来说说这个东西。想看的更具体一点呢,可以去看看sqybi神牛的经典Splay教程《The Magical Splay》(地址:http://www.oibh.org/bbs/viewthread.php?tid=23645&highlight=splay)
首先,平衡树的重要操作肯定少不了旋转,Splay的旋转就是个很悲剧的东西。因为splay的精髓在于把一个点旋转到任意一个位置,所以要记录每个点的父亲。但是一旦旋转中出现了父亲,很多东西都很IMBA~
还是一样,两种旋转ZIG和ZAG。ZIG(x)表示当x为它父亲的左儿子时,将x旋转到父亲的位置上的操作,ZAG则反之。(这个东西要认真写,差一点都会出大问题。)
然后就是伸展树的精髓,就是Splay(x,y)过程,就是将x旋转到y的儿子的位置,当y=0的时候旋转到根。这样就一共有6种情况,写写还可以。
然后就是怎么用它来维护树的平衡,说白了就是每次搞完了之后就将操作的那个点旋转到根去就好。所有操作中比较神奇的应该说是删除操作,首先找到您要删除的节点转到根上,然后找到比它大的最小的数和比它小的最大的数。(P.s.说白了就是找前驱和后继),这个时候要看这两个指针是否为空,如果是空,那么直接把root改下就好。反之,如果左右都有,那么将前驱转到根上,然后将后继转到前驱的右儿子上,细心的人这时候就发现,根的右儿子的左儿子只有一个元素,就是我们要删掉的那个元素。这样就结了,干掉这个点就好……
实测情况:
![](http://hi.csdn.net/attachment/201004/20/0_1271763143hZ12.gif)
P.s.skyprophet那个是我以前的treap,cqf那个是陈启峰神牛的SBT,splay就是我这会写的东西了。~~
【代码】:
Splay也就是传说中的伸展树~以前很想学,但是因为旋转比较晕,所以一直没学~这回因为决定学了,所以就看了看,写了写。经历了3个小时的摸索……终于写出来了……
首先说我用的题,是一道专门测平衡树的题:
给出N(N<=1000000)个操作,然后有N行,每行两个数,ch和k
ch=1表示插入一个值为k的数
ch=2表示查询第k小的数
ch=3表示删除值为k的数(k一定存在)
我之前的平衡树速度测试和学习都用的这道题(P.s.据说是陈启峰神牛的数据)。Splay是所以神奇就是因为它的灵活,我还是按照我的习惯来说说这个东西。想看的更具体一点呢,可以去看看sqybi神牛的经典Splay教程《The Magical Splay》(地址:http://www.oibh.org/bbs/viewthread.php?tid=23645&highlight=splay)
首先,平衡树的重要操作肯定少不了旋转,Splay的旋转就是个很悲剧的东西。因为splay的精髓在于把一个点旋转到任意一个位置,所以要记录每个点的父亲。但是一旦旋转中出现了父亲,很多东西都很IMBA~
还是一样,两种旋转ZIG和ZAG。ZIG(x)表示当x为它父亲的左儿子时,将x旋转到父亲的位置上的操作,ZAG则反之。(这个东西要认真写,差一点都会出大问题。)
然后就是伸展树的精髓,就是Splay(x,y)过程,就是将x旋转到y的儿子的位置,当y=0的时候旋转到根。这样就一共有6种情况,写写还可以。
然后就是怎么用它来维护树的平衡,说白了就是每次搞完了之后就将操作的那个点旋转到根去就好。所有操作中比较神奇的应该说是删除操作,首先找到您要删除的节点转到根上,然后找到比它大的最小的数和比它小的最大的数。(P.s.说白了就是找前驱和后继),这个时候要看这两个指针是否为空,如果是空,那么直接把root改下就好。反之,如果左右都有,那么将前驱转到根上,然后将后继转到前驱的右儿子上,细心的人这时候就发现,根的右儿子的左儿子只有一个元素,就是我们要删掉的那个元素。这样就结了,干掉这个点就好……
实测情况:
![](http://hi.csdn.net/attachment/201004/20/0_1271763143hZ12.gif)
P.s.skyprophet那个是我以前的treap,cqf那个是陈启峰神牛的SBT,splay就是我这会写的东西了。~~
【代码】:
{$M 655360000} program Project1; type ttype=record data,left,right,father,size,count:longint; end; var tree:array[0..1000000] of ttype; root,n,i,k,x,tot,now:longint; procedure modify(p:longint); begin tree[p].size:=tree[tree[p].left].size+tree[tree[p].right].size+tree[p].count; end; procedure zig(t:longint); var p:longint; begin p:=tree[t].father; tree[p].left:=tree[t].right; if tree[t].right<>0 then tree[tree[t].right].father:=p; tree[t].father:=tree[p].father; if tree[p].father<>0 then if tree[tree[p].father].left=p then tree[tree[p].father].left:=t else tree[tree[p].father].right:=t; tree[t].right:=p; tree[p].father:=t; modify(p); modify(t); end; procedure zag(t:longint); var p:longint; begin p:=tree[t].father; tree[p].right:=tree[t].left; if tree[t].left<>0 then tree[tree[t].left].father:=p; tree[t].father:=tree[p].father; if tree[p].father<>0 then if tree[tree[p].father].left=p then tree[tree[p].father].left:=t else tree[tree[p].father].right:=t; tree[t].left:=p; tree[p].father:=t; modify(p); modify(t); end; procedure splay(p,x:longint); begin while tree[p].father<>x do begin if tree[tree[p].father].father=x then begin if tree[tree[p].father].left=p then zig(p) else zag(p); end else begin if tree[p].father=tree[tree[tree[p].father].father].left then begin if tree[tree[p].father].left=p then begin zig(tree[p].father); zig(p); end else begin zag(p); zig(p); end; end else begin if tree[tree[p].father].left=p then begin zig(p); zag(p); end else begin zag(tree[p].father); zag(p); end; end; end; end; if x=0 then root:=p; end; procedure insert(var p:longint;x,fa:longint); begin if p=0 then begin inc(tot); p:=tot; tree[p].data:=x; tree[p].left:=0; tree[p].right:=0; tree[p].father:=fa; tree[p].size:=1; tree[p].count:=1; now:=p; end else if tree[p].data=x then inc(tree[p].count) else if x<tree[p].data then insert(tree[p].left,x,p) else insert(tree[p].right,x,p); modify(p); end; function find(p,x:longint):longint; begin if tree[p].data=x then exit(p) else if x<tree[p].data then exit(find(tree[p].left,x)) else exit(find(tree[p].right,x)); end; procedure delete(x:longint); var t1,t2,p:longint; begin p:=find(root,x); splay(p,0); if tree[p].count>1 then begin dec(tree[p].count); dec(tree[p].size); end else begin t1:=tree[p].left; while tree[t1].right<>0 do t1:=tree[t1].right; t2:=tree[p].right; while tree[t2].left<>0 do t2:=tree[t2].left; if t1=0 then begin root:=tree[p].right; tree[root].father:=0; exit; end; if t2=0 then begin root:=tree[p].left; tree[root].father:=0; exit; end; splay(t1,0); splay(t2,t1); tree[t2].left:=0; modify(t2); modify(t1); end; end; function findkth(p,x:longint):longint; begin if tree[tree[p].left].size>=x then exit(findkth(tree[p].left,x)) else if tree[tree[p].left].size+tree[p].count>=x then begin now:=p; exit(tree[p].data); end else exit(findkth(tree[p].right,x-tree[tree[p].left].size-tree[p].count)); end; begin assign(input,'sbt.in'); assign(output,'sbt.out'); reset(input); rewrite(output); readln(n); root:=0; tot:=0; for i:=1 to n do begin readln(k,x); case k of 1:begin insert(root,x,0); splay(now,0); end; 2:begin if tree[root].size>=x then begin writeln(findkth(root,x)); splay(now,0); end else writeln(0); end; 3:delete(x); end; end; close(input); close(output); end.
相关文章推荐
- 伸展树(Splay Tree)的旋转
- 伸展树 Splay Tree
- 伸展树(Splay Tree)尽收眼底
- 伸展树(Splay Tree)尽收眼底
- hdu 1754 splay tree伸展树 初战(单点更新,区间属性查询)
- 伸展树(Splay tree)学习小结 ---by---cxlove
- Splay Tree(伸展树)
- 伸展树(Splay tree)
- 伸展树(Splay Tree)
- Splay Tree - 伸展树
- 伸展树(splay tree)自顶向下的算法
- 伸展树splay tree
- splay tree(伸展树)
- 伸展树(Splay tree)
- 伸展树(Splay tree)
- Splay Tree(伸展树)[NOI2005]维修数列
- UVA 11922 Permutation Transformer(伸展树 Splay Tree)
- 纸上谈兵: 伸展树 (splay tree)[转]
- hdu 1754 splay tree伸展树 初战(单点更新,区间属性查询)
- 伸展树(splay tree)实现