一、双向队列是什么
双向队列,顾名思义就是能在双向(队头和队尾)进行操作的一种特殊的队列。如果说队列是一个只能在一端扔东西,在另一端丢东西的容器,那么双向队列就好比一个两端都通的容器,既可以在头部扔进东西,在尾部倒出东西;也能在尾部扔进东西,在头部倒出东西的容器。它支持在队头、队尾插入或删除元素。双向队列和队列不同,它能用operator[]访问元素。
二 、双向队列操作
我们知道队列的定义方法是queue<typename> Variable_Name,Typename代表队列内存储的元素类型,比如queue <int> 就是队列内存储int类型的数据,Variable_Name是队列名;双向队列既然是队列的一种,定义方法肯定差不多。它的定义方法是deque<typename> Variable_Name,Typename代表双向队列内存储的元素类型,比如deque <int> 就是双向队列内存储int类型的数据,Variable_Name是双向队列名。除了queue改成deque以外其他没啥区别。
除此以外,双向队列还有 亿 一些常用操作。主要有:
1.front():返回队首元素,队列为空则无效
2.back():返回队尾元素,队列为空则无效
3.push_back(x):从队尾插入元素x,无返回值
4.pop_back():从队尾弹出元素,无返回值
5.push_front(x):从队头插入元素x,无返回值
6.pop_front():从队头弹出元素,无返回值
7.insert():在指定位置前插入元素(传入元素、迭代器),无返回值
8.erase():在指定位置删除元素(传入迭代器),无返回值
9.empty():判断队列是否为空,为空返回true,不为空返回false
10.size():返回队列中元素个数
和队列相同,在使用这些操作时,需要用句点运算符将操作对象与操作关联起来。比如定义了两个队列deque<int> dq1,dq2;dq1.push(7);就是在dq1的队尾插入元素7,cout << dq2.empty();就是输出dq2是否为空。
三、如何模拟双向队列
和队列差不多,详情请看我的另一篇文章 C++ 队列(WZOI 846 模拟队列),按同样的思路也能用数组模拟,就是插入、删除效率较低。
四、WZOI 864 滑动窗口
滑动窗口
题目描述:
给你一个长度为N的数组,一个长为K的滑动的窗体从最左移至最右端,你只能见到窗口的K个数,每次窗体向右移动一位,如下表:
Window position | Min value | Max value |
[ 1 3 -1 ] -3 5 3 6 7 | -1 | 3 |
1 [ 3 -1 -3 ] 5 3 6 7 | -3 | 3 |
1 3 [ -1 -3 5 ] 3 6 7 | -3 | 5 |
1 3 -1 [ -3 5 3 ] 6 7 | -3 | 5 |
1 3 -1 -3 [ 5 3 6 ] 7 | 3 | 6 |
1 3 -1 -3 5 [ 3 6 7 ] | 3 | 7 |
你的任务是找出窗口在各位置时的max value,min value.
数据范围:
20%: n<=500; 50%: n<=100000;
100%: n<=1000000;
输入格式:
第1行n,k,第2行为长度为n的数组
输出格式:
2行,第1行每个位置的min value,第2行每个位置的max value
样例输入:
<span style="color:#212529"><span style="background-color:#f5f5f5">8 3
1 3 -1 -3 5 3 6 7
</span></span>
样例输出:
<span style="color:#212529"><span style="background-color:#f5f5f5">-1 -3 -3 -3 3 3
3 3 5 5 6 7
</span></span>
时间限制: 1000ms
空间限制: 128MB
这里附上滑动窗口的AC代码(虽然关联不大起码用到了双向队列)。
#include <bits/stdc++.h>
using namespace std;
int a[1000005];
int ans1[1000005], ans2[1000005];
int main(){
cin.tie(nullptr);
cout.tie(nullptr);
ios::sync_with_stdio(false);
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; i++)
cin >> a[i];
deque< int > maxq, minq;
for (int i = 1; i <= k; i++) {
while (!maxq.empty() && a[maxq.back()] <= a[i])
maxq.pop_back();
maxq.push_back(i);
while (!minq.empty() && a[minq.back()] >= a[i])
minq.pop_back();
minq.push_back(i);
}
int p = 0;
ans1[p++] = a[minq.front()];
ans2[p - 1] = a[maxq.front()];
for (int i = k + 1; i <= n; i++) {
while (!maxq.empty() && a[maxq.back()] <= a[i])
maxq.pop_back();
maxq.push_back(i);
while (!minq.empty() && a[minq.back()] >= a[i])
minq.pop_back();
minq.push_back(i);
while (!maxq.empty() && maxq.front() <= i - k)
maxq.pop_front();
while (!minq.empty() && minq.front() <= i - k)
minq.pop_front();
ans1[p++] = a[minq.front()];
ans2[p - 1] = a[maxq.front()];
}
cout << ans1[0];
for (int i = 1; i < p; i++)
cout << ' ' << ans1[i];
cout << endl;
cout << ans2[0];
for (int i = 1; i < p; i++)
cout << ' ' << ans2[i];
return 0;
}