zoukankan      html  css  js  c++  java
  • STL-Deque(双端队列)与单调队列的实现

    前言:

      STl是个好东西,虽然他在不开O2的条件下会跑的很慢,但他着实会让你的代码可读性大大提高,令你的代码看起来既简单又整洁。

    双端队列:

      顾名思义,双端队列是有两个头的,一个队首指针,一个队尾指针,先进先出或是先进后出都可以实现。

    基本操作:

      (1) deque<int> dq 定义一个int类型的双端队列dq

      (2) deque<int> dq(15) 队列dq具有15个元素单位

      (3) deque<int> dq(15,10) 队列dq内15个元素初始值均为10

      (4) dq.push_back(x) 将x放入dq的末端

      (5) dq.push_front(z) 将x放入dq的前端

      (6) dq.size() 返回队列中元素的个数

      (7) dq.pop_front() 弹出队列的前端元素
      (8) dq.pop_back() 弹出队列的后端元素

      (7) dq.front() 返回队列的前端元素
      (8) dq.back() 返回队列的后端元素

    代码实现:

     1 #include<cstdio>
     2 #include<queue>
     3 using namespace std;
     4 const int maxn=1e5+5;
     5 deque<int> dq;
     6 int a[maxn]={0,1,2,3,4,5,6,7,8,9,10};
     7 int main(){
     8     dq.push_front(a[1]),dq.push_front(a[2]),dq.push_front(a[3]);
     9     dq.push_back(a[4]),dq.push_back(a[5]),dq.push_back(a[6]);
    10     dq.push_front(a[7]),dq.push_front(a[8]);
    11     dq.push_back(a[9]),dq.push_back(a[10]);
    12     dq.pop_front(),dq.pop_front();
    13     dq.pop_back(),dq.pop_back();
    14     int n=dq.size();//n=6
    15     for(int i=1;i<=n;i++){
    16         printf("%d ",dq.front());
    17         dq.pop_front();
    18     }
    19     return 0;
    20 }
    deque

    小结:

      双端队列不仅可以用来优化搜索,更能用来写单调队列这个神奇的xx来优化其他的一些东西(例如DP)

    单调队列:

      顾名思义,单调队列是单调递增或者是单调递减的一种队列,就像一个递增队列,若将数列1 6 5 3 8放入队列中,则队列的每一步变化为:1、1 6、1 5、1 3、1 3 8 。每当放入的元素使得队列不在单调,则弹出队尾的元素,直到使得队列元素单调。

    代码实现:

     1 #include<cstdio>
     2 #include<queue>
     3 using namespace std;
     4 const int maxn=1e5+5;
     5 deque<int> q_up;
     6 deque<int> q_dw;
     7 int a[maxn]={0,1,6,5,3,8};
     8 int main(){
     9     for(int i=1;i<=5;i++){
    10         while(q_up.size()&&q_up.back()>=a[i]) 
    11             q_up.pop_back();
    12         q_up.push_back(a[i]);
    13     }
    14     int n=q_up.size();
    15     for(int i=1;i<=n;i++){
    16         printf("%d ",q_up.front());
    17         q_up.pop_front();
    18     }
    19     return 0;
    20 }
    q_up

       当然,单调队列也可以用来维护滑动窗口的区间最大值和区间最小值。

    例题_滑动窗口(洛谷P1886)

    题目描述

      现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。

     1 #include<cstdio>
     2 #include<queue>
     3 using namespace std;
     4 const int maxn=1e6+5;
     5 struct cp{
     6     int ord,x;
     7 };
     8 deque<cp> q1,q2;
     9 int n,k;
    10 int a[maxn],s1[maxn],s2[maxn];
    11 inline void q_max(cp e){
    12     while(q1.size()){
    13         cp q=q1.back();
    14         if(q.x>=e.x) q1.pop_back();
    15         else break;
    16     }
    17     while(q1.size()){
    18         cp q=q1.front();
    19         if(q.ord==e.ord-k) q1.pop_front();
    20         else break;
    21     }
    22     q1.push_back(e);
    23     cp q=q1.front();
    24     if(e.ord-k>=0) s1[e.ord-k+1]=q.x;
    25 }
    26 inline void q_min(cp e){
    27     while(q2.size()){
    28         cp q=q2.back();
    29         if(q.x<=e.x) q2.pop_back();
    30         else break;
    31     }
    32     while(q2.size()){
    33         cp q=q2.front();
    34         if(q.ord==e.ord-k) q2.pop_front();
    35         else break;
    36     }
    37     q2.push_back(e);
    38     cp q=q2.front();
    39     if(e.ord-k>=0) s2[e.ord-k+1]=q.x;
    40 }
    41 inline int read(){
    42     char ch=getchar();
    43     int x=0,f=1;
    44     while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    45     while(ch>='0'&&ch<='9') x=x*10+(ch^48),ch=getchar();
    46     return x*f;
    47 }
    48 int main(){
    49     n=read(),k=read();
    50     for(int i=1;i<=n;i++) a[i]=read();
    51     for(int i=1;i<=n;i++){
    52         cp q;
    53         q.ord=i,q.x=a[i];
    54         q_max(q),q_min(q);
    55         printf("%d ",s1[i])
    56     }
    57     for(int i=1;i<=n-k+1;i++) ;
    58     putchar('
    ');
    59     for(int i=1;i<=n-k+1;i++) printf("%d ",s2[i]);
    60     return 0;
    61 }
    Code

      结构体类型的队列不知为何不能用 q.front().ord,所以代码显得特别冗长,如果有dalao可以解决这个问题,蒟蒻洗耳恭听!

    (以上问题现已解决,附上代码)

     1 #include<cstdio>
     2 #include<queue>
     3 using namespace std;
     4 const int maxn=1e6+5;
     5 struct cp{
     6     int ord,x;
     7 };
     8 deque<cp> q1,q2;
     9 int n,k;
    10 int a[maxn],s1[maxn],s2[maxn];
    11 inline void q_max(cp e){
    12     while(q1.size()&&q1.back().x>=e.x) q1.pop_back();
    13     if(q1.size()&&q1.front().ord==e.ord-k) q1.pop_front();
    14     q1.push_back(e);
    15     if(e.ord-k>=0) s1[e.ord-k+1]=q1.front().x;
    16 }
    17 inline void q_min(cp e){
    18     while(q2.size()&&q2.back().x<=e.x) q2.pop_back();
    19     if(q2.size()&&q2.front().ord==e.ord-k) q2.pop_front();
    20     q2.push_back(e);
    21     if(e.ord-k>=0) s2[e.ord-k+1]=q2.front().x;
    22 }
    23 inline int read(){
    24     char ch=getchar();
    25     int x=0,f=1;
    26     while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    27     while(ch>='0'&&ch<='9') x=x*10+(ch^48),ch=getchar();
    28     return x*f;
    29 }
    30 int main(){
    31     n=read(),k=read();
    32     for(int i=1;i<=n;i++) a[i]=read();
    33     for(int i=1;i<=n;i++){
    34         cp q=(cp){i,a[i]};
    35         q_max(q),q_min(q);
    36     }
    37     for(int i=1;i<=n-k+1;i++) printf("%d ",s1[i]);
    38     putchar('
    ');
    39     for(int i=1;i<=n-k+1;i++) printf("%d ",s2[i]);
    40     return 0;
    41 }
    Code(如果您喜欢压行)

      如有任何问题,蒟蒻洗耳恭听!

  • 相关阅读:
    HashMap数据结构分析(jdk8)
    ConcurrentHashMap数据结构(jdk8)
    TOJ1373_多项式规律
    Windows程序基础——Windows应用程序的基本概念
    Why to learn MFC?
    TOJ1062
    TOJ1369
    TOJ1003
    vue 生命周期~~
    如何跨域访问的两种方法~
  • 原文地址:https://www.cnblogs.com/RisingGods/p/9426127.html
Copyright © 2011-2022 走看看