treap
时间:2010-11-11 来源:forever zsz
首先是插入:插入这列基本与裸的TREAP一样,只需要加两句话即可:
void insert(int &x,int y)//注意x前面的&。 { if (x==0) { x=++size; e[x].l=0;e[x].r=0;e[x].a=y;e[x].ll=0;e[x].rr=0; e[x].b=rand()*rand(); return; } if (y>e[x].a) { e[x].rr++;//如果大于X的话,则x的右儿子个数++; insert(e[x].r,y); if (e[x].b>e[e[x].r].b) right(x); return; } if (y<=e[x].a) { e[x].ll++;//同理,如果小于x的话,则X的左儿子个数++; insert(e[x].l,y); if (e[x].b>e[e[x].l].b) left(x); return; } }
下面就是treap的旋转:
其实只要正确理解旋转的定义就可以了.下面就以右旋为例(其实左右旋到底哪个是哪个我也不是很清楚,不过只要记住操作就可以了)
在右旋中,因为右儿子的随机关键字小于父节点(这里以小根堆为例),因此需要执行旋转.
由图上的旋转可知,旋转后x(要旋转的节点)的右节点(下面称J),J的左儿子变成了X的右儿子,因此E[X].RR=E[J].LL;
而J的左儿子,变成了X+X左儿子+J左儿子;
因此,只要如下面代码那样就可以实现了;
void right(int &x) { int j=e[x].r; e[x].r=e[j].l; e[x].rr=e[j].ll;// e[j].l=x; e[j].ll=e[x].ll+e[j].ll+1; x=j; }
最后是最复杂的Delete操作:
有了旋转的操作之后,Treap的删除比BST还要简单。因为Treap满足堆性质,所以我们只需要把要删除的节点旋转到叶节点上,然后直接删除就可以了。具体的方法就是每次找到优先级最大的儿子,向与其相反的方向旋转,直到那个节点被旋转到了叶节点,然后直接删除。
删除最多进行O(h)次旋转,期望复杂度是O(log n)。
详细的讲解还是上NOCOW http://www.nocow.cn/index.php/Treap
foreverzsz原创,转载请注明出处.
本文出处:http://www.cnblogs.com/foreverzsz/archive/2010/11/11/1875021.html
相关阅读 更多 +