伸展树(Splay tree)学习小结 ---by---cxlove

转载 2015年02月25日 17:43:42

转载请注明出处,谢谢 http://blog.csdn.net/ACM_cxlove?viewmode=contents           by---cxlove

总结一下最近学习的Splay tree。万事开头难啊,像这种神一样的数据结构,刚学是很痛苦的,建议之前要把平衡树,SBT之类的数据结构先学学。

资料都是网上乱翻的,前一两道题,代码主要追随别人,后面慢慢的调整,成为自己的东西。

Splay tree意为伸展树,和别的不同的正是在于它的伸展操作。

在这里,我也证明,解释不了伸展树在时间复杂度,操作上的优势之类的。网上很正规的资料里都会有介绍

伸展树并不是严格意义上的平衡树,也还是极有可能退化成线性结构,但他的伸展操作能使它的每一次操作近似(logn),而且独特的伸展操作能解决一些其它数据结构实现不了的(如线段树,SBT等)。

先说伸展操作,在我的理解中,伸展操作和平衡树的保持平衡是类似的,只不过他不要求保持平衡,只是相应的旋转。

如果旋转的节点的父节点便是目标结点,那么一次旋转即可。但是在平衡树中这一步还要拆开。

举例:现在要将根结点的左孩子右旋操作,而此时如果根的左孩子存在右孩子的话,那么直接旋转过去,新的根便有两个左孩子,显然不可以,所以将左子树先执行左旋,再右旋即可。

如果在伸展树中,父节点并不是目标结点,那就存在爷爷结点,如果爷爷结点和父节点方向一样,那么连续两次上面的右旋或者左旋即可。如果方向不一样,便是一左一右两次旋转。画图比较好理解,大家可以从别的资料中找到图,在伸展树中称为一字型和之字型。虽然说的很复杂,但是在Splay中,代码已经被前辈们优化到很短,很精练。

 

 

void Rotate(int x,int kind){   //kind分别代表左右旋 
    int y=pre[x];      
    Push_Down(y);  
    Push_Down(x);  
    ch[y][!kind]=ch[x][kind];     
    pre[ch[x][kind]]=y;    
    if(pre[y])    
        ch[pre[y]][ch[pre[y]][1]==y]=x;    
    pre[x]=pre[y];    
    ch[x][kind]=y;    
    pre[y]=x;    
    Push_Up(y);    
}     
//将节点r旋转至goal
void Splay(int r,int goal){    
    Push_Down(r);  
    while(pre[r]!=goal){    
        if(pre[pre[r]]==goal)    
            Rotate(r,ch[pre[r]][0]==r);    
        else{    
            int y=pre[r];    
            int kind=(ch[pre[y]][0]==y);    
            if(ch[y][kind]==r){    
                Rotate(r,!kind);    
                Rotate(r,kind);    
            }    
            else{    
                Rotate(y,kind);    
                Rotate(r,kind);    
            }    
        }    
    }    
    Push_Up(r);    
    if(goal==0) root=r;    
}

 

这样的伸展操作对于我们的区间操作有什么优势呢。

可以想一个问题,对于一个区间[l,r],对于平衡树,SBT,如果很快定位到这个区间是很困难的,面对于线段树是可以做到的,那么如果要把区间进行删除,旋转,线段树便做不到了。

接下来看看Splay tree是怎么做的,首先伸展树本质还是个二叉查找树。做法也很简单,将第l-1个结点旋转至根(之前的Splay操作),将第r+1个结点旋转至根的右孩子,那么根据二叉查找树我们知道,在这两个结点之间,也是根的右孩子的左子树就包括节点[l,r],我们便很快定位,如果需要删除,直接便可以把子树拿走。其中Get_Kth表示找到第K个结点,记录子树的大小,便可以很快实现。

 

int Get_interval(int l,int r){
	Splay(Get_Kth(l-1),0);
	Splay(Get_Kth(r+1),root);
	Push_Up(ch[root][1]);
	Push_Up(root);
}

 

 

这个函数便可以很快找到区间[l,r]执行之后的根的右孩子的左子树便是所要区间,便可以进行操作。 

伸展树也可以完成线段树的一些工作,也可以设置延迟标记,向上更新,向下更新等等。具体的在后面的练习中会遇到。


接下来是一些练习。

入门题:可以找一些线段树,或者别的数据结构练练手,操作少,简单。线段树这里有


之后我自己做的一些训练,大多是从这里参考来的

[HNOI2002]营业额统计 

