简单计算器 - 九度教程第27题
题目
时间限制:1 秒 内存限制:32 兆 特殊判题:否
题目描述:
读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。
输入:
测试输入包含若干测试用例,每个测试用例占一行,每行不超过200个字符,整数和运算符之间用一个空格分隔。没有非法表达式。当一行中只有0时输入结
束,相应的结果不要输出。
输出:
对每个测试用例输出1行,即该表达式的值,精确到小数点后2位。
样例输入:
1 + 2
4 + 2 * 5 - 7 / 11
0
样例输出:
3.00
13.36
来源:
2006年浙江大学计算机及软件工程研究生机试真题
利用堆栈对表达式求值的方法:
1.设立两个堆栈,一个用来保存运算符,另一个用来保存数字。
2.在表达式首尾添加标记运算符,该运算符运算优先级最低。
3.从左至右依次遍历字符串,若遍历到运算符,则将其与运算符栈的栈顶元素进行比较,若运算符栈的栈顶运算符优先级小于该运算符或者此时运算符栈为空,则将该运算符压入堆栈。遍历字符串中下一个元素。
4.若运算符栈的栈顶运算符优先级大于该运算符,则弹出该栈顶运算符,再从数字栈中依次弹出两个栈顶数字,完成弹出的运算符对应的运算并得到结果后,再将该结果压入数字栈,重复比较此时栈顶运算符与当前遍历到的运算符优先级,视其优先级大小重复步骤3或步骤4。
5.若遍历到表达式中的数字,则直接压入数字栈。
6.若运算符堆栈中仅存有两个运算符且栈顶元素为我们人为添加的标记运算符,那么表达式运算结束,此时数字堆栈中唯一的数字即为表达式的值。
#include <stdio.h>
#include <stack>
using namespace std;
char str[201];//保存表达式字符串
int mat[][5]={
//优先级矩阵,若mat[i][j]==1,则表示i号运算符优先级大于
//j号运算符,运算符编码规则为:+为1号,-为2号,*为3号,/为4号
//人为添加在表达式首尾的标记运算符@为0号
// @ + - * /
// @ 1 0 0 0 0
// + 1 0 0 0 0
// - 1 0 0 0 0
// * 1 1 1 0 0
// / 1 1 1 0 0
1,0,0,0,0,
1,0,0,0,0,
1,0,0,0,0,
1,1,1,0,0,
1,1,1,0,0,
};
stack<int> op;//运算符栈,保存运算符编号
stack<double> in;//数字栈,运算结果可能存在浮点数(除法)
void getOp(bool &reto, int &retn, int &i){
//获得表达式中下一个元素。若函数运行结束时,
//引用变量reto为true,则表示该元素为运算符,
//其编号保存在引用变量retn中;否则表示该元素
//为数字,其值保存在retn中。i表示遍历的字符串下标
if(i==0 && op.empty()==true){
//若此时遍历字符串第一个字符且运算符栈为空,
//人为添加编号为0的标记字符
reto=true;
retn=0;
return;
}
if(str[i]==0){
//若此时遍历字符为空字符,则表示字符串已被遍历完,
//人为添加编号为0的标记字符
reto=true;
retn=0;
return;
}
if(str[i]>='0' && str[i]<='9'){
//若此时遍历字符为数字
reto=false;
retn=0;//返回结果为数字
for(;str[i]!=0 && str[i]!=' ';i++){
//若字符串未被遍历完且下一个字符不是空格
//则依次遍历其后数字,计算当前连续数字字符表示的数值
retn*=10;
retn+=str[i]-'0';
}//计算该数字的数字值
if(str[i]==' '){
//若字符为空格
i++;//i递增,跳过该空格
return;
}
}else{
reto=true;//返回为运算符
if(str[i]=='+'){
retn=1;
}else if(str[i]=='-'){
retn=2;
}else if(str[i]=='*'){
retn=3;
}else{//(str[i]=='/')
retn=4;
}
i+=2;//i递增,跳过该运算符和其后的空格
return;
}
return;
}
int main()
{
while(gets(str)){//输入字符串,当其位于文件尾时gets返回0
if(str[0]=='0' && str[1]==0)break;
bool retop;
int retnum;
int idx=0;//遍历字符串的下标
while(!op.empty())op.pop();//清空运算符栈
while(!in.empty())in.pop();//清空数字栈
while(true){
getOp(retop,retnum,idx);//获取表达式中下一个元素
if(retop==false){
//若该元素为数字将其压入数字栈中
in.push((double)retnum);
}else{
double tmp;
if(op.empty()==true || mat[retnum][op.top()]==1){
//若运算符栈为空或当前遍历到的运算符优先级大于栈顶运算符
//将该运算符压入运算符栈
op.push(retnum);
}else{
while(mat[retnum][op.top()]==0){
//只要当前运算符优先级小于栈顶运算符则重复循环
int ret=op.top();//保存栈顶运算符
op.pop();//弹出栈顶运算符
double b=in.top();
in.pop();
double a=in.top();
in.pop();
//从数字栈栈顶弹出两个数字,按压栈顺序保存在a,b中
if(ret==1)tmp=a+b;
else if(ret==2)tmp=a-b;
else if(ret==3)tmp=a*b;
else tmp=a/b;
in.push(tmp);//将结果压回数字栈
}
op.push(retnum);//将当前运算符压入运算符栈
}
}
if(op.size()==2 && op.top()==0)break;
//若运算符栈只有两个且其栈顶元素为标记运算符,则表示表达式求值结束
}
printf("%.2f\n",in.top());
//输出数字栈中唯一的数字,即为答案,保留两位小数
}
return 0;
}