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

Treap

时间:2015-03-31 14:40:38      阅读:226      评论:0      收藏:0      [点我收藏+]

标签:算法   algorithm   acm   

Treap

        Treap是一种动态平衡的BST(Binary Search Tree),它每个节点拥有键值和优先级两种属性。对于键值而言,它是一颗排序二叉树。对于优先级而言,这棵树是堆(优先级最高的是根节点)。可以证明Treap中插入,删除和查找的期望时间复杂度均为O(logn)。关于Treap的更多介绍,可见刘汝佳《训练指南》P230。

一般我们用Treap就是用来替代平衡二叉排序树用的。

         Treap实现的代码很少,实现简单。我们可以在Treap的基础上实现名次树。

         名次树支持两个操作:

        1)找出第k小的元素(元素从小到大排序的第k个)。

        2)找到值x的名次。

Treap基本代码:

<span style="font-size:18px;">#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;

struct Node
{
    Node *ch[2];
    int r;//优先级,构成大顶堆
    int v;//键值,构成排序二叉树

    int cmp(int x)//比较键值大小
    {
        if(x==v) return -1;
        return x<v?0:1;
    }
};

//d=0表示左旋,d=1表示右旋
void rotate(Node* &o,int d)
{
    Node *k=o->ch[d^1];
    o->ch[d^1]=k->ch[d];
    k->ch[d]=o;
    o=k;
}

//插入值为x的节点
void insert(Node* &o,int x)
{
    if(o==NULL)
    {
        o=new Node();
        o->ch[0]=o->ch[1]=NULL;
        o->v=x;
        o->r=rand();//在cstdlib头声明
    }
    else
    {
        //如这里改成int d=o->cmp(x);
        //就不可以插入相同的值,因为d可能为-1
        int d=x<(o->v)?0:1;
        insert(o->ch[d],x);
        if(o->ch[d]->r > o->r)
            rotate(o,d^1);
    }
}

//删除v值为x的节点
void remove(Node *&o,int v)
{
    if(o==NULL) return ;//空时返回

    int d=o->cmp(v);
    if(d==-1)//o就是需要删除的节点
    {
        Node *u=o;
        if(o->ch[0] && o->ch[1])
        {
            int d2 = o->ch[0]->r < o->ch[1]->r ?0:1;
            rotate(o,d2);
            remove(o->ch[d2],v);
        }
        else
        {
            if(o->ch[0]==NULL)o=o->ch[1];
            else o=o->ch[0];
            delete u;//记得删除节点
        }
    }
    else remove(o->ch[d],v);
}
int find(Node *o,int x)
{
    while(o)
    {
        int d=o->cmp(x);
        if(d==-1)return 1; //存在
        o=o->ch[d];
    }
    return 0;              //不存在
}
</span>

Treap实现名次树的代码:

<span style="font-size:18px;">#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cassert>
using namespace std;
struct Node
{
    Node *ch[2];
    int r,v,s;//s表示节点数

    Node(int v):v(v)
    {
        ch[0]=ch[1]=NULL;
        r=rand();//在cstdlib头声明
        s=1;
    }

    int cmp(int x)
    {
        if(x==v)return -1;
        return x<v?0:1;
    }
    void maintain()
    {
        s=1;
        if(ch[0]!=NULL) s+=ch[0]->s;
        if(ch[1]!=NULL) s+=ch[1]->s;
    }
};
void rotate(Node* &o,int d)
{
    Node *k=o->ch[d^1];
    o->ch[d^1]=k->ch[d];
    k->ch[d]=o;
    o->maintain();
    k->maintain();
    o=k;
}
void insert(Node* &o,int x)//o子树中事先不存在x
{
    if(o==NULL) o=new Node(x);
    else
    {
        //如这里改成int d=o->cmp(x);
        //就不可以插入相同的值,因为d可能为-1
        int d=x<(o->v)?0:1;
        insert(o->ch[d],x);
        if(o->ch[d]->r > o->r)
            rotate(o,d^1);
    }
    o->maintain();
}

void remove(Node* &o,int x)
{
    if(o==NULL) return ;//空时返回

    int d=o->cmp(x);
    if(d==-1)
    {
        Node *u=o;
        if(o->ch[0] && o->ch[1])
        {
            int d2=(o->ch[0]->r < o->ch[1]->r)?0:1;
            rotate(o,d2);
            remove(o->ch[d2],x);
        }
        else
        {
            if(o->ch[0]==NULL) o=o->ch[1];
            else o=o->ch[0];
            delete u;//这个要放里面
        }
    }
    else remove(o->ch[d],x);
    if(o) o->maintain();//之前o存在,但是删除节点后o可能就是空NULL了,所以需要先判断o是否为空
}

//返回关键字从小到大排序时的第k个值
int kth(Node* o,int k)
{
    assert(o && k>=1 && k<=o->s);//保证输入合法
    int s=(o->ch[0]==NULL)?0:o->ch[0]->s;
    if(k==s+1) return o->v;
    else if(k<=s) return kth(o->ch[0],k);
    else return kth(o->ch[1],k-s-1);
}

//返回值x在树中的排名,就算x不在o树中也能返回排名
//返回值范围在[1,o->s+1]范围内
int rank(Node* o,int x)
{
    if(o==NULL) return 1;//未找到x;

    int num= o->ch[0]==NULL ? 0:o->ch[0]->s;
    if(x==o->v) return num+1;
    else if(x < o->v) return rank(o->ch[0],x);
    else return rank(o->ch[1],x)+num+1;
}


int main()
{
    int n=0;
    while(scanf("%d",&n)==1 && n)
    {
        Node *root=NULL;
        for(int i=0;i<n;i++)
        {
            int x;
            scanf("%d",&x);
            if(root==NULL) root=new Node(x);
            else insert(root,x);
        }

        int v;
        while(scanf("%d",&v)==1)
        {
            printf("%d\n",rank(root,v));
        }
    }
    return 0;
}
</span>

Treap应用

POJ 1442 Black Box(Treap):Treap名次树应用。解题报告!

POJ 3481 Double Queue(Treap):平衡二叉树基本应用。解题报告!

POJ 2761 Feed the dogs(Treap名次树+离线处理):如何解决区间第k大的数的询问?解题报告

POJ 2985 The k-th LargestGroup(Treap+并查集):同时用并查集且维护名次树。解题报告

 

 

 

 

Treap

标签:算法   algorithm   acm   

原文地址:http://blog.csdn.net/u013480600/article/details/44779293

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