第一个Splay,多种数据结构可解。其中主要操作是找到前驱和后继,作为一棵二叉查找树,这并不困难。一个节点的后继,便是右子树中的最左的结点,前驱便是左子树中最右边的节点。

题解这里有


POJ 3468 A Simple Problem with Integers 

 

比较经典的线段树题目。将区间先插入到树中,开始便保证有序,之后的操作不改变顺序,注意懒惰标记

题解这里有


 

HDU 1890 Robotic Sort


 

之前便排好序,依次保存好下标。依次考虑第K大的,将其旋转至根,左子树的数量便是需要反转的,之后把根删除即可。

题解这里有


HDU 3436 Queue-jumpers 


 

重点在于需要离散化,将TOP和QUERY操作的节点拿出来,中间不同的区间缩成点。

 

题解这里有


HDU 3487 Play with Chain

出现了一个新的操作,CUT。就是旋转,然后删除,然后插入,犀利

题解这里有


[AHOI2006]文本编辑器editor 


 

保存光标位置,也就是第K大的位置,之后都是Splay经典操作

题解这里有


[NOI2005]维修数列 

NOI里非常BT的数据结构题,不过不做过此题,Splay的学习怎么能算完整呢。

其它的都类似,有个最大子列和,不过也类似于线段树里的经典操作

题解这里有


POJ 3580 SuperMemo 


 

有个独特的操作,REVOLVE,右移操作,其实就是找到区间,分成两段,删除和插入。

 

题解这里有

 

Splay伸展树模板总结

1.基本点操作 //Splay 基本操作 均摊复杂度O(lgN) //POJ 1442 //基本点操作 // sp.init() 初始化 #include #include #in...
  • snk1996
  • snk1996
  • 2015年09月04日 16:20
  • 778

伸展树(Splay tree)图解与实现

一、伸展树  本文介绍了二叉查找树的一种改进数据结构–伸展树(Splay Tree)。它的主要特点是不会保证树一直是平衡的,但各种操作的平摊时间复杂度是O(log n),因而,从平摊复杂度上看,二叉...
  • u014634338
  • u014634338
  • 2015年11月02日 16:20
  • 3264

数据结构实现之Splay伸展树

Splay Tree 是二叉查找树的一种,它与平衡二叉树、红黑树不同的是,Splay Tree从不强制地保持自身的平衡,每当查找到某个节点n的时候,在返回节点n的同时,Splay Tree...
  • qing0706
  • qing0706
  • 2016年02月03日 23:27
  • 798

查找——图文翔解SplayTree(伸展树)

伸展树 伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它由Daniel Sleator和Robert Tarjan创造,后者对其进行了改进。 假设想要对一个二叉查找树执行一系列的查...
  • yang_yulei
  • yang_yulei
  • 2015年05月27日 00:05
  • 5685

Splay Tree(伸展树)

参考:《数据结构(C++语言版)》邓俊辉著 (好书 一、 伸展树(由 D. D. Sleator 和 R. E. Tarjan 于 1985 年发明)也是平衡二叉搜索树的一种形式。相对于 AVL 树...
  • Only_AiR
  • Only_AiR
  • 2016年09月06日 19:23
  • 1682

AVL树、splay树(伸展树)和红黑树比较

一、AVL树: 优点:查找、插入和删除,最坏复杂度均为O(logN)。实现操作简单     如过是随机插入或者删除,其理论上可以得到O(logN)的复杂度,但是实际情况大多不是随机的。如果是随机的,则...
  • u010585135
  • u010585135
  • 2014年12月10日 21:58
  • 2532

[Splay伸展树]splay树入门级教程

本弱鸟对于SPLAY树的一些理解。。。
  • u013591931
  • u013591931
  • 2014年02月28日 20:48
  • 9027

伸展树splay之求区间极值

伸展树splay之求区间极值
  • chen1352
  • chen1352
  • 2016年09月29日 19:07
  • 285

初学伸展树区间建树(A Simple Problem with Integers)

一.几个重要概念 1.伸展树属于一种平衡树,也是一棵普通的二叉排序树。 2.伸展树的核心在于它的伸展(splay)操作,对于每一次的伸展操作(把某个节点放到目标节点的下面),都有可能改变树中每个节点...
  • Forever_wjs
  • Forever_wjs
  • 2016年02月21日 11:27
  • 284

HDU 1166 敌兵布阵 伸展树splay简单练手题

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1166题意:C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了...
  • discreeter
  • discreeter
  • 2016年10月23日 13:47
  • 447
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:伸展树(Splay tree)学习小结 ---by---cxlove
举报原因:
原因补充:

(最多只允许输入30个字)