队列(优先队列,单调队列)

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 - 队列最前面的下标 ≥ 窗口所包含的数量,那么说明最前面的元素超出了窗口,将最前面的元素弹出,同时最前面的元素就是当前这个窗口的最大值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值