treap树模版

 白书中对treap的删除讲的不是很详尽,这里转载个补充(from:点击打开链接):

我们知道,二叉查找树相对来说比较容易形成最坏的链表情况,所以前辈们想尽了各种优化策略,包括AVL,红黑,以及今天

要讲的Treap树。

       Treap树算是一种简单的优化策略,这名字大家也能猜到,树和堆的合体,其实原理比较简单,在树中维护一个"优先级“,”优先级“

采用随机数的方法,但是”优先级“必须满足根堆的性质,当然是“大根堆”或者“小根堆”都无所谓,比如下面的一棵树:




从树中我们可以看到:

①:节点中的key满足“二叉查找树”。

②:节点中的“优先级”满足小根堆。

节点里面定义了一个priority作为“堆定义”的旋转因子,因子采用“随机数“。

 

2:添加

    首先我们知道各个节点的“优先级”是采用随机数的方法,那么就存在一个问题,当我们插入一个节点后,优先级不满足“堆定义"的

时候我们该怎么办,前辈说此时需要旋转,直到满足堆定义为止。

旋转有两种方式,如果大家玩转了AVL,那么对Treap中的旋转的理解轻而易举。

①: 左左情况旋转


从图中可以看出,当我们插入“节点12”的时候,此时“堆性质”遭到破坏,必须进行旋转,我们发现优先级是6<9,所以就要进行

左左情况旋转,最终也就形成了我们需要的结果。

 

②: 右右情况旋转

既然理解了”左左情况旋转“,右右情况也是同样的道理,优先级中发现“6<9",进行”右右旋转“最终达到我们要的效果。

3:删除

  跟普通的二叉查找树一样,删除结点存在三种情况。

①:叶子结点

      跟普通查找树一样,直接释放本节点即可。

②:单孩子结点

     跟普通查找树一样操作。

③:满孩子结点

    其实在treap中删除满孩子结点有两种方式。

第一种:跟普通的二叉查找树一样,找到“右子树”的最左结点(15),拷贝元素的值,但不拷贝元素的优先级,然后在右子树中

           删除“结点15”即可,最终效果如下图。

第二种:将”结点下旋“,直到该节点不是”满孩子的情况“,该赋null的赋null,该将孩子结点顶上的就顶上,如下图:

4:总结

treap树在CURD中是期望的logN,由于我们加了”优先级“,所以会出现”链表“的情况几乎不存在,但是他的Add和Remove相比严格的

平衡二叉树有更少的旋转操作,可以说性能是在”普通二叉树“和”平衡二叉树“之间。


const int maxn=30000+1000;
int ch[maxn][2],val[maxn],counts[maxn],r[maxn],size[maxn],tot,root;
void Newnode(int &rt,int v)
{
    rt=++tot;
    val[rt]=v;
    ch[rt][0]=ch[rt][1]=0;
    counts[rt]=size[rt]=1;
    r[rt]=rand();
}
inline void PushUp(int rt)
{
    size[rt]=size[ch[rt][0]]+size[ch[rt][1]]+counts[rt];
}
void Rotate(int &x,int kind)
{
    int y=ch[x][kind^1];
    ch[x][kind^1]=ch[y][kind];
    ch[y][kind]=x;
    PushUp(x);PushUp(y);
    x=y;
}
void Insert(int &rt,int v)
{
    if(rt==0)
    {
        Newnode(rt,v);
        return ;
    }
    if(v==val[rt]) counts[rt]++;
    else
    {
        int kind=(v>val[rt]);
        Insert(ch[rt][kind],v);
        if(r[ch[rt][kind]]<r[rt])
            Rotate(rt,kind^1);
    }
    PushUp(rt);
}
int select(int rt,int k)
{
    if(size[ch[rt][0]]>=k) return select(ch[rt][0],k);
    if(size[ch[rt][0]]+counts[rt]>=k) return val[rt];
    return select(ch[rt][1],k-size[ch[rt][0]]-counts[rt]);
}
void remove(int &rt,int v)
{
    if(val[rt]==v)
    {
        if(counts[rt]>1)
            counts[rt]--;
        else if(!ch[rt][0]&&!ch[rt][1])
        {rt=0;return ;}
        else
        {
            int kind=r[ch[rt][0]]<r[ch[rt][1]];
            Rotate(rt,kind);
            remove(rt,v);
        }
    }
    else remove(ch[rt][v>val[rt]],v);
    PushUp(rt);
}
void Init()
{
    ch[0][0]=ch[0][1]=0;
    size[0]=counts[0]=val[0]=0;
    tot=root=0;
    r[0]=(1LL<<31)-1;
    Newnode(root,2000000001);
}

#define N 20005  
struct Treap{  
	Treap *ch[2];  
	int r;          //数字越大,优先级越高  
	int v;          //值  
	int size;       //子树的节点数  
	Treap(int v):v(v) { ch[0]=ch[1]=NULL; r=rand(); size=1;}  
	bool operator < (const Treap& rhs) const{  
		return r < rhs.r;  
	}  
	int cmp(int x) const{  
		if(x == v)return -1;  
		return x < v ? 0 : 1;  
	}  
	void maintain(){  //以该点为根的子树节点数(包括自己)
		size = 1;  
		if(ch[0] != NULL) size += ch[0]->size;  
		if(ch[1] != NULL) size += ch[1]->size;  
	}  
};  
Treap* root[N];  

void rotate(Treap* &o, int d){  
	Treap* k = o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d] = o;  
	o->maintain(); k->maintain(); o = k;  
}  

void insert(Treap* &o, int x){  
	if(o == NULL)  o = new Treap(x);  
	else {  
		int d = (x < o->v ? 0 : 1);  
		insert(o->ch[d], x);  
		if(o->ch[d] > o) rotate(o, d^1);  
	}  
	o->maintain();  
}  

void remove(Treap* &o, int x){  
	int d = o->cmp(x);  
	if(d == -1){  
		Treap* u = o;  
		if(o->ch[0] != NULL && o->ch[1] != NULL){  
			int d2 = (o->ch[0] > o->ch[1] ? 1: 0);  
			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 != NULL) o->maintain();  
}  

int kth(Treap* o, int k){  
	if(o == NULL || k<=0 || k> o->size) return 0;  
	int s = (o->ch[1] == NULL ? 0 : o->ch[1]->size);  
	if( k == s+1) return o->v;  
	else if(k <= s) return kth(o->ch[1], k);  
	else return kth(o->ch[0], k - s - 1);  
}  

void mergeto(Treap* &src, Treap* &dest){  
	if(src->ch[0] != NULL) mergeto(src->ch[0], dest);  
	if(src->ch[1] != NULL) mergeto(src->ch[1], dest);  
	insert(dest, src->v);  
	delete src;  
	src = NULL;  
}  

void removetree(Treap* &x){  
	if(x->ch[0] != NULL) removetree(x->ch[0]);  
	if(x->ch[1] != NULL) removetree(x->ch[1]);  
	delete x;  
	x = NULL;  
}  

void add_edge(int x){  
	int u = findset(from[x]), v = findset(to[x]);  
	if(u != v){  
		if(root[u]->size < root[v]->size) { fa[u] = v; mergeto(root[u], root[v]);}  
		else { fa[v] = u; mergeto(root[v], root[u]);}  
	}  
}  


 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值