中缀表达式转后缀表达式并求值(多位数)
一、问题简述
- 中缀表达式:是一种通用的算术或逻辑公式表示方法,操作符处于操作数的中间。中缀表达式是人们常用的算术表示方法,如3+5*8。
- 后缀表达式(逆波兰表达式):运算符位于两个相应操作数之后,更方便计算机的运算,如3 5 8 * +。
- 为了方便计算机的运算,我们需要把中缀表达式转成后缀表达式。(也可直接计算中缀表达式的值)
二、背景题目:中缀表达式的值(北大oj平台)
-
描述
人们熟悉的四则运算表达式称为中缀表达式,例如(23+34*45/(5+6+7))。在程序设计语言中,可以利用堆栈的方法把中缀表达式转换成保值的后缀表达式(又称逆波兰表示法),并最终变为计算机可以直接执行的指令,得到表达式的值。 给定一个中缀表达式,编写程序,利用堆栈的方法,计算表达式的值。
-
输入
第一行为测试数据的组数N 接下来的N行,每行是一个中缀表达式。表达式中只含数字、四则运算符和圆括号,操作数都是正整数,数和运算符、括号之间没有空格。中缀表达式的字符串长度不超过600。
-
输出
对每一组测试数据输出一行,为表达式的值
-
样例输入
3 3+5*8 (3+5)*8 (23+34*45/(5+6+7)) `
-
样例输出
43 64 108
-
提示
注意:运算过程均为整数运算(除法运算’/'即按照C++定义的int除以int的结果,测试数据不会出现除数为0的情况),输出结果也为整数(可能为负)。 中间计算结果可能为负。
三、表达式转换思路
- 多位数的计算与一位数的计算有差别:需要将字符串表达式中的多位数字分出来(下面代码中的初始化部分)。用vector来接收分解出string表达式中的数字和字符。
- string_to_int函数将字符串数组中的数字部分转为int类型用于表达式的计算。
- 中缀转后缀:扫描已初始化后的字符串数组,建立一个辅助栈和存储后缀表达式的字符串数组。
- 当遇到数字时:直接输出,即push_back到辅助字符串数组。
- 当遇到操作符时(该操作符不是右括号):如果栈空就直接入栈;如果栈不为空,则用该 操作符与栈顶的操作符作比较,若操作符优先级比栈顶操作符优先级高,直接入栈,否则弹栈并输出直到栈为空或遇到优先级更低的操作符 (除了左括号),再将该操作符入栈。
- 当遇到右括号:顺序出栈并输出(入辅助字符串数组)直到遇到左括号,最后将左括号出栈,不输出左括号。
- 扫描结束后:将栈中所有元素出栈并输出(入辅助字符串数组)。
四、后缀表达式计算
- 扫描中缀表达式转换后的后缀表达式,建立一个辅助栈。
- 若遇到数字,将其转成int类型并入辅助栈。
- 若遇到操作符就从栈顶出栈两个元素并进行相应的运算,将结果再入栈。
- 依次进行,最后的栈顶元素即为表达式的结果。
五、代码实现
#include<iostream>
#include<string>
#include<stack>
#include<cstdlib>
#include<sstream>
#include<vector>
using namespace std;
int string_to_int(string a){
stringstream ss;
int s;
ss<<a;
ss>>s;
return s;
}
int judge(string a){
if(a=="+"||a=="-")
return 1;
else if(a=="*"||a=="/")
return 2;
else if(a=="(")
return 3;
else if(a==")")
return -1;
else
return 0;
}
vector<string> chu_shi_hua(string s){//初始化
vector<string>a;
int j,i;
i=0;
while(i<s.size())
{ j=i;
while(j<s.size()&&s.at(j)<='9'&&s.at(j)>='0'){
j++;
}
if(i==j){
a.push_back(s.substr(i,1));
i=i+1;
}
else{
a.push_back(s.substr(i,j-i));
i=j;
}
}
return a;
}
int calculate(vector<string> s){
stack<int> result;
int a,b;
for(int i=0; i<s.size();i++){
if(judge(s[i])==0)
result.push(string_to_int(s[i]));
else{
a=result.top();
result.pop();
b=result.top();
result.pop();
if(s[i]=="+")
result.push(b+a);
if(s[i]=="-")
result.push(b-a);
if(s[i]=="*")
result.push(a*b);
if(s[i]=="/")
result.push(b/a);
}
}
return result.top();
}
vector<string> zhong_hou(vector<string> s){
stack<string> result;
vector<string> save;
for(int i=0; i<s.size();i++){
if(judge(s[i])==0)//遇到数字就直接输出
save.push_back(s[i]);
if(judge(s[i])>0){
if(result.empty())//栈为空则直接压栈
result.push(s[i]);
else{
if(judge(s[i])>judge(result.top()))//操作符优先级比栈顶操作符优先级高
{ result.push(s[i]);
}
else{
while((!result.empty())&&judge(result.top())>=judge(s[i])&&result.top()!="(")//弹栈并输出直到栈为空或遇到优先级更低的操作符 (除了左括号)
{
save.push_back(result.top());
result.pop();
}
result.push(s[i]);
}
}
}
if(judge(s[i])==-1){
while(result.top()!="("){
save.push_back(result.top());
result.pop();
}
result.pop();
}
}
while(!result.empty()){
save.push_back(result.top());
result.pop();
}
return save;
}
int main(){
int n;
string s1;//s1表达式
vector<string> s2,s3;//s2是初始化后的表达式,将多位的数字分出来。s3是后缀表达式
cin>>n;
while(n--){
cin>>s1;
s2=chu_shi_hua(s1);
s3=zhong_hou(s2);
cout<<calculate(s3)<<endl;
}
return 0;
}