简单计算器
描述
读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。
输入描述:
测试输入包含若干测试用例,每个测试用例占一行,每行不超过200个字符,整数和运算符之间用一个空格分隔。没有非法表达式。当一行中只有0时输入结束,相应的结果不要输出。
输出描述:
对每个测试用例输出1行,即该表达式的值,精确到小数点后2位。
示例
输入:
1 + 2
4 + 2 * 5 - 7 / 11
0
输出:
3.00
13.36
这个题有个比较坑的点,也是因为本人比较菜。。。做栈相关的题目还是多找几个例子在纸上先模拟一下比较好
新的运算符如果优先级和栈顶的运算符的优先级一样的话,要先算栈顶的运算符,这个原理其实就是在计算表达式的过程中对于优先级相同的要遵循从左往右计算的顺序。如果不这样算的话,对于栈,我们都知道,是后进先出,有逆序的特点,那么举个例子 3/1×3,如果除号入栈之后,乘号也入栈之后,那么弹栈的时候就是先计算1×3得3了,然后3/3=1,与原来的3/1×3=9的结果大不相同,相当于计算了3/(1×3),多给加了个括号,即证开始的规则
#include<bits/stdc++.h>
using namespace std;
//表达式求值
//这儿的下标i必须是引用类型
//因为需要不断获取下一位数字的下标
//而且此处的下标变了在main函数中的下标也要发生变化
//因此是引用类型
int getnum(string str,int& i){
double num=0;
while(isdigit(str[i])){
num=num*10+str[i]-'0';
i++;
}
return num;
}
int getprior(char s){
//#和$的优先级大小
//#的优先级要比$小,如果#优先级高无法取操作数做#运算,因为#本身不是什么运算
//$的优先级次低是为了在字符串中最后一个操作数读入数据栈中之后
//能够通过$与符号栈栈顶符号的不断比较, 最终完成运算
//以上解释不明白的话,可以在纸上画出栈利用示例模拟一下就懂了
//符号的优先级次序为 #$+-*/
if(s=='#'){
return 0;
}
else if(s=='$'){
return 1;
}
else if(s=='+'||s=='-'){
return 2;
}
else{
return 3;
}
}
double calculate(double data1,double data2,char ch){
double data3;
if(ch=='+'){
data3=data1+data2;
}
else if(ch=='-'){
data3=data1-data2;
}
else if(ch=='*'){
data3=data1*data2;
}
else if(ch=='/'){
data3=data1/data2;
}
return data3;
}
int main(){
//两个栈,一个符号栈,一个运算数栈
string str;
while(getline(cin,str)){
if(str=="0"){
break;
}
stack<char> opr;
stack<double> data;
//运算符栈的底部是#
opr.push('#');
//字符串表达式的末尾是$,用来标志结束
str+='$';
int i=0;
while(i<str.length()){
if(str[i]==' '){
i++;
}
else if(isdigit(str[i])){
//是数字,但要考虑数字的位数
//入数据栈的必须是完整的数
data.push(getnum(str,i));
//传的参数必须是整个字符串,因为需要进一步去找寻下一位数字
}
else{
//是运算符
if(getprior(str[i])<=getprior(opr.top())){
//如果新的运算符的优先级小于等于运算符栈顶的
//先运算栈顶优先级高的
double data2=data.top();
data.pop();
double data1=data.top();
data.pop();
char ch=opr.top();
double data3 = calculate(data1,data2,ch);
data.push(data3);
opr.pop();
}
else{
//新的运算符的优先级大于运算符栈顶
//直接入栈
opr.push(str[i]);
i++;
}
}
}
cout<<fixed<<setprecision(2)<<data.top()<<endl;
}
return 0;
}