codeup 1918 简单计算器

简单计算器
题目描述
读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。

输入
测试输入包含若干测试用例,每个测试用例占一行,每行不超过200个字符,整数和运算符之间用一个空格分隔。没有非法表达式。当一行中只有0时输入结束,相应的结果不要输出。

输出
对每个测试用例输出1行,即该表达式的值,精确到小数点后2位。

样例输入 Copy
30 / 90 - 26 + 97 - 5 - 6 - 13 / 88 * 6 + 51 / 29 + 79 * 87 + 57 * 92
0
样例输出 Copy
-代码1:不能计算负号

//北航机试2020/3/27
#include<iostream>
#include<stdio.h>
#include<stack>
#include<queue>
#include<string>
#include<map>
using namespace std;

/*
转化为后缀
后缀计算
*/

struct node
{
    double num;
    char op;
    bool flag;
};

string str;
stack<node> s;
queue<node> q;
map<char,int> op;

//转化为后缀
void Change()
{
    int i;
    //首先应该定义优先级
    //然后处理不同的字符(数字、运算符)
    double  num;
    node temp;
    for(i = 0;i<str.length();)
    {
        if(str[i]>='0' && str[i] <= '9')//数字
        {
            temp.flag = true;
            temp.num = str[i] - '0';//*****************
            i++;//**************************
            while(i<str.length()&&str[i]>='0'&& str[i]<='9')
            {
                temp.num =temp.num*10 + (str[i] - '0');
                i++;
            }
            q.push(temp);
        }
        else//操作符
        {
            temp.flag = false;
            while(!s.empty() && op[str[i]] <= op[s.top().op])
            {
                q.push(s.top());
                s.pop();

            }
            temp.op = str[i];
            s.push(temp);
            i++;
        }
    }
    while(!s.empty())
    {
        q.push(s.top());
        s.pop();
    }
}

double cal()
{
    double temp1,temp2;
    node cur,temp;//cur保存当前的队首元素、temp将两个操作符的结果保存
    while(!q.empty())
    {
        cur = q.front();
        q.pop();
        if(cur.flag == true)
        {
            s.push(cur);
        }
        else
        {
            temp2 = s.top().num;
            s.pop();
            temp1 = s.top().num;
            s.pop();

            temp.flag = true;
            if(cur.op == '-') temp.num = temp1-temp2;
            else if(cur.op == '+') temp.num = temp1 + temp2;
            else if(cur.op == '*') temp.num = temp1 * temp2;
            else temp.num = temp1/temp2;

            s.push(temp);
        }
    }
    return s.top().num;
}


int main()
{
    op['+'] = op['-'] = 1;
    op['*'] = op['/'] = 2;

    while(getline(cin,str),str!="0")
    {
 /*
        //去除所有的空格,注意没有使用size(),大小会发生变化
        for(string::iterator it = str.begin();it != str.end();it++)//***********
        {
            if(*it == ' ') str.erase(it);
        }
*/

         for(string::iterator it = str.end();it != str.begin();it--)//***********
        {
            if(*it == ' ') str.erase(it);
        }

        //cout<<str<<endl;

        while(!s.empty()) s.pop();//初始化栈
        Change();
        printf("%.2f\n",cal());
    }


    return 0;
}

  • 代码2:能够计算负号(如:-4-8*2)
    //只需要把上面的cal()函数替换成下面的即可
    首先需要判断的是什么情况下回进行负运算?
    当碰到运算符为-时会有两种情况
  • 第一种就是正常的减法运算,特征是此时的栈中的操作数>1
  • 第二种就是负运算,特征是栈中的操作数只有一个
