栈的特点
1. 一种线性存储结构,先进后出。
2.限定只能在栈顶进行插入和删除操作。
s.empty(); //如果栈为空则返回true, 否则返回false;
s.size(); //返回栈中元素的个数
s.top(); //返回栈顶元素, 但不删除该元素
s.pop(); //弹出栈顶元素, 但不返回其值
s.push(); //将元素压入栈顶
【分析】
1.考虑表达式中数的先后顺序,具体可用树状图来表示。
2.运用栈相关的操作完成加减乘除运算
【代码】
#include <bits/stdc++.h>
using namespace std;
string a;
int main(){
stack<long long> s;//记得开long long
getline(cin,a);
int l=a.size();
int i=0;//赋初值
long long m,n;
while(a[i]!='@'){
switch(a[i]){
case '+':n=s.top();s.pop();m=s.top();s.pop();s.push(m+n);break;
case '-':n=s.top();s.pop();m=s.top();s.pop();s.push(m-n);break;
case '*':n=s.top();s.pop();m=s.top();s.pop();s.push(m*n);break;
case '/':n=s.top();s.pop();m=s.top();s.pop();s.push(m/n);break;//运算
default:
long long t=0,flag=0;
while(a[i]>='0' && a[i]<='9'){
t=t*10+a[i]-'0';
i++;
flag=1;
}
if(flag) s.push(t);//如果是数字 入栈
break;
}
i++;//下一位
}
cout<<s.top() ;
return 0;
}
【分析】
先考虑将左括号放入栈中(可以直接用别的数代替),再用右括号进行配对。不能先使右括号入栈,那样的运算是非法的。当栈不为空时,每一个右括号,弹出栈中一个元素与其配对。最后当栈为空时,说明全部配对成功;否则,配对失败。(需要考虑栈本身是空的,直接输出“NO”。
【代码】
#include<bits/stdc++.h>
using namespace std;
stack<long long>a;
string s;
int main(){
cin>>s;
int i=0;
while(s[i]!='@'){
if(s[i]=='('){
a.push(i);//入栈
}
if(s[i]==')'){
if(a.empty()==1){
cout<<"NO";
return 0;
}
else{
a.pop();//弹出
}
}
i++;
}
if(a.empty()==1) cout<<"YES";
else cout<<"NO";
}
【分析】
1.定义字符串读入四种类型的操作
2.分别操作
【代码1 数组】
#include <bits/stdc++.h>
#define N 1000010
using namespace std;
string a;
int stk[N];
int main(){
int m,top=0;//top用来指向栈顶元素
cin>>m;
while(m--){
cin>>a;
if(a=="push"){
int x;
cin>>x;
stk[++top]=x;
}
if(a=="pop"){
top--;
}
if(a=="query"){
cout<<stk[top]<<endl;
}
if(a=="empty"){
if(top<=0){
cout<<"YES"<<endl;//说明栈为空
}
else cout<<"NO"<<endl;
}
}
return 0;
}
【代码2 stl】
#include <bits/stdc++.h>
#define N 1000010
using namespace std;
string a;
stack<long long> s;
int main(){
int m;
cin>>m;
while(m--){
cin>>a;
if(a=="push"){
int x;
cin>>x;
s.push(x);//x入栈
}
if(a=="pop"){
s.pop();
}
if(a=="query"){
cout<<s.top()<<endl;//输出栈顶元素
}
if(a=="empty"){
if(s.empty()){
cout<<"YES"<<endl;
}
else cout<<"NO"<<endl;
}
}
return 0;
}
【分析】
1.和后缀表达式一样,运用树来理解,进行中序遍历。
2.注意考虑括号的问题,遇到右括号需要计算到相应的左括号之间的值
3.注意‘ + ’‘ - ’ ‘ * ’ ‘ / ’的运算优先级,运用哈希表(头文件为<unordered_map>)。
【散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。应用详见代码。】
【代码】
#include <iostream>
#include <cstring>
#include <stack>
#include <algorithm>
#include <unordered_map>
using namespace std;
stack<int> num;
stack<char> op;//num用来存放数值,op用来存放运算符
void eval(){
int b=num.top();num.pop();
int a=num.top();num.pop();//注意b和a的顺序
char c=op.top();op.pop();
int x=0;
if(c=='+') x=a+b;
if(c=='-') x=a-b;
if(c=='*') x=a*b;
if(c=='/') x=a/b;
num.push(x);
}//计算函数
int main(){
unordered_map<char,int> pr{{'+',1},{'-',1},{'*',2},{'/',2}};//哈希表 运算等级
string str;
cin>>str;
for(int i=0;i<str.size();i++){
auto c=str[i];
if(isdigit(c)){
int x=0,j=i;//j从i开始遍历
while(j<str.size()&&isdigit(str[j])){
x=x*10+str[j++]-'0';
}
i=j-1;//时刻更新i的值
num.push(x);//将数字存入数组
}
else if(c=='(') op.push(c);//存入左括号
else if(c==')'){
while(op.top()!='(') eval();
op.pop();
}//当遇到右括号时,从右到左运算到左括号,并弹出
else{
while(op.size()&&pr[op.top()]>=pr[c]) eval();
op.push(c);//根据优先级 存入运算符
}
}
while(op.size()) eval();//运算剩下的
cout<<num.top()<<endl;
return 0;
}
(ps:本题参照yxc)
另一个思路是把中缀表达式转换成后缀表达式求值 另开一个数组用来存放 还有计算函数以及优先级的设定 但需要注意判断合法的情况
类似的 OJ1358 中缀表达式
详见
练习1 OJ357 车厢调度
【代码】
#include <cstdio>
#include <iostream>
#include <stack>
using namespace std;
stack<char> t;
int a[1005];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
int i=1,m=1;//i为指针,b为入栈的数
while(i<=n&&m<=n+1){//不能超过总车厢数
if(!t.empty()&&a[i]<=t.top()){//栈内不为空且当前车厢编号小于等于栈顶元素
i++;//i指向下一位
t.pop();//当前车厢驶出
}
else t.push(m++);//否则 继续入栈
}
if(i>n) cout<<"YES";//能够遍历完整个数组 说明可以得到指定顺序
else cout<<"NO";
return 0;
}