1.优先队列
优先队列具有队列的所有特性,包括基本操作,只是在这基础上添加了内部的一个排序,它本质是一个堆实现的
和队列基本操作相同:
- top 访问队头元素 ,队列为front
- empty 队列是否为空
- size 返回队列内元素个数
- push 插入元素到队尾 (并排序)
- emplace 原地构造一个元素并插入队列
- pop 弹出队头元素
- swap 交换内容
priority_queue<Type, Container, Functional>
Type 就是数据类型,Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector,Functional 就是比较的方式,当需要用自定义的数据类型时才需要传入这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大顶堆
priority_queue <int,vector<int>,less<int> > q; //大顶堆
priority_queue<int> a; //默认大顶堆,内部从大到小排序
priority_queue<int,vector<int>,greater<int> > c; //小顶堆,从小到大
2.单调队列
滑动窗口:例题链接
就是一道板子题,ac代码如下
#include<iostream>
#include<queue>
using namespace std;
const int N=1e6+5;
int a[N],b[N],c[N];
int main(){
int n,k,t1=1,t2=1;
cin>>n>>k;
deque<int> q;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++){
while(!q.empty()&&a[q.back()]>a[i])
q.pop_back();
q.push_back(i);
if(i>=k){
while(!q.empty()&&q.front()<=i-k)
q.pop_front();
b[t1++]=a[q.front()];
}
}
while(!q.empty()) q.pop_front();
for(int i=1;i<=n;i++){
while(!q.empty()&&a[q.back()]<a[i])
q.pop_back();
q.push_back(i);
if(i>=k){
while(!q.empty()&&q.front()<=i-k)
q.pop_front();
c[t2++]=a[q.front()];
}
}
for(int i=1;i<t1;i++)
cout<<b[i]<<" ";
cout<<endl;
for(int i=1;i<t2;i++)
cout<<c[i]<<" ";
cout<<endl;
}
滑动窗口求最大值
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
#define ll long long
const int N=1e5+5;
int a[N];
int main(){
ll n,m;
cin>>n>>m;
deque<int> q;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++){
while(!q.empty()&&a[q.back()]>a[i])
q.pop_back();
q.push_back(i);
if(i>=m){
while(!q.empty()&&q.front()<=i-m)
q.pop_front();
cout<<a[q.front()]<<endl;
}
}
}
n为数组个数,k为滑动窗口包含的个数,双端队列q中存储的为数组的下标
while(!q.empty()&&a[q.back()]<a[i])
q.pop_back();
我们对数组进行遍历,如果队列末尾的数小于当前遍历的数a[i],那么我们就弹出队尾的元素,因为比a[i]小的数可能有多个,所以用while循环,然后把当前元素的下标入队,队首的元素为窗口的最大值
例如 2 1 4 2 3 2这个数组,刚开始我们遇见2,它有可能成为窗口的最大值,把它记录下来(记录下标);再遇见1,记录 1 的下标(因为 1 可能成为后面窗口的最大值);遇见 4,我们要把 1 2 给弹出,因为现在有了一个更大的数,那么 1 2 肯定不可能成为窗口的最大值;再后面遇到 2 ,存入 2 的下标(因为有可能成为后面窗口的最大值);再遇见 3,将 2 弹出记录 3;遇见 2 记录 2,因为 当前下标 i - 队列最前面 q.front 的值大于窗口包含数量,所以把 4 弹出,那么当前最大的就为 3.
if(i>=k){while(!q.empty()&&i-q.front()>=k)
q.pop_front();
cout<<a[q.front()]<<endl;}
因为如果i>=k,那么队列内的元素下标数量有可能超过了窗口所包含的数量,用while循环,如果当前遍历的位置下标 i - 队列最前面的下标 ≥ 窗口所包含的数量,那么说明最前面的元素超出了窗口,将最前面的元素弹出,同时最前面的元素就是当前这个窗口的最大值。