数据结构--堆
来源:互联网 发布:淘宝宝贝长图作用 编辑:程序博客网 时间:2024/05/29 18:36
堆是一棵完全二叉树,可以
堆的性质:每个非叶子节点比它的孩子都大(大根堆/大顶堆)/每个非叶子节点比它的孩子都小(小根堆/小顶堆)。
从上面的性质可以推出堆的根就是最值。
堆的常用操作:top返回堆顶,pop弹出堆顶,push压入新元素。
后两个操作时间是
然而堆是完全二叉树,深度不超过
接下来是手写堆的代码:
//完全二叉树的保存方式://根:1//节点i的左儿子i*2,右儿子i*2+1#include<bits/stdc++.h>using namespace std;int n,tot;int t[1000001];void push(int x){ tot++; t[tot]=x; int u=tot; while(t[u>>1]>t[u]){ swap(t[u>>1],t[u]); u>>=1; }}void pop(){ if(tot==0){ return; } swap(t[1],t[tot]); tot--; int u=1; while(((u<<1<=tot)&&(t[u]>t[u<<1]))||(((u<<1)+1<=tot)&&(t[u]>t[(u<<1)+1]))){ if((u<<1)+1>tot){ swap(t[u],t[u<<1]); break; } if(t[u<<1]<t[(u<<1)+1]){ swap(t[u],t[u<<1]); u<<=1; } else{ swap(t[u],t[(u<<1)+1]); u<<=1; u++; } }}int top(){ return t[1];}int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ int num; scanf("%d",&num); if(num==1){ int x; scanf("%d",&x); push(x); } else if(num==2){ printf("%d\n",top()); } else{ pop(); } } return 0;}
然后其实在竞赛中更常用的是系统自带堆——优先队列priority_queue,很方便,就是慢了一倍左右。
关于优先队列的使用方法:
priority_queue< T > (T为类型)(后面括号内为时间复杂度)
1. T top(void):返回堆顶(即最值);(1)
2. void pop(void):弹出堆顶;(logn)
3. void push(T):压入新元素;(logn)
4. bool empty(void):如果堆为空返回true,否则返回false;(1)
5. int size(void):返回堆的元素数量;(1)
另一种定义方式:(建议)
priority_queue< T , vector< T > ,less< T > > (大根堆)
priority_queue< T , vector< T > ,greater< T > > (小根堆)
用自定义类型的前提是那个类型有定义小于号(大根堆)/ 大于号(小根堆)
我这里给出优先队列的使用代码:
#include<bits/stdc++.h>using namespace std;int n,tot;priority_queue<int,vector<int>,greater<int> > q;int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ int num; scanf("%d",&num); if(num==1){ int x; scanf("%d",&x); q.push(x); } else if(num==2){ printf("%d\n",q.top()); } else{ if(!q.empty()) q.pop(); } } return 0;}
具体时间差就是:
手写堆828ms
优先队列1677ms
到这里,堆的初步介绍就结束了。
接下来最重要的还是题。
洛谷 P3378 【模板】堆
写完堆先交这个题,确保时间不超1000ms就基本合格。
洛谷 P1090 合并果子
这个题其实本身很简单,每次取两堆最小的合并再放入,重复到只剩一堆。
我想把这个题放在这儿的目的就是要说这种思想很重要,就是放入再取出的思想。
有时候这种思想可以使你的操作变得可以撤销,可以过好多题。
有一次我和@hzy一起去培训的时候就碰到了这么一个题,他想出来了,可是没时间写了,错失了100分,最后就让我这么一个只会暴力的拿了第一(笑)。
洛谷 P2085 最小函数值
这是堆的一个经典应用:求若干个单调序列中的第m小(大)
这题我们可以将每个函数看成一个单调上升的序列,这样最小值一定在某个队首,取出最小值后次小值就一定还在某个队首,这样,我们就可以一开始将所有队首放入堆中,然后每次取出某个值后,再将它的序列中的下一个值放入堆中;如此重复m次就可以得到第m小。
贴代码:
#include<bits/stdc++.h>using namespace std;struct func{ int a,b,c,x,v; void calc(){ v=a*x*x+b*x+c; } bool operator > (const func& y) const { return v>y.v; }}f[10001];int n,m;priority_queue<func,vector<func>,greater<func> > q;int main(){ scanf("%d %d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d %d %d",&f[i].a,&f[i].b,&f[i].c); f[i].x=1; f[i].calc(); q.push(f[i]); } for(int i=1;i<=m;i++){ func g=q.top(); q.pop(); printf("%d ",g.v); g.x++; g.calc(); q.push(g); } return 0;}
洛谷 P1631 序列合并
这题和上面那个本质上一样,排序后,将A序列中一个值和B序列中所有值的配对看做一个单调上升序列,像上面那样做就好了。
代码:
#include<bits/stdc++.h>using namespace std;int A[100001],B[100001];struct func{ int a,b; bool operator > (const func& y) const { return A[a]+B[b]>A[y.a]+B[y.b]; }}f[10001];int n;priority_queue<func,vector<func>,greater<func> > q;int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&A[i]); } for(int i=1;i<=n;i++){ scanf("%d",&B[i]); } sort(A+1,A+n+1); sort(B+1,B+n+1); for(int i=1;i<=n;i++){ func g; g.a=i; g.b=1; q.push(g); } for(int i=1;i<=n;i++){ func g=q.top(); q.pop(); printf("%d ",A[g.a]+B[g.b]); g.b++; if(g.b<=n) q.push(g); } return 0;}
洛谷 P1801 黑匣子_NOI导刊2010提高(06)
这题虽然算是一个平衡树模板,可是也是一道堆的进阶题目,难度达到了提高+/省选-;
这个题中我们要开两个堆,一个大顶堆q1,一个小顶堆q2,大顶堆的顶部对着小顶堆的顶部(
此时这两个堆合在一起被称为对顶堆。
我们还要记录一个变量size来记录q1的大小;每次GET的时候,如果size < i,就一直将q2的顶部压入q1;
如果size > i,就一直将q1的顶部压入q2;直到size==i之后q1的顶部就是查询结果。
代码不难写出:
#include<bits/stdc++.h>using namespace std;int a[200001],u[200001];int n,m;priority_queue<int,vector<int>,less<int> > q1;priority_queue<int,vector<int>,greater<int> > q2;int main(){ scanf("%d %d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } for(int i=1;i<=m;i++){ scanf("%d",&u[i]); } sort(u+1,u+m+1); int k=1; int sz=0; for(int i=1;k<=m;i++){ if(q2.empty()||a[i]<q2.top()){ q1.push(a[i]); sz++; } else{ q2.push(a[i]); } while(i==u[k]){ while(sz<k){ q1.push(q2.top()); q2.pop(); sz++; } while(sz>k){ q2.push(q1.top()); q1.pop(); sz--; } printf("%d\n",q1.top()); k++; } } return 0;}
题目我就放这么多,关键还是要能想到用堆,数据结构对比赛只是辅助。
end
- 数据结构:堆
- 数据结构-堆
- 堆数据结构
- 堆数据结构
- 数据结构:堆
- 数据结构-堆
- 数据结构-堆
- 数据结构 堆
- 数据结构--堆
- 数据结构:堆
- 数据结构:堆
- 数据结构--堆
- 堆数据结构
- 数据结构- 堆
- 数据结构:堆
- 【数据结构】堆
- 数据结构--堆
- 数据结构-堆
- python3[爬虫实战] 爬虫之requests爬取新浪微博京东客服
- 异步代码错误捕获
- 杭电ACM:人见人爱A-B
- 路漫漫其修远兮,吾将上下而求索(非干货,勿入)
- CSS3理解display属性
- 数据结构--堆
- css——三角形的实现
- 互斥资源加锁的实现方式
- 用面向对象的方法实现互斥资源加锁
- 串行队列/并发队列&异步任务/同步任务代码演练
- less简单笔记
- Simple Class Serialization With JsonCpp
- 【HDU1069】 Monkey and Banana(动态规划)
- windows10 64位 redis3.0.*下载以及安装