3.3 栈&队列

栈与队列

  • 栈:具有后进先出(Last In First Out)特性的线性表
//stack  栈
int sta[N], head=0;  // 数组模拟栈,head 指向栈顶

sta[++head] = x; // 入栈
--head;          // 出栈 
if(head)         // 栈不为空
sta[head];       // 栈顶
  • 队列:具有先进先出(First In First Out)特性的线性表
// queue 队列, front 队首, tail 队尾 
int que[N], front=0, tail=-1;

que[++tail] = x; // 入队
++front;         // 出队
que[front];      //队头
if(front <= tail) //队列不为空

P1739 表达式括号匹配

表达式有英文字母(小写)、运算符(+-*/)和左右小(圆)括号构成,以 @ 作为表达式的结束符。请编写一个程序检查表达式中的左右圆括号是否匹配;

  • 若匹配,则输出 YES
  • 否则输出 NO

表达式长度小于 \(255\),左圆括号少于 \(20\) 个。

输入样例 输出样例
2*(x+y)/(1-x)@
YES

分析

统计左括号的数量 h,如果出现右括号,那么左括号的数量 h-1。
合法的情况下:h 永远 ≥0,且最后 h=0。

参考程序

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e6+10;
int main(){
    string s; cin>>s;
    int h=0;
    for(int i=0; i<s.size(); i++){
        if(s[i]=='(') h++;
        else if(s[i]==')'){
            h--;
            if(h < 0) break;
        }
    }
    if(h==0) cout<<"YES";
    else cout<<"NO";
    return 0;
}

参考程序

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e6+10,INF=0x3f3f3f3f;
char sta[N];  // stack  栈
int head=0;   // 数组模拟栈,head 指向栈顶 

int main(){
    string s; cin>>s;
    bool flag=1; // 假设原本括号是匹配的 
    for(int i=0; i<s.size(); i++){
        if(s[i]=='(') sta[++head]=s[i]; 
        else if(s[i]==')'){
            if(head) head--; // 出栈
            else { 			 // 空栈, 无法出栈,括号不匹配 
                flag=0; break; 
            } 
        }
    }
    if(flag && head==0) cout<<"YES";
    else cout<<"NO"; 
    return 0;
}

P1449 后缀表达式

所谓后缀表达式是指这样的一个表达式:式中不再引用括号,运算符号放在两个运算对象之后,所有计算按运算符号出现的顺序,严格地由左而右新进行(不用考虑运算符的优先级)。

如:\(\texttt{3*(5-2)+7}\) 对应的后缀表达式为:\(\texttt{3.5.2.-*7.+@}\)。在该式中,@ 为表达式的结束符号。. 为操作数的结束符号。

数据保证,\(1 \leq |s| \leq 50\),答案和计算过程中的每一个值的绝对值不超过 \(10^9\)

输入样例 输出样例
3.5.2.-*7.+@
16

参考程序

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e6+10,INF=0x3f3f3f3f;
int sta[N], head=0, t=0;

int main(){
    string s; cin>>s; 
    for(int i=0; i<s.size(); i++){
        if(s[i] >='0' & s[i]<='9')
          t = t*10 + s[i]-'0';
        else if(s[i]=='.'){
            sta[++head] = t; t=0; // t需要归 0 
        }else {
            if(s[i]=='@') break; // 退出放最前面 
            int a=sta[head]; head--;
            int b=sta[head]; head--;
            if(s[i]=='+') sta[++head] = a+b;
            if(s[i]=='-') sta[++head] = b-a;//注意先后
            if(s[i]=='*') sta[++head] = a*b;
            if(s[i]=='/') sta[++head] = b/a;
        }
    }
    cout<<sta[head];
    return 0;
}

P1981 [NOIP2013 普及组] 表达式求值

给定一个只包含加法和乘法的算术表达式,请你编程计算表达式的值。

输入一行,为需要你计算的表达式,所有参与运算的数字均为 \(0\)\(2^{31}-1\) 之间的整数。

输入数据保证这一行只有 \(0-9\)\(+\)、$ \times$ 这 $12 $种字符。

对于 \(100\%\) 的数据,\(0≤\) 表达式中加法运算符和乘法运算符的总数 \(≤100000\)

注意:当答案长度多于 \(4\) 位时,请只输出最后 $ 4$ 位,前导 $ 0$ 不输出。

输入样例 输出样例
1+1*3+4
8

参考程序

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e6+10,INF=0x3f3f3f3f;
LL sta[N], head=0, mod=1e4;
// (a+b) % p = (a%p+b%p) % p;
int main(){
    LL a,b; char ch;
    cin>>a;   sta[++head]=a%mod;
    while(cin>>ch>>b){
        if(ch=='+') sta[++head]=b%mod;
        if(ch=='*'){
            a = sta[head--];
            sta[++head] = a*b%mod;
        }
    }
    LL res=0;
    for(int i=1; i<=head; i++) res=(res+sta[i])%mod;
    cout<<res;
    return 0;
}

B3616 【模板】队列

请你实现一个队列(queue),支持如下操作:

  • push(x):向队列中加入一个数 \(x\)
  • pop():将队首弹出。如果此时队列为空,则不进行弹出操作,并输出 ERR_CANNOT_POP
  • query():输出队首元素。如果此时队首为空,则输出 ERR_CANNOT_QUERY
  • size():输出此时队列内元素个数。

数据范围:\(n\leq 10000\),且被插入队列的所有元素值是 \([1, 1000000]\) 以内的正整数。

输入格式

第一行,一个整数 \(n\),表示操作的次数。

