codeup1918 计算中缀表达式(C++)


题目

题目描述

读入一个只包含+、-、*、/的非负整数计算表达式,计算该表达式的值。

输入格式

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

输出格式

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

样例输入

30 / 90 - 26 + 97 - 5 - 6 - 13 / 88 * 6 + 51 / 29 + 79 * 87 + 57 * 92

样例输出

12178.21

分析

  1. 主要过程是通过给出的中缀表达式转换成后缀表达式,然后计算出结果;
  2. 注意如何把包括空格在内的一行字符串读入,以及如何解决读取的操作数可能不止一位的情况;
  3. 算法需要频繁使用栈和队列,使用STL中的stack和queue类比较方便。

下列给出算法的主要思路流程:
步骤1:中缀表达式转后缀表达式
while(中缀队列非空)
{
     if(当前指向的是操作数)
        加入到后缀队列中;
    else if(当前指向的是操作符)
    {
        if(栈为空||当前指向的操作符优先级高于栈顶操作符优先级)
            压入操作符栈;
    else
     {
        while(栈为空&&当前指向操作符优先级低于或等于栈顶操作符优先级)
            弹出并加入后缀队列;
        压入操作符栈;
     }
}
操作栈内操作符依次弹出并放入后缀队列.

步骤2: 计算后缀表达式
while(后缀队列非空)
{
     if(当前指向队列元素是操作数)
          压入栈内;
     else //是操作符
     {
          先后从栈中弹出第二操作数、第一操作数(注意顺序);
          结合操作符计算并将结果压入栈内;
     }
}

代码

#include <iostream>
#include <fstream>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <cmath>

using namespace std;

map<char,int> mp;

struct node
{
    float num;
    char c;
    bool flag;    //flag=true:是操作数 flag=false:是操作符
};


int isOperator(char c)   //判断是否是操作符,如果是则返回优先级(2:乘除 1:加减),否则返回-1(表示是操作数)
{
    return mp[c];
}


//将字符串(中缀表达式)转成后缀表达式
void GetPostfix(queue<node> infixQ,queue<node> &postfixQ)
{
    int i=0,level;
    stack<node> S;
    while(!infixQ.empty())    //遍历中缀表达式中所有字符
    {
        node nd=infixQ.front();
        if(nd.flag==true)     //是操作数
        {
            nd.flag=true;
            postfixQ.push(nd);   //加入后缀队列中
        }
        else                         //是操作符
        {
            nd.flag=false;
            if(S.empty()||isOperator(nd.c)>isOperator(S.top().c))   //当前OP优先级高于栈顶OP
                S.push(nd);
            else                    //当前OP优先级小于等于栈顶OP
            {
                while(!S.empty()&&isOperator(nd.c)<=isOperator(S.top().c))
                {
                    node nd0=S.top();   //将栈顶操作符弹出并装入后缀队列中
                    nd0.flag=false;
                    S.pop();
                    postfixQ.push(nd0);
                }
                S.push(nd);
            }
        }
        infixQ.pop();
    }
    while(!S.empty())     //栈内剩余操作符弹出加入后缀队列
    {
        node nd=S.top();
        S.pop();
        postfixQ.push(nd);
    }
    return;


}

//将后缀表达式计算出结果
void Calcu(queue<node> Q)
{
    stack<float> S;       //装当前结果的栈
    while(!Q.empty())
    {
        node nd=Q.front();
        if(nd.flag==true)    //是操作数
        {
            S.push(nd.num);
            //cout<<"push:"<<nd.num<<endl;
        }
        else                 //是操作符
        {
            float x1,x2,result;
            x2=S.top();
            S.pop();
            x1=S.top();
            S.pop();
            if(nd.c=='+')
                result=x1+x2;
            else if(nd.c=='-')
                result=x1-x2;
            else if(nd.c=='*')
                result=x1*x2;
            else if(nd.c=='/')
                result=x1/x2;
            S.push(result);
            //cout<<"push:"<<result<<endl;
        }
        Q.pop();
    }
    //cout<<"最终计算结果:";
    float result0=S.top();
    cout<<result0<<endl;
}




int main()
{
    ifstream fileIn;
    fileIn.open("data.txt",ios::in);
    if(!fileIn.is_open())
    {
        //cout<<"open file failed."<<endl;
        return 0;
    }

    mp['*']=2;
    mp['/']=2;
    mp['+']=1;
    mp['-']=1;

    //从文件中获取所有字符串
    vector<string> strs;         //建一个string类型的容器
    string line;
    while(getline(fileIn,line))  //获得一行的字符串(包括空格)
    {
        strs.push_back(line);
    }

    for(int i=0;i<strs.size();i++)
    {
        if(strs[i]!="0")       //没有到结尾行
        {
            //清空字符串中的空格后放入中缀队列中
            queue<node> infixQ;      //中缀队列
            int pos=0;
            while(pos<strs[i].size())
            {
                if(strs[i][pos]>='0'&&strs[i][pos]<='9')   //是数字
                {
                    node nd;
                    nd.num=strs[i][pos]-'0';
                    nd.flag=true;
                    pos++;
                    while(pos<strs[i].size()&&strs[i][pos]>='0'&&strs[i][pos]<='9')   //后面的仍是数字
                    {
                        float tmp;
                        tmp=strs[i][pos]-'0';
                        nd.num=nd.num*10+tmp;
                        pos++;
                    }
                    infixQ.push(nd);
                }
                else if(strs[i][pos]==' ')
                    pos++;
                else
                {
                    node nd;
                    nd.c=strs[i][pos];
                    nd.flag=false;
                    pos++;
                    infixQ.push(nd);
                }
            }
            queue<node> postfixQ;     //后缀队列
            GetPostfix(infixQ,postfixQ);
            Calcu(postfixQ);
        }
    }
   return 0;
}

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

音无八重

谢谢老板!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值