Time Limit: 3 second
Memory Limit: 2 MB
问题描述
从键盘上输入算术表达式串(只含+、-、*、/运算符,允许含圆括号,运算数为整型、实型常量),输出算术表达式的值。设输入的表达式串是合法的。
Input
输入为一行算术表达式串
Output
输出一行,算术表达式的值(输出两位小数,整数部分按实际位数输出,最后用换行结束)。
Sample Input
(3+2)-5*(6-1)
Sample Output
-20.00
【题解】
用分治法来求中缀表达式:
具体过程.每层递归,都找到所有运算符里面优先级别最低的运算符。
假设这个运算符的位置为k
则把1..k-1截出来 设为x,k+1..length(s)也截出来,设为y;
然后对x和y进行相同的操作。也去找运算级别最小的运算符。。。
直到最后操作的一个字符串全是数字。然后就返回这个数字就好。
最后根据k位置的运算符。做相应的运算。
即"x" 运算符 "y";
【代码】
#include <cstdio> #include <stdlib.h> #include <string> #include <iostream> using namespace std; string s; char cmp(char x, char y) //判断操作符x和操作符y,哪一个优先级大 { if (x == '$') return '>'; if ( (x == '*' || x == '/') && (y == '+' || y =='-'))//乘法和除法的优先级比加减法高 return '>'; if ( (x == '+' || x == '-') && (y == '+' || y =='-')) //如果是同一优先级。则往后找运算符。因为同一优先级先找到的是后运算的 return '>'; if ( (x == '*' || x == '/') && (y == '*' || y =='/')) //依旧是同一优先级的处理; return '>'; return '<'; } int find(string tt) //表示找tt这个字符串的优先级最小的操作符 { int k =0; char now = '$'; int i = 0; while (i <= tt.size()-1) //用i来枚举 { if (tt[i] == '(') //如果是括号的话就要跳过。因为括号里的东西一定是后算的,不能考虑优先级 { int b = 0; //这是用来匹配这个括号,当然可能有多个括号 用栈的思想来匹配 do { switch (tt[i]) { case '(': b++; break; case ')': b--; break; } i++; } while (b !=0); } else if (tt[i] == '*' || tt[i] == '/' || tt[i] == '+' || ( tt[i] == '-' && i >0 && (tt[i-1] ==')' || (tt[i-1] >='0' && tt[i-1] <='9')))) { //如果是运算符,就先和当前获得的优先级最小的运算符比较。看看是否优先级更低 if (cmp(now,tt[i]) == '>') { now = tt[i];//如果更低 则更新 k = i; } i++; } else i++; //不管是什么 都要递增循环变量 } return k; } void reducebracket(string & tss) //去掉两边的括号 表示对括号里的string进行操作 { int ltss = tss.size(); //表示tss的长度 if (tss[0] !='(' || tss[ltss-1]!=')') //如果两边不是配对的括号就返回。 return; int b =0; for (int i = 1;i <= ltss-2;i++) //表示在2到l-1之间查看括号是否配对,因为可能有()+()这样的情况。 { if (tss[i] == '(') b++; if (tss[i] == ')') b--; if (b < 0) return; } if (b!=0) return; tss = tss.erase(ltss-1,1); //去除两边的括号 tss = tss.erase(0,1); } double reduce( string ss) { int i = 0,ls = ss.size(); if (ls == 0) //如果长度为0,则直接返回0; return 0; bool judge = false; //表示是否找到了运算符 while (i <= ls-1) { if (ss[i] == '+' || ss[i] == '*' || ss[i] == '/') //+*/都可以直接判断 { judge = true; break; } else //如果是减法的话,要判断它前一位是不是右括号或者是数字。因为可能是负数 if (ss[i] == '-' && i > 0 && (ss[i-1] == ')' || (ss[i-1] >='0' && ss[i-1] <='9'))) { judge = true; break; } i++; } if (!judge) //如果没有运算符。则这个串就是一个数字。直接返回就可以了 { double x = atof(ss.c_str()); return x; } reducebracket(ss); //如果有运算符。就先去掉两边的括号(如果有) int k = find(ss); //找到运算级别最小的运算符的位置 string s1 = ss.substr(0,k); //截取这个运算符左边的"数字" string s2 = ss.substr(k+1,ss.size()-s1.size()-1); //截取这个运算符右边的"数字" double x = reduce(s1),y = reduce(s2),z; //对左边和右边的进行计算。 switch (ss[k]) //对ss[k]进行判断 根据运算符做相应的运算。 { case '+': z = x + y; break; case '-': z = x - y; break; case '*': z = x * y; break; case '/': z = x / y; break; } return z; //返回这个值。 } int main() { //freopen("F:\rush.txt","r",stdin); getline(cin,s); printf("%.2lf",reduce(s)); return 0; }