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;
}