利用后缀表达式求值(Acwing)

3302. 表达式求值

给定一个表达式,其中运算符仅包含 +,-,*,/(加 减 乘 整除),可能包含括号,请你求出表达式的最终值。

注意:

  • 数据保证给定的表达式合法。
  • 题目保证符号 - 只作为减号出现,不会作为负号出现,例如,-1+2,(2+2)*(-(1+1)+2) 之类表达式均不会出现。
  • 题目保证表达式中所有数字均为正整数。
  • 题目保证表达式在中间计算过程以及结果中,均不超过 231−1
  • 题目中的整除是指向 0
  • 取整,也就是说对于大于 0 的结果向下取整,例如 5/3=1,对于小于 0 的结果向上取整,例如 5/(1−4)=−1
    • C++和Java中的整除默认是向零取整;Python中的整除//默认向下取整,因此Python的eval()函数中的整除也是向下取整,在本题中不能直接使用。

    输入格式

    共一行,为给定表达式。

    输出格式

    共一行,为表达式的结果。

    数据范围

    表达式的长度不超过 105

    输入样例:

    (2+2)*(1+1)
    

    输出样例:

    8
    

第一种是算法笔记上的写法:

 /**
 * 将中缀表达式转换为后缀表达式可以直接从左到右进行运算,不用考虑中间
 * 运算符的优先级。
*/

/**
 * 将中缀表达式转换为后缀表达式可以直接从左到右进行运算,不用考虑中间
 * 运算符的优先级。
*/

#include <iostream>
#include <queue>
#include <stack>
#include <map>

using namespace std;

struct Node
{
    int num; //运算数
    char op;    //运算符
    bool flag;  //true表示操作数,false表示操作符
};

stack<Node> stk;    //操作符栈
queue<Node> q;      //后缀表达式
map<char,int> op;   //将运算符优先级映射成数字,数字越大,优先级越高

void get_beh(string &str)
{
    while(stk.size())   //清空栈的内容
        stk.pop();
        
    Node tm;
    for(int i=0;i<str.size();)
    {
        if(isdigit(str[i])) 
        {
            tm.flag=true;
            tm.num=str[i++]-'0';
            while(i<str.size() && isdigit(str[i]))//也许运算数并不止一位
                tm.num=tm.num*10+str[i++]-'0';
            q.push(tm);
        }
        else
        {
            if(str[i] == ')')
            {
                Node t=stk.top();
                stk.pop();
                while(t.op != '(')
                {
                    q.push(t);
                    t=stk.top();
                    stk.pop();
                }
                ++i;    //别忘了将i右移一位
                continue;
            }
            
            tm.flag=false;
            
            while(!stk.empty() && op[stk.top().op] >= op[str[i]] && stk.top().op != '(')
            {   //当栈顶的运算符优先级大于或等于该运算符
                q.push(stk.top());
                stk.pop();
            }
            tm.op=str[i++];
            stk.push(tm);
        }
    }
    
    while(stk.size())   //也许栈还有运算符,加入后缀表达式中
    {
        q.push(stk.top());
        stk.pop();
    }
    
    
}

int cal()
{
    while(q.size()) //只要后缀表达式中还有值
    {
        Node tm = q.front();    //取出队首元素
        q.pop();
        if(tm.flag == true)
            stk.push(tm);
        else
        {
            int temp2=stk.top().num;
            stk.pop();  //栈顶是第二个操作数
            int temp1=stk.top().num;
            stk.pop();  //栈的第二个元素才是第一个运算数
            
            if(tm.op == '+')
                tm.num=temp1+temp2;
            else if(tm.op == '-')
                tm.num=temp1-temp2;
            else if(tm.op == '*')
                tm.num=temp1*temp2;
            else
                tm.num=temp1/temp2;
            stk.push(tm);   //将得到的结果加入栈内
        }
    }
    
    return stk.top().num;   //只要是正确的运算式,那么栈此时有唯一一个元素,也是该算式的答案
}

int main()
{
    op['+'] = op['-'] =1;
    op['*'] = op['/'] =2;
    op['('] = 5;
    op[')'] = 6;
    
    string str;
    getline(cin,str);
    
    string temp;
    for(int i=0;i<str.size();++i)
        if(!isspace(str[i]))
            temp+=str[i]; //将空格统统去掉
    str=temp;   

    get_beh(str);
    
    cout << cal() << endl;
    
    return 0;
}

第二种写法跟着y总写的:

#include <iostream>
#include <algorithm>
#include <map>
#include <stack>

using namespace std;

stack<int> num;
stack<char> op;

void cal()
{
    int t2=num.top(); num.pop();
    int t1=num.top(); num.pop();
    char ch =op.top(); op.pop();
    
    int res;
    if(ch == '+')
        res = t1+t2;
    else if(ch == '-')
        res = t1-t2;
    else if(ch == '*')
        res = t1*t2;
    else
        res = t1/t2;
    num.push(res);
}

int beh(string &s)
{
    map<char,int> pr{{'+',1},{'-',1},{'*',2},{'/',2}};
    
    for(int i=0;i<s.size();++i)
    {
        if(isdigit(s[i]))
        {
            int j=i,n=0;
            while(j<s.size() && isdigit(s[j]))
                n = n*10 + s[j++]-'0';
            num.push(n);
            i=j-1;
        }
        else if(s[i] == '(')
            op.push(s[i]);
        else if(s[i] == ')')
        {
            while(op.top() != '(')
                cal();
            op.pop();
        }
        else
        {
            while(op.size() && pr[op.top()]>=pr[s[i]] && op.top()!='(')
                cal();
            op.push(s[i]);
        }
    }
    
    while(op.size())
        cal();
    return num.top();
}

int main()
{
    string str;
    getline(cin,str);
    
    cout << beh(str) << endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值