九度OJ 1019 简单计算器(栈的应用)

来源:互联网 发布:js实现二级菜单导航 编辑:程序博客网 时间:2024/05/16 06:11

原题地址:http://ac.jobdu.com/problem.php?pid=1019

题目描述:

    读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。
输入:
    测试输入包含若干测试用例,每个测试用例占一行,每行不超过200个字符,整数和运算符之间用一个空格分隔。没有非法表达式。当一行中只有0时输入结束,相应的结果不要输出。
输出:
    对每个测试用例输出1行,即该表达式的值,精确到小数点后2位。
样例输入:
1 + 24 + 2 * 5 - 7 / 110
样例输出:
3.0013.36
来源:

2006年浙江大学计算机及软件工程研究生机试真题


本题考查的是利用堆栈对表达式求值,这类问题的基本思想如下

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 205using 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)

0 0
原创粉丝点击