码迷,mamicode.com
首页 > 其他好文 > 详细

【Splay树】

时间:2016-02-25 23:00:10      阅读:361      评论:0      收藏:0      [点我收藏+]

标签:

伸展树英语:Splay Tree)是一种二叉查找树,它能在O(log n)内完成插入、查找和删除操作。它是由丹尼尔·斯立特Daniel Sleator)和罗伯特·塔扬在1985年发明的[1]

在伸展树上的一般操作都基于伸展操作:假设想要对一个二叉查找树执行一系列的查找操作,为了使整个查找时间更小,被查频率高的那些条目就应当经常处于靠近树根的位置。于是想到设计一个简单方法, 在每次查找之后对树进行重构,把被查找的条目搬移到离树根近一些的地方。伸展树应运而生。伸展树是一种自调整形式的二叉查找树,它会沿着从某个节点到树根之间的路径,通过一系列的旋转把这个节点搬移到树根去。

它的优势在于不需要记录用于平衡树的冗余信息。

                                                               ——来自维基百科

几个常用操作:

其实也不一定对。。。

 

rotate操作

技术分享
void rotate(int x,int &k) 
{
    int y = f[x], z = f[y], l, r;
    if (tr[y][0] == x) l = 0; else l = 1;
    r = l ^ 1;
    if (y == k) k = x;
    else
    {
        if (tr[z][0] == y) tr[z][0] = x;
            else tr[z][1] = x;
    }
    f[x] = z; f[y] = x; f[tr[x][r]] = y;
    tr[y][l] = tr[x][r]; tr[x][r] = y;    
}
rotate

把x向上旋转一个

r = l ^ 1; 01取反

 

 

splay操作

技术分享
void splay(int x,int &k)
{
    int y,z;
    while (x != k)
    {
        y = f[x]; z = f[y];
        if (y != k)
        {
            if ((tr[z][0] == y)^(tr[y][0] == x)) rotate(x,k);
                else rotate(y,k);
        }
        rotate(x,k);
    }
}
splay

把x转到k的位置
y !=k 至少要旋转两次,否则直接旋转一次x就行了
(tr[z][0] == y)^(tr[y][0] == x) 判断在不在一条直线上
  如果是的话,先旋转父节点,再旋转自己;否则先旋转自己,再旋转父节点(就是旋转两次自己)
因为调用了rotate,在rotate中k的值改变了,所以在这里也要加&

 

 

插入元素

技术分享
void ins(int &k,int x,int last)
{
    if (k == 0)
    {
        size ++; k = size; num[k] = x; f[k] = last; splay(k,rt); return;
    }
    if (x < num[k]) ins(tr[k][0],x,k);    else ins(tr[k][1],x,k);
}
insert

插入一个元素
操作完成后k的值会变成size,size会转到根,所以k的值要返回给rt,所以要加上&

 

 

删除元素

技术分享
void del(int x)
{
    splay(x,rt);
    if (tr[x][0] * tr[x][1] == 0)
        rt = tr[x][0] + tr[x][1];
    else
    {
        int k = tr[x][1];
        while (tr[k][0]) k = tr[k][0];
        tr[k][0] = tr[x][0]; f[tr[x][0]] = k;
        rt = tr[x][1];
    }
    f[rt] = 0;
}
delete

删除编号为x的结点
先旋转到根,如果只有一棵子树,直接删除,让子树的根作为根节点
否则寻找右子树中最小的那个点,作为根节点

 

 

寻找前驱

技术分享
void ask_before(int k,int x)
{
    if (k == 0) return;
    if (num[k] <= x)
    {
        t1 = k;
        ask_before(tr[k][1],x);
    }
    else ask_before(tr[k][0],x);
}
ask_before

 

寻找后继

技术分享
void ask_after(int k,int x)
{
    if (k == 0) return;
    if (num[k] >= x)
    {
        t2 = k;
        ask_after(tr[k][0],x);
    }
    else ask_after(tr[k][1],x);
}
ask_after

 

【Splay树】

标签:

原文地址:http://www.cnblogs.com/liumengyue/p/5218473.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!