double cal()
{
//能够运算负数
    double temp1,temp2;
    node cur,temp;//cur保存当前的队首元素、temp将两个操作符的结果保存
    while(!q.empty())
    {
        cur = q.front();
        q.pop();
        if(cur.flag == true)
        {
            s.push(cur);
        }
        else
        {

            if(cur.op == '-')
            {
                if(s.size() == 1)
                {
                    temp.num = 0-s.top().num;
                    s.pop();
                }
                else
                {
                    temp2 = s.top().num;
                    s.pop();
                    temp1 = s.top().num;
                    s.pop();
                    temp.num = temp1-temp2;
                }

            }
            else
            {
                temp2 = s.top().num;
                s.pop();
                temp1 = s.top().num;
                s.pop();
                if(cur.op == '+') temp.num = temp1 + temp2;
                else if(cur.op == '*') temp.num = temp1 * temp2;
                else temp.num = temp1/temp2;
            }
            temp.flag = 1;
            s.push(temp);
        }
    }
    return s.top().num;
}
  • 关于中缀表达式的计算
  • 计算中缀表达式”可以称得上是一个特别经典的关于栈的算法题,几乎在所有数据结构教材中都会涉及,而且很多公司面试或者笔试的时候都会把这道题作为一个考察点。可以说,这是一道必须要掌握的算法题。中缀表达式、后缀表达式等概念在这里就不赘述了,让我们直奔主题。
    题目:输入一个中缀表达式,计算其结果。
    输入的前提假设:
    (1)只考虑+、-、、/这四种运算符,中缀表达式中只有一种括号:();
    (2)输入的中缀表达式中只有整数,没有小数;
    (3)假定输入是合法的。
    很多文章或课本喜欢一步到位,直接讨论如何从中缀表达式计算结果。但对于初学者来说,跨度未免大了点。这里循序渐进,从易到难,先讨论如何将中缀表达式转化为后缀表达式,再讨论如何计算后缀表达式。最后在前面两步的基础上,讨论如何一步到位,直接计算中缀表达式的结果:
    一、如何将中缀表达式转化为后缀表达式
    在日常应用中,算术表达式中运算符总是出现在两个操作数之间,例如5
    (7-23)+8/2,这种形式称为中缀表达式。计算一个中缀表达式需要知道运算符的优先级和结合性。乘除是高优先级,加减是低优先级,优先级相同时他们都是左结合的,也就是从左计算到右。有括号就要计算括号内的表达式。
    中缀表达式利于人的理解,但不便于计算机的处理。因此需要将中缀表达式转换成后缀表达式,以方便计算机处理。所谓后缀表达式就是将运算符放在运算数之后。后缀表达式也称为逆波兰表达式。
    比如:
    中缀表达式为:1+(2-3)4+4/2
    对应后缀表达式为:1 2 3 - 4
    + 4 2 / +
    如何将一个中缀表达式转化为后缀表达式?我们需要借助栈的力量,用它来存放运算符。算法流程如下:
    首先将各种运算符(包括括号)的优先级排列如下(数字越大,优先级越高):
    1:(
    2:+ -
    3:
    /
    4:)
    对输入的中缀表达式从左到右遍历:
    1)如果遇到数字,直接添加到后缀表达式末尾;
    2)如果遇到运算符+、-、*、/:
    先判断栈是否为空。若是,则直接将此运算符压入栈。若不是,则查看当前栈顶元素。若栈顶元素优先级大于或等于此操作符级别,则弹出栈顶元素,将栈顶元素添加到后缀表达式中,并继续进行上述判断。如果不满足上述判断或者栈为空,将这个运算符入栈。要注意的是,经过上述步骤,这个运算符最终一定会入栈。
    3)如果遇到括号:
    如果是左括号,直接入栈。如果是右括号,弹出栈中第一个左括号前所有的操作符,并将左括号弹出。(右括号别入栈)。
    4)字符串遍历结束后,如果栈不为空,则弹出栈中所有元素,将它们添加到后缀表达式的末尾,直到栈为空。
    二、计算后缀表达式
    后缀表达式的计算就相当简单了。准备一个数字栈。从左到右扫描后缀表达式,如果是数字,放入数字栈。如果是符号,从数字栈中弹出两个数字,第一个取出的数字为右运算数,第二个为左运算数,进行运算。然后将结果放进数字栈中。如此反复,直到读完整个表达式后,留在数字栈中的那个数字就是最终结果。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值