题意:求解一串不出现数学公式只含\'+\',\'-\',\'*\',\'/\', \'(\' , \')\'的计算表达式,输出结果;
其中\'/\'是带小数的除法。并且输入的数值位double型,若是输入的运算符有误,或者出现除0错误,则直接输出intput error.
输入时除数值之间不能出现空格外,其他地方均能有空格。并且3(...)看成为3*(); 0.5也可以输入为.5;
注意:代码中目前没有加入识别是减号还是符号的处理;所以只能处理非负整数之间的运算;
实现细节:以运算符的优先级来设置一个优先级(数学意义)递减的单调栈。但是给予\'(\' ,\')\'不一样的优先级;即栈中实际上只是存储的是\'+\',\'-\'运算,\'*\',\'/\'运算会计算出数值;没遇到一个\')\'。表示计算与前一个\'(\'之间的所有值;最后加发\')\'为了全部计算完。
ps:由于只是随便写的,要是发现bug直接指出即可;
#include<iostream> #include<cstdio> #include<cstring> #include<map> #include<cmath> #define esp 1e-7 using namespace std; char s[3000],op[1000]; double v[1000]; map<char,int> mp; bool solve() { mp[\'*\'] = 1,mp[\'/\'] = 1,mp[\'+\'] = 2,mp[\'-\'] = 2,mp[\'(\'] = 3, mp[\')\'] = 4;//维护一个单调递增的栈; int len = strlen(s),stk = 0,top = 0; s[len++] = \')\'; op[++stk] = \'(\'; for(int i = 0;i < len;i++)if(s[i] != \' \'){//容许输入有空格; if(s[i] != \'.\' && s[i] < \'0\' || s[i] > \'9\'){//可能输入的小数位 .5 即0.5 if(mp.find(s[i]) == mp.end()) return false; while(stk >= 1 && mp[op[stk]] < mp[s[i]] && s[i] != \'(\'){ if(stk == 1 && i != len - 1) return false; if(s[i] == \')\' && op[stk] == \'(\'){stk--; break;} if(op[stk] == \'+\') v[top-1] += v[top]; else if(op[stk] == \'-\') v[top-1] -= v[top]; else if(op[stk] == \'*\') v[top-1] *= v[top]; else if(op[stk] == \'/\') if(fabs(v[top]) < esp) return false;//除0; else v[top-1] /= v[top]; top--;stk--; } if(s[i] != \')\') op[++stk] = s[i]; } else{ double val = 0.0,f = 1; if(s[i] == \'.\') f /= 10,i++; for(;s[i] >= \'0\' && s[i] <= \'9\';i++){//小数不能写成 .1这样的形式; if(f == 1){ val = val*10 + (s[i]-\'0\'); } else{ val += f*(s[i] - \'0\'); f /= 10; } if(s[i+1] == \'.\') f = 0.1,i++; if(f < 1 && s[i+1] == \'.\') return false;//出现多个小数点 } if(s[i--] == \'(\') op[++stk] = \'*\';// 3(2 - 4) = 3*(2 - 4) v[++top] = val; } } return stk?false:true;//最终符号栈中没有一个符号 } int main() { while(gets(s), strlen(s)){ if(solve()) printf("%f\n",v[1]); else puts("input error"); } }