Treap(树堆)
treap是排序二叉树的一种改进,因为排序二叉树有可能会造成链状结构的时候复杂度变成O(n^2)所以通过随机一个优先级的方法来维持每次让优先级最大的作为树根,然后形成一个满足:
A. 节点中的key满足排序二叉树(二叉查找树)
B. 节点中的“优先级”满足大顶堆。
可以证明通过这种方法维持的插入、删除、查找的期望时间复杂度为O(logn)

一、节点的定义:左右孩子用指针数组的形式储存
struct Node{
Node*ch[];//左右子树
int r;//优先值
int v;//值
int cmp(int x) const{
if(x==v)return -;
return x<v?:;//0在ch[0]中正好是左孩子,对应向左搜索和操作,1在ch[1]中是右孩子,对应向右搜索和操作
}
};
二、旋转:和大顶堆的调整方法类似,左旋和右旋,用于对优先级的堆排序,这里不会影响二叉排序树的性质,介绍一种位运算可以巧妙的进行左旋和右旋的选择——异或,相同为0,不同为1,那么x^1就是对x取反的操作。
现在以下图为例
o 表示的指向根节点的指针
有旋转的代码如下:
//左旋代码
k = o->ch[];
o->ch[] = k->ch[];
k->ch[] = o;
o = k;
//右旋代码
k = o->ch[];
o->ch[] = k->ch[];
k->ch[] = o;
o = k;
//两种代码可以写成一种,利用异或
void rotate(Node* &o,int d){//d = 0 左旋,d = 1 右旋
Node *k = o->ch[d^];
o->ch[d^] = k->ch[d];
k->ch[d] = o;
o = k;
}
三、插入: 在插入的时候除了要在满足排序二叉树的插入要求,即递归的操作之外,还要满足堆的相应操作,所以,要通过旋转来实现,下面是代码:
srand(time(NULL));
void insert(Node *&o, int x){
if(o==NULL){
o = new Node();
o->ch[] = o->ch[] = NULL;
o->v = x;
o->r = rand();
}
else {
int d = o->cmp(x);//如果要插入的值x比当前根节点的值小则d==0,向左子树寻找,这里可以看出定义指针数组的好处
insert(o->ch[d],x);
if(o->ch[d]->r > o->r) rotate(o,d^);//左孩子权值大右旋,右孩子权值大左旋
}
}
四、删除:如果待删除结点为叶子结点或只有一棵子树,则用其子树(可能为空)替代它即可。如果有两棵子树,则将孩子中优先级高的旋转到根,然后在另一棵子树中递归删除目标点。
代码如下:
void remove(Node *&o,int x){
int d = o->cmp(x);
if(d==-){//找到了
if(o->ch[] == NULL) o = o->ch[];
else if(o->ch[] == NULL) o = o->ch[];
else {
int d2 = ((o->ch[]->r)>(o->ch[]->r)?:);//删除节点的左孩子权值大右旋,右孩子权值大左旋
rotate(o,d2);
remove(o->ch[d2],x);
}
}
else remove(o->ch[d],x);
}
五、查找:在插入和查找前进行查找,防止特殊情况,代码如下
int find(Node*o, int x){
while(o!=NULL){
int d = o->cmp(x);
if(d==-) return ;//找到了
else o = o->ch[d];
}
return ;//不存在
}
六、应用,这个数据结构可以用来解决二叉排序树的超时问题
X]C71D1GEUN`5)H]T.png)
Treap(树堆)的更多相关文章
- BZOJ3224/LOJ104 普通平衡树 treap(树堆)
您需要写一种数据结构,来维护一些数,其中需要提供以下操作:1. 插入x2. 删除x(若有多个相同的数,因只删除一个)3. 查询x的排名(若有多个相同的数,因输出最小的排名)4. 查询排名为x的数5. ...
- 可旋转Treap(树堆)总结
树堆,在数据结构中也称Treap,是指有一个随机附加域满足堆的性质的二叉搜索树,其结构相当于以随机数据插入的二叉搜索树.其基本操作的期望时间复杂度为O(logn).相对于其他的平衡二叉搜索树,Trea ...
- treap(树堆)
一棵treap是一棵修改了结点顺序的二叉查找树,如图,显示一个例子,通常树内的每个结点x都有一个关键字值key[x],另外,还要为结点分配priority[x],它是一个独立选取的随机数. 假设所有的 ...
- 查找——图文翔解Treap(树堆)
之前我们讲到二叉搜索树,从二叉搜索树到2-3树到红黑树到B-树. 二叉搜索树的主要问题就是其结构与数据相关,树的深度可能会非常大,Treap树就是一种解决二叉搜索树可能深度过大的还有一种数据结构. T ...
- 树堆(Treap)学习笔记 2020.8.12
如果一棵二叉排序树的节点插入的顺序是随机的,那么这样建立的二叉排序树在大多数情况下是平衡的,可以证明,其高度期望值为 \(O( \log_2 n )\).即使存在一些极端情况,但是这种情况发生的概率很 ...
- Treap树的基础知识
原文 其它较好的的介绍:堆排序 AVL树 树堆,在数据结构中也称Treap(事实上在国内OI界常称为Traep,与之同理的还有"Tarjan神犇发明的"Spaly),是指有一个随 ...
- Treap树
Treap树算是一种简单的优化策略,这名字大家也能猜到,树和堆的合体,其实原理比较简单,在树中维护一个"优先级“,”优先级“ 采用随机数的方法,但是”优先级“必须满足根堆的性质,当然是“大根 ...
- 6天通吃树结构—— 第三天 Treap树
原文:6天通吃树结构-- 第三天 Treap树 我们知道,二叉查找树相对来说比较容易形成最坏的链表情况,所以前辈们想尽了各种优化策略,包括AVL,红黑,以及今天 要讲的Treap树. Treap树算是 ...
- Treap树 笔记
预备知识:二叉查找树.堆(heap).平衡二叉树(AVL)的基本操作(左旋右旋) 定义: Treap.平衡二叉树.Tree+Heap.树堆. 每个结点两个键值(key.priority). 性质1. ...
- 真·浅谈treap树
treap树是一种平衡树,它有平衡树的性质,满足堆的性质,是二叉搜索树,但是我们需要维护他 为什么满足堆的性质?因为每个节点还有一个随机权值,按照随机权值维持这个堆(树),可以用O(logn)的复杂度 ...
随机推荐
- VS源码编译QuaZip(Windows下)
最近写个Qt demo,想要使用压缩和解压多个文件的功能,并不使用额外进程.网上参考了很多资料,发现只有QuaZip比较适合我的需求.但是QuaZip只提供源码,因此需要自己来编译. QuaZip简介 ...
- 防盗链与token运用
为什么要防盗链? 例如手机/PC应用,如果有人知道你的api地址,和应用格式,那么他人就可以利用这个接口进行盗链:盗取/盗用里面的数据. 防盗链特性: 1.因为是非开放性的,所以所有的接口都是封闭的, ...
- JMeter 插件 Json Path 解析HTTP响应JSON数据
一.基本简介 JMeter 是一个不错的负载和性能测试工具,我们也用来做 HTTP API 接口测试.我们的 API 返回结果为JSON数据格式.JSON 简介,JSON 教程. JSON 已经成为数 ...
- lastIndex对正则结果的影响
前言 今天遇到一个问题,用正则表达式去检查同一个字符串时,交替返回true和false.无奈之下,重新翻了翻权威指南,发现罪魁祸首原来是lastIndex.可在控制台尝试下 let reg = /[\ ...
- Python学习_13_继承和元类
继承 继承的含义就是子类继承父类的命名空间,子类中可以调用父类的属性和方法,由于命名空间的查找方式,当子类中定义和父类同名属性或者方法时,子类的实例调用的是子类中的属性,而不是父类,这就形成了pyth ...
- 每天学一点Docker(1)
Docker能做些什么? 1.docker能够解决虚拟机能够解决的问题 2.隔离应用依赖 3.创建应用镜像并复制 4.创建容易分发的即启即用的应用 5.docker的想法是创建软件程序可移植的轻量容器 ...
- 利用Service Fabric承载eShop On Containers
从模块化到微服务化 从Pet Shop 到eShop on Container都是Microsoft在技术演进的路径上给开发者展示.Net的开发能力和架构能力的Sample工程,Petshop的时候更 ...
- [js高手之路]从零开始打造一个javascript开源框架gdom与插件开发免费视频教程连载中
百度网盘下载地址:https://pan.baidu.com/s/1kULNXOF 优酷土豆观看地址:http://v.youku.com/v_show/id_XMzAwNTY2MTE0MA==.ht ...
- css实现平行四边形、菱形图片效果
一.平行四边形 1. 使用两个元素实现 html <a class="button"> <div>click me</div> </a&g ...
- ERP报错:所在的期间无效,但又无法新增账套期间。
问题: 进入2018新年月,客户在新增单据的时候,报错:日期[2018-01-03]所在的期间无效 正常解决方法 过账期间里面设置一下路径:管理----期间与结账----过账期间设置 先设置年期间-- ...