接下来 \(n\) 行,每行表示一个操作。格式如下:

  • 1 x,表示将元素 x 加入队列。
  • 2,表示将队首弹出队列。
  • 3,表示查询队首。
  • 4,表示查询队列内元素个数。

输出格式

输出若干行,对于每个操作,按「题目描述」输出结果。

每条输出之间应当用空行隔开。

参考程序

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e6+10,INF=0x3f3f3f3f;
int que[N], front=0, tail=-1;

void push(int x){
    que[++tail] = x;
} 
void pop(){
    if(front>tail) cout<<"ERR_CANNOT_POP"<<endl;
    else ++front; // 出队 
}
void query(){
    if(front>tail) cout<<"ERR_CANNOT_QUERY"<<endl;
    else cout<<que[front]<<endl;
}
int size(){
    return tail-front+1;
}
int main(){
    //freopen("data.in", "r", stdin);
    int n,op,x; cin>>n;
    while(n--){
        cin>>op;
        if(op==1) cin>>x,push(x);    
        if(op==2) pop();
        if(op==3) query();
        if(op==4) cout<<size()<<endl;
    }
    return 0;
}

P1996 约瑟夫问题

\(n\) 个人围成一圈,从第一个人开始报数,数到 \(m\) 的人出列,再由下一个人重新从 \(1\) 开始报数,数到 \(m\) 的人再出圈,依次类推,直到所有的人都出圈,请输出依次出圈人的编号。

数据范围:\(1 \le m, n \le 100\)

输入两个整数 \(n,m\)

输出一行 \(n\) 个整数,按顺序输出每个出圈人的编号。

输入样例 输出样例
10 3
3 6 9 2 7 1 8 5 10 4

参考程序

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e6+10,INF=0x3f3f3f3f;
int que[N], front=0, tail=-1;

int main() {
    int n, m, cnt=0; cin>>n>>m;
    for(int i=1; i<=n; i++) que[++tail] = i;
    while(front <= tail) {
        ++cnt;
        if(cnt%m==0) cout<<que[front]<<" "; // 杀掉
        else que[++tail] = que[front]; // 没杀掉
        ++front;
    }
    return 0;
}

一本通 1332 周末舞会

假设在周末舞会上,男士们和女士们进入舞厅时,各自排成一队。跳舞开始时,依次从男队和女队的队头上各出一人配成舞伴。规定每个舞曲能有一对跳舞者。若两队初始人数不相同,则较长的那一队中未配对者等待下一轮舞曲。现要求写一个程序,模拟上述舞伴配对问题。
输入两队的人数 a,b,舞曲的数目 n,输出配对情况。

输入样例 输出样例
4 6 7
(1,1)(2,2)(3,3)(4,4)(1,5)(2,6)(3,1)

参考程序

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int N=1e4;
int que1[N], que2[N];
int main() {
    int a,b,n; scanf("%d%d%d", &a,&b,&n);
    for(int i=0; i<a; i++) que1[i]=i+1;
    for(int i=0; i<b; i++) que2[i]=i+1;
    for(int i=0; i<n; i++){
        int t1=que1[i%a], t2=que2[i%b];
        printf("(%d,%d)",t1,t2);
    }
    return 0;
}

STL中的stack,queue

#include<stack> // 栈的头文件
stack<int> sta; // 栈的定义
sta.push(x);    // 入栈
sta.pop();      // 出栈
sta.top();      // 栈顶
sta.empty();    // 栈是否为空
sta.size();     // 栈内元素个数

#include<queue> // 队列的头文件
queue<int> que; // 队列的定义
que.push(x);    // 入队
que.pop();      // 出队 
que.front();    // 队首
que.back();     // 队尾
que.empty();    // 队列是否为空
que.size();     // 队内元素个数

字符匹配问题

现在有一行括号序列,请你检查这行括号是否配对。

输入:第一行输入一个数N(0<N<=100),表示有N组测试数据。

后面的N行输入多组输入数据,每组输入数据都是一个字符串S ( S的长度小于10000,且S不是空串),数据保证S中只含有"[", “]”, “(”, “)” 四种字符。

输出:每组输入数据的输出占一行,如果该字符串中所含的括号是配对的,则输出Yes,如果不配对则输出No。

输入样例 输出样例
3
[][][]
[()]()[
[(])[]()
Yes
No
No

参考程序

#include<iostream>
#include<stack>
using namespace std;
int main() {
    int n; cin>>n;
    for(int i=1; i<=n; i++){
        stack<char> sta; string s; cin>>s;   
        for(int j=0; j<s.length(); j++){
            if(s[j]=='[') sta.push('[');
            else if(s[j]=='(') sta.push('(');
            else if(s[j]==']' && sta.top()=='[') sta.pop();
            else if(s[j]==')' && sta.top()=='(') sta.pop();
            else{ break; }
        }
        if(sta.empty()) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    } return 0;
}

一本通 1332 周末舞会

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int main() {
    int a,b,n; scanf("%d%d%d", &a,&b,&n);
    queue<int> que1,que2;
    for(int i=1; i<=a; i++) que1.push(i);
    for(int i=1; i<=b; i++) que2.push(i);
    for(int i=1; i<=n; i++) {
        int t1=que1.front(), t2=que2.front();
        que1.pop(), que1.push(t1);
        que2.pop(), que2.push(t2);
        printf("(%d,%d)",t1,t2);
    }
    return 0;
}
posted @ 2021-12-11 22:17  HelloHeBin  阅读(201)  评论(0编辑  收藏  举报