splay树(伸展树):
概述:二叉查找树的一种改进数据结构,为了使整个查找时间更小,被查频率高的那些节点应当经常处于靠近树根的位置;因此,每次查找节点之后对树进行重构,把被查找的节点搬移到树根,这种自调整形式的二叉查找树就是伸展树。
平摊时间复杂度:O(logn)
基本操作:通过旋转的方法把被访问节点旋转到树根的位置,同时不打乱数列中数据大小关系(指中序遍历结果是全序的),伸展树主要有三种旋转操作:单旋转,一字形旋转和之字形旋转。
代码:(旋转操作)
void rotate(long x,int kind)
//kind=0表示左旋,kind=1表示右旋 ch[X][0..1]表示X的左儿子和右儿子
{
long y=father[x]; long z=father[y];
ch[y][!kind]=ch[x][kind];
if(!ch[x][kind])
father[ch[x][kind]]=y;
father[x]=z;
if(z!=-1)
ch[z][ch[z][1]==y]=x;
father[y]=x; ch[x][kind]=y;
}
代码:(Splay操作)
void splay(long x)
{
while(father[x]!=-1)
{
long y=father[x]; long z=father[y];
if(z==-1)//单旋转
rotate(x,ch[y][0]==x);
else
{
if(ch[z][0]==y)//一字形旋转
{
if(ch[y][0]==x)
rotate(y,1),rotate(x,1);
else
rotate(x,0),rotate(x,1);
}
else//之字形旋转
{
if(ch[y][1]==x)
rotate(y,0),rotate(x,0);
else
rotate(x,1),rotate(x,0);
}
}
}
root=x;
}
应用:
1. 插入:在当前数列第posi 个数字后面插入tot 个数字;若在数列首位插入,则posi 为0。
2. 删除:从当前数列第posi 个数字开始连续删除tot 个数字。
3. 修改:从当前数列第posi 个数字开始连续tot 个数字统一修改为c 。
4. 翻转:取出从当前数列第posi 个数字开始的tot 个数字,翻转后放入原来的位置。
5. 求和:计算从当前数列第posi 个数字开始连续tot 个数字的和并输出。
6. 求和最大子序列:求出当前数列中和最大的一段子序列,并输出最大和。
未完待续...