数组模拟 栈 和 队列

一、我们首先要了解栈的概念 在 c++中有着 STL 的存在可以方便我们做很多事,而 栈(stack)就是其中的一部分,简单的说栈就是一种 先进后出 的数据机构


通过思考和模拟栈的结构,发现我们可以用 一维数组 和一个变量 tt 来实现栈这一数据结构

stk[100010] 用来代表栈  tt 代表一种指针

栈的读入操作


//  add  insert
int x;
cin>>x;
stk[++tt]  = x; // 我这里是把栈的下标从 1 开始 用来与队列进行区别
                // 这样我们就已经把 x 读入到了我们的模拟栈中

  栈的弹出操作

// remove
tt--;//这样就已经把队头的元素弹出了

因为栈是一个类似于木桶的存在,同时 tt  又一直指向木桶的最上方;所以当  tt--  时,位于最上方的元素就会被弹出

这道题来自于AcWing第830题 也是有关单调栈的应用

给定一个长度为 NN 的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出 −1−1。

输入格式

第一行包含整数 NN,表示数列长度。

第二行包含 NN 个整数,表示整数数列。

输出格式

共一行,包含 NN 个整数,其中第 ii 个数表示第 ii 个数的左边第一个比它小的数,如果不存在则输出 −1−1。

数据范围

1≤N≤1051≤N≤105
1≤数列中元素≤1091≤数列中元素≤109

输入样例:

5
3 4 2 7 5

输出样例: 

-1 3 -1 2 2

 这个是题解

#include <iostream>

using namespace std;

const int N = 1e5 +10;

int stk[N],tt;
int a[N];
int main(void)
{
    int n;
    cin>>n;
    for(int i = 0;i<n;i++)
    {
        while(tt && stk[tt] > a[i]) tt--; // 这里会遍历数组里面的元素 把大于该值的数弹出
                                          // 因为题意里面找的是第一位小于 a[i] 的值 如果
                                          // 如果上一个值是大于 a[i] 的话那么接下来的值都
                                          // 不会选择该值
        if(!tt) cout<<"-1";
        stk[++tt] = x;
    }
}



下面来模拟队列,队列也是 STL 中的一个容器,他和栈的区别是先进先出,类似于水管一样,

也就是从队尾进入,从对头弹出

同样,通过对队列的模拟我们也可以用数组来实现队列的功能

q[100010] , tt , hh;

hh 代表队头

tt 代表队尾

 队列的读入操作

// add
hh = 0,tt = -1;// 这里我们将队列的下标设置为从一开始 与 栈 进行分开
int x;
cin>>x;
q[++tt] = x;// 从队尾插进了元素

队列的弹出操作

// remove
hh++;

这里弹出和 栈 的弹出也是有些相似,hh 相当于在一条水管中的上部分,tt 相当于下部分

当 hh++ 时就相当于 hh 往下移动,因此前面位于 hh 的元素 q[hh] 就会被弹出 

 

 这道题来自于AcWing第154题的滑动窗口问题

给定一个大小为 n≤106n≤106 的数组。

有一个大小为 kk 的滑动窗口,它从数组的最左边移动到最右边。

你只能在窗口中看到 kk 个数字。

每次滑动窗口向右移动一个位置。

以下是一个例子:

该数组为 [1 3 -1 -3 5 3 6 7],kk 为 33。

窗口位置最小值最大值
[1 3 -1] -3 5 3 6 7-13
1 [3 -1 -3] 5 3 6 7-33
1 3 [-1 -3 5] 3 6 7-35
1 3 -1 [-3 5 3] 6 7-35
1 3 -1 -3 [5 3 6] 736
1 3 -1 -3 5 [3 6 7]37

你的任务是确定滑动窗口位于每个位置时,窗口中的最大值和最小值。

输入格式

输入包含两行。

第一行包含两个整数 nn 和 kk,分别代表数组长度和滑动窗口的长度。

第二行有 nn 个整数,代表数组的具体数值。

同行数据之间用空格隔开。

输出格式

输出包含两个。

第一行输出,从左至右,每个位置滑动窗口中的最小值。

第二行输出,从左至右,每个位置滑动窗口中的最大值。

输入样例:

8 3
1 3 -1 -3 5 3 6 7

输出样例:

-1 -3 -3 -3 3 3
3 3 5 5 6 7

下面是题解 

#include <iostream>
using namespace std;
const int N = 1e6 +10;

int q[N];
int a[N];
int hh,tt = -1;
int main(void)
{
    int n,k;
    cin>>n>>k;// n 代表数组长度   k  代表窗口长度
    for(int i = 0;i<n;i++) cin>>a[i];
    for(int i = 0;i < n;i++)
    {
        if(hh <= tt && i - k + 1>q[hh]) hh++;
        while(hh <= tt && a[q[tt]] >= a[i]) tt--; // 这里是把所有大于 a[i] 的元素都弹了出去
                                                  //因为当队列中的最后进来的如果比前面的都
                                                  //小的话,前面的所有数值就都会用不到,所
                                                  //以把没用的元素都弹了出去,下面求大值的
                                                  //时候也是一个道理
        q[++tt] = i;
        if (i >= k - 1) printf("%d ", a[q[hh]]);
    }
    puts("");
    hh=0,tt= -1;
    for(int i = 0;i<n;i++)
    {
        if(hh <= tt && i-k+1>q[hh]) hh++;
        while(hh <= tt && a[q[tt]] <= a[i]) tt--;
        q[++tt] = i;
        if (i >= k - 1) printf("%d ", a[q[hh]]);
    }
    cout<<endl;
}

 

有些人可能会有疑惑,明明可以用STL,我们为什么又要费心思去模拟他呢,这是因为,模拟STL可以省出很多时间,优化程序的效率,这一点在做算法题目的时候尤为重要

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赵英英俊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值