HDU - 1237
题目描述
简单计算器
读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。
Input
测试输入包含若干测试用例,每个测试用例占一行,每行不超过200个字符,整数和运算符之间用一个空格分隔。没有非法表达式。当一行中只有0时输入结束,相应的结果不要输出。
Output
对每个测试用例输出1行,即该表达式的值,精确到小数点后2位。
Sample Input
1 + 2
4 + 2 * 5 - 7 / 11
0
Sample Output
3.00
13.36
在这里我简单地修改题目,允许使用括号,也允许小数输入,之后的代码也支持这个功能,原题AC代码可以自行修改
题目大意
中文题目不用解释,在这个修改中,加入了括号的使用,在判断时要加上对括号的判断,在读取数字时,要额外考虑小数点的状况。此外,表达式中没有空格,这就意味着一次性输入,这不同于逆波兰表达式求值的一些内容。
解题方法
使用递归的方法。
我们逐层分析
- 表达式expression,它由若干个项term组成,每个项之间用’+’或者’-‘连接。
- 项term,它由若干个因子factor组成,每个因子之间用’*’或者’/’连接。
- 因子factor,它由一个数字或者一个()括号表达式组成,在这里我们看到了递归,括号表达式即为一个递归条件,它的终止条件是因子是一个数。
因此我们需要这么几个函数:experssion_value(),term_value(),factor_value()。用他们分别计算表达式的值,项的值以及因子的值。其中,用expression_value()调用term_value(),term_value()调用factor_value(),factor_value()达到终止条件或者递归调用experssion_value()。总之,中间有个层级关系,要捋清递归关系。
另外一个问题,要对字符串进行操作,这里用到的方法使用cin.peek()和cin.get()进行读取和读出。其中,cin.peek()会返回输入流中的第一个字符,但不会删除,cin.get()同样返回输入流中的第一个字符,但是会删除。这样就方便了我们对字符串进行操作,只需要查看第一个字符的类型,就可以知道表达式中的运算关系。
举个例子:
表达式3.4+2*(6*4+1/5)
调用experssion_value()计算表达式的值,进入函数,用term_value()计算第一个项的值,进入term_value()函数,用factor_value()计算第一因子的表达式,cin.peek()发现第一个字符为3,则循环读取3.4,返回term_value(),没有其他因子,返回experssion_value(),存入结果result,cin.peek()读取到’+’,调用term计算第二项的值,同理,计算返回后,与rusult相加,得到答案。
另外,从字符串读取一个小数的代码如下:
#include <iostream>
#include <cstdio>
#include <cctype>
#include <cmath>
using namespace std;
int main()
{
int dot = 0;
double result = 0;
char op;
op = cin.peek();
while(isdigit(op) || op == '.') //isdigit()为cctype中的函数,用于判断一个数是否为十进制数字
{
if(op == '.')
{
dot = -1;
cin.get();
op = cin.peek();
}
else
{
if(dot == 0)
{
cin.get();
result = 10 * result + op - '0';
op = cin.peek();
}
else
{
cin.get();
result += pow(10, dot) * (op - '0');
dot --;
op = cin.peek();
}
}
}
printf("%.2f\n", result);
return 0;
}
以下为题解代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <algorithm>
using namespace std;
float factor_value();
float term_value();
float expression_value();
int main()
{
printf("%.2f\n", expression_value());
return 0;
}
float expression_value()
{
float result = term_value();
bool more = true;
while(more)
{
char op = cin.peek();
if(op == '+' || op == '-')
{
cin.get();
float value = term_value();
if(op == '+')
result += value;
else
result -= value;
op = cin.peek();
}
else
more = false;
}
return result;
}
float term_value()
{
float result = factor_value();
bool more = true;
while(more)
{
char op = cin.peek();
if(op == '*' || op == '/')
{
cin.get();
float value = factor_value();
if(op == '*')
result *= value;
else
result /= value;
op = cin.peek();
}
else
more = false;
}
return result;
}
float factor_value()
{
float result = 0;
char op = cin.peek();
if(op == '(')
{
cin.get();
result = expression_value();
cin.get();
}
else
{
int dot = 0;
while(isdigit(op) || op == '.')
{
cin.get();
if(op == '.')
{
dot = -1;
op = cin.peek();
}
else
{
if(dot == 0)
{
result = 10 * result + op - '0';
op = cin.peek();
}
else
{
result += pow(10, dot) * (op - '0');
dot --;
op = cin.peek();
}
}
}
}
return result;
}