考察优先队列
总时间限制: 3000ms内存限制: 65536kB 题目
描述
定义一个数组,初始化为空。在数组上执行两种操作:
1、增添1个元素,把1个新的元素放入数组。
2、输出并删除数组中最小的数。
使用堆结构实现上述功能的高效算法。
输入
第一行输入一个整数t,代表测试数据的组数。
对于每组测试数据,第一行输入一个整数n,代表操作的次数。
每次操作首先输入一个整数type。
当type=1,增添操作,接着输入一个整数u,代表要插入的元素。
当type=2,输出删除操作,输出并删除数组中最小的元素。
1<=n<=100000。
输出
每次删除操作输出被删除的数字。
样例输入
4
1 5
1 1
1 7
2
样例输出
1
提示
每组测试数据的复杂度为O(nlogn)的算法才能通过本次,否则会返回TLE(超时)
需要使用最小堆结构来实现本题的算法
思路1普通方法:
1 用全局数组实现heap,要熟悉downadjust(low ,high)和upadjust(low , high)的书写
2 注意heap数组从下标1开始存数,否则左右孩子计算公式(2*low,2*low+1)不再正确[heap[++k] = num]
3 入堆向上调整 出堆向下调整 建堆从右往左从下往上调整(逆序的for+向下调整)
代码:
#include<map>
#include<string>
#include<set>
#include<cmath>
#include<sstream>
#include <algorithm>
#include<queue>
#include<stack>
using namespace std;
//小顶堆
int heap[100000];//最多100000次操作
void downadjust(int tag,int k)//建堆和删除向下调整
{
while(2*tag<=k)
{
int minnum;
if(2*tag+1<=k)
minnum=min(heap[2*tag],heap[2*tag+1]);
else //可能没有右孩子
minnum = heap[2*tag];
if(heap[tag]>minnum)
{
if(minnum==heap[2*tag])
{
heap[2*tag]=heap[tag];
heap[tag]=minnum;
tag=2*tag;//向下调整
}
else
{
heap[2*tag+1]=heap[tag];
heap[tag]=minnum;
tag = 2*tag+1;//向下调整
}
}
else break;//根节点达到最小,循环结束
}
}
void upadjust(int low,int high)//入堆向上调整
{
while(low>=1)
{
int minnum;
if(2*low+1<=high)
minnum=min(heap[2*low],heap[2*low+1]);
else //可能没有右孩子
minnum = heap[2*low];
if(heap[low]>minnum)
{
if(minnum==heap[2*low])
{
heap[2*low]=heap[low];
heap[low]=minnum;
low=low/2;//向上调整
}
else
{
heap[2*low+1]=heap[low];
heap[low]=minnum;
low = (low-1)/2;//向上调整
}
}
else break;
}
}
int main()
{
long long int n;
freopen("input.txt","r",stdin);
int k=0,type,num;
while(cin>>n)
{
int i=0;
while(i<n)
{
i++;
cin>>type;
if(type==1)
{
cin>>num;
heap[++k]=num;
if(k!=1) upadjust(k/2,k);
}
else
{
int out_num=heap[1];
cout<<out_num<<endl;
heap[1]=heap[k--];
downadjust(1,k);
}
}
}
return 0;
}
思路2使用优先队列:
优先队列的应用。注意优先队列是用堆实现的,所以对优先队里push()、pop()操作的时间复杂度都是O(nlongn)
初始化优先队列需要三个参数,第一个参数是元素类型,第二个参数为容器类型,第三个参数是比较算子。
priority_queue 《int ,vector《int》,greater《int》》 p; 大的放在队尾(小顶堆)
priority_queue 《int ,vector《int》,less《int》》 p; 小的放在队尾(大顶堆)
priority_queue 《int ,vector《int》,cmp 》 p; 注意队列的cmp和排序sort中的cmp作用相反(队列中cmp<是队首到队尾降序,排序中cmp<则是数组首到数组尾升序)
需要熟悉队列操作:
1 q.top()访问堆顶
2 q.push()入堆
3 q.pop()出堆
4 cmp需要写成结构体形式
struct cmp{
bool operator()(int a,int b){
return a>b;//优先输出值小的
}
};
5 定义堆需要注意最后两个> 之间有一个空格
代码:
#include <iostream>
#include<cstdio>
#include<vector>
#include<map>
#include<string>
#include<set>
#include<cmath>
#include<sstream>
#include <algorithm>
#include<queue>
#include<stack>
using namespace std;
int type,num;
struct cmp{
bool operator()(int a,int b){
return a>b;//优先输出值小的
}
};
int main()
{
//freopen("input.txt","r",stdin);
priority_queue<int ,vector<int>,greater<int> > q;
//使用cmp的方法速度更快
//priority_queue<int ,vector<int>,cmp > q;
long long int n;
cin>>n;
for(long long int i=0;i<n;i++)
{
cin>>type;
if(type==1)
{
cin>>num;
q.push(num);
}
else
{
cout<<q.top()<<endl;
q.pop();
}
}
return 0;
}