-
读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。
原题地址:http://ac.jobdu.com/problem.php?pid=1019
题目描述:
-
输入:
-
测试输入包含若干测试用例,每个测试用例占一行,每行不超过200个字符,整数和运算符之间用一个空格分隔。没有非法表达式。当一行中只有0时输入结束,相应的结果不要输出。
-
输出:
-
对每个测试用例输出1行,即该表达式的值,精确到小数点后2位。
-
样例输入:
-
1 + 2 4 + 2 * 5 - 7 / 11 0
-
样例输出:
-
3.00 13.36
-
来源:
本题考查的是利用堆栈对表达式求值,这类问题的基本思想如下:
1.设立两个堆栈,一个用来存放运算符,一个用来存放操作数。
2.从左到右遍历字符串,如果遍历到运算符,则将其与运算符栈顶元素进行比较,若新运算符的优先级大于(严格大于!后面会解释)栈顶运算符,或者栈为空,则将新运算符压入栈。
3.如果新运算符的优先级小于等于栈顶运算符,则弹出栈顶运算符,再从数字栈中弹出两个数字做对应的运算,计算的结果压入数字栈,重复第三步,直到满足新运算符的优先级大于栈顶运算符。
4.遍历到数字直接入栈。遍历到字符串结束则将剩余符号栈中的运算符依次计算直到清空。
值得注意的点:
√计算结果可能是浮点数,涉及计算的结果都要声明为double型。
√一行中只有0时输入结束,意味着这一行的字符串为"0\0",不能只根据第一个符号为0就退出,比如01 + 2是允许的。
√遍历当前元素时,需要判断是符号还是数字,是数字则只需要改变函数的传参IsOp,是数字则要读入之后可能紧接着的数字(一般都不是一位数),返回这个整数。
√ 当前指向运算符的情况下,根据上述基本思想的规则,比较栈顶运算符和新运算符的优先级。注意!由于本题不存在括号,入栈新运算符的优先级必须严格大于栈顶运算符,比如栈顶是/号,来了一个*号,如果直接把*号进栈而不弹出/号,那么之后的遍历中,会导致/优先计算,比如会出现3/3*2*2=0.25的情况,而实际上应该3/3先做计算。(就算设置除法优先级优高于乘法也不能取>=,会存在3/3/6 = 6的问题,所以必须严格大于才能入栈!)
AC代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <ctype.h>
#include <stack>
#define MAXLEN 205
using namespace std;
char str[MAXLEN];
stack<char> op;
stack<double> num;
int get_priority(char c) //定义四则运算的优先级
{
if (c == '+' || c == '-') //加减法同级
return 1;
if (c == '*' || c == '/') //乘除法同级
return 2;
else return 0;
}
double JudgeOpNum(bool &IsOp, int &index)
{
if(!isdigit(str[index])) //当前字符是运算符
{
IsOp = true;
return -1;
}
else //当前字符是数字,取出这个整数
{
IsOp = false;
double tmp = 0;
while (str[index] != '\0' && str[index] != ' ')
{
tmp = tmp*10 + (str[index]-'0');
index++; //返回时的index指向空格或'\0'
}
return tmp;
}
}
void Calculate() //取出num栈顶的两个数做op栈顶运算,结果压入num栈
{
char c = op.top(); op.pop();
double r = num.top(); num.pop();
double l = num.top(); num.pop();
double tmp = 0;
if (c == '+') tmp = l+r;
else if (c == '-') tmp = l-r;
else if (c == '*') tmp = l*r;
else tmp = l/r;
num.push(tmp);
}
double ClearStack() //清空符号栈和数字栈
{
while (!op.empty())
Calculate();
double res = num.top(); num.pop();
return res;
}
int main()
{
while(gets(str))
{
if(str[0] == '0' && str[1] == '\0') //只有0
break;
int index = 0; //当前操作的下标
bool IsOp = false;
while (1)
{
if (str[index] == ' ') index++; //跳过空格
if (str[index] == '\0') //表达式已经处理完毕,直接计算出结果
{
double result = ClearStack();
printf("%.2f\n",result);
break;
}
double ret_num = JudgeOpNum(IsOp, index); //判断当前元素是符号还是数字
if (IsOp == false) //当前指向的数字入栈
{
num.push((double)ret_num);
}
else //当前指向运算符
{
//如果符号栈空或者新符号优先级大于栈顶符号(必须是>,不能是>=,否则会出现3/3*2*2=0.25的情况)
if (op.empty() || get_priority(str[index]) > get_priority(op.top()) )
op.push(str[index]);
else //新符号优先级小于栈顶符号
{
while (!op.empty() && get_priority(str[index]) <= get_priority(op.top())) //重复直到高优先级运算完(保证栈不空)
Calculate();
op.push(str[index]); //新运算符入栈
}
index += 2; //跳掉空格
}
}
memset(str, 0, MAXLEN);
}
return 0;
}
内存占用:1524Kb 耗时:0ms
算法复杂度: O(n)