今天好好研究了下传说中的Splay,如果真的比Treap强大的话那就将常用的平衡树换成Splay。

看了一上午别人的论文什么的,又在纸上反复的做了推理,下午尝试着将几个不同的Splay写法进行整理,晚上的时候用splay解决了几个问题。总体来讲,splay的确是一个非常强大的数据结构。当做平衡树只是它的用处之一,作为“伸展树”,它还能做些别人做不了的事情。

首先把今天的结论放在最前面:(只是个人的看法,因为对Splay了解不多,有错误请指出,万分感激)

1.splay的旋转操作与Treap是完全相同的(或者说二叉平衡树都是相同的), 唯一的不同就是Splay有其独特的操作“伸展”。这也就意味着Splay的代码量稍微大一些,速度也稍微慢一些,但是其功能比treap强大而且不需要维护额外的随机值。如果题目仅仅需要进行一下非常基本,如插入,查找,删除之类的基本平衡树操作。那treap应该还是首选,因为treap的维护实在是太简单了。不过一旦涉及到一下较为特殊的操作,那就只能用splay了。

2.另外一个经常与splay进行对比的就是线段树了,与treap和splay相反的是,好像在维护区间这方面,splay的要比线段树快上那么一些。splay的常数比线段树大太多了,能用线段树的时候不要用splay了,虽然splay的维护操作很神奇。但是同样的,因为线段树的结构和操作实在是太简单了,所以代码量要比splay少那么一个级别吧。

 综上所述,当遇到基本的操作时,treap和线段树因为其优秀的代码复杂度应该是首选,但是一旦出现比较复杂或是比较奇特的维护时,就应该用splay在强行乱搞来解决。我一下在想起来去年zbwmqlw神牛给我们讲课讨论的时候,碰到一道数据结构题目的时候,最常用的一句话就是:“呀,用splay硬搞一下就行了。”splay的功能真是强大的太过分了。不过,话说回来,上面说这么多,只是对我像我一样的普通人,对于像nehzilrz这样的神驼来说,完全不存在这样的问题。(强烈不建议初学者观看)

 1 //第一个是自下而上的,25行(ps.这个是有双旋的……)
 2 
 3 struct node {
 4     int key,sz;
 5     bool is_root;
 6     #define lc c[0]
 7     #define rc c[1]
 8     node *c[2],*f;
 9     node();
10     void update(){ sz=lc->sz+rc->sz+1; }
11 }TNode[MAXN],*nil=TNode,*PN=TNode+1;
12 node::node(){ lc=rc=f=nil; sz=is_root=0; }
13 
14 void zig(node* y,bool w) {
15     node *x=y->f; y->f=x->f;
16     if (x->is_root) x->is_root=0, y->is_root=1else
17     if (x==x->f->lc) y=x->f->lc; else y=x->f->rc;
18     x->c[w]=y->c[!w]; x->c[w]->f=x; y->c[!w]=x; x->f=y;
19     x->update();
20 }
21 
22 void splay(node *x) {
23     while (!x->is_root) {
24         node *y=x->f; bool w=x==y->rc;
25         if (!y->is_root && w==(y==y->f->rc)) zig(y,w);
26         zig(x,w);
27     }
28     x->update();
29 }

相关文章:

  • 2021-10-27
猜你喜欢
  • 2021-05-28
  • 2021-08-18
  • 2021-05-22
  • 2021-12-05
  • 2022-01-21
  • 2022-02-23
  • 2021-07-24
相关资源
相似解决方案