中缀表达式转后缀表达式以及表达式的求值


题目

本题链接:表达式求值
在这里插入图片描述

考研对本知识点不要求写出实际代码,但必须掌握思路
本题后续会补充C语言版本,其实就是模拟栈,关于栈的模拟,详见博客:数组模拟栈
目前用C++中自带的STL函数

下面分几个小点进行介绍:
1.什么是中缀表达式以及后缀表达式
2.中缀表达式转后缀表达式(思维)
3.如何进行表达式求值

1.什么是中缀表达式以及后缀表达式

这个举栗子最容易理解:
我们所熟知的计算方法其实就是中缀表达式,如:a + b, a - b, a * b ...
大致概念就是两个数之间用运算符号链接,这就是中缀表达式,那么后缀表达式的概念是不是很容易猜到呢?
a b +, a b -, a b * ...形如这种式子,就被称为后缀表达式,大概意思就是运算符在两个数之后。
这里再举两个对应的中缀表达式和后缀表达式:
中缀表达式:a + b - ca + b - c * d
后缀表达式:a b + c -a b + c d * -
其实从这里我们就可以看出,我们的中缀表达式转后缀表达式,数字的顺序(位置)其实是不会发生变化的,只有运算符的顺序(位置)才发生改变

2.中缀表达式转后缀表达式(思维)

这里还是举个栗子:
中缀表达式:((15 / (7 - (1 + 1))) * 3 ) - (2 + (1 + 1))
后缀表达式:15 7 1 1 + - / 3 * 2 1 1 + + -

哈哈哈哈哈哈,是不是看着上面两个等价的前缀和中缀表达式一脸懵,下面讲解怎么把中缀表达式转为后缀表达式:
1.确定中缀表达式中各个运算符的顺序
2.选择下一个运算符,按照 [左操作数 右操作数 运算符] 的方式组合成一个新的操作数
3.如果还有运算符没被处理就继续执行2.

好了,看到这里,你愤怒了,这说了三点说了个啥?看球不懂啊!!!,这写的什么 ** 博客
啊!客官莫急,且听我狡辩! 吓的博主赶紧拿出栗子去说明:
这里我们拿一个基础的栗子:A + B * (C - D) - E / F
我们来给这些符号编一个顺序,拿到上述的中缀表达式之后,我们按照小学思维去考虑:

下面小故事的场景为一个班级中有一位老师(晶姐),两个学生:聪明的博主以及娇妹儿

“同学们看这个表达式,我们应该最先去计算哪一个呀?“
“小括号里面的元素!”(两个人异口同声的说到)
“真聪明,所以我们先计算小括号中的 -,那么接下来呢?”

这时,出现了两种不同的声音:
“先算 *(博主吼道)
“先算 /(娇妹儿吼道)

两人俞吵俞烈,最后老师提出两个人打一架吧(不是
最终,老师同意了 聪明的博主 的建议,先算*

“那么接下来呢?”
“先算 +(博主吼道)
“先算 /(娇妹儿吼道)

显然,博主说的是不容置疑的,故老师选择先计算+
最后一步当然毋庸置疑的先计算/,最后计算-
最终的后缀表达式被写成了:A B C D - * + E F / -

大家可能要为娇妹儿打抱不平了,凭什么娇妹儿说的不对,难道知识因为娇妹儿比博主傻么!?
确实(逃
咳咳咳,其实娇妹儿说的不无道理,做法也是可取的,显然我们的后缀表达式也是可以按照娇妹儿的思维去写的,但是我们这里规定一个原则:左优先原则:只要左边的运算符能先计算,就优先算左边的

为什么呢?
1.计算机内部实现方式为左优先的原则去实现
2.我们用左优先的原则写成后缀表达式之后,是非常直观的,读者可以再看一下我们上述过程中优先计算符号的顺序:- * + / -,恰好这种顺序正好是我们写成后缀表达式之后,后缀表达式中的顺序:A B C D - * + E F / -

看到这里,读者应该明白如何进行中缀表达式以及后缀表达式之间的转换计算了,不妨看一下最开始的栗子,自己动手转换一下看看是否能转换成功

3.如何进行表达式求值

用栈实现后缀表达式的计算
①.从左往右扫描下一个元素,直到完全处理完所有的元素
②.若扫描到操作数则压入栈,并返回到①,否则执行③
③若扫描到运算符则弹出两个栈顶元素 (注:先出栈的为右操作数),执行相应操作,运算结果压回栈顶回到①

若表达式合法,则最后栈中只会留下一个元素,就是最终结果

AC代码

注:考研中其实是不要求会写出下面的代码,但还是希望读者好好看懂并自己写一遍
上面已经说的很详细了(自认为,咳咳),如果代码还有哪里不知道原因的话,可以评论或者私聊我,博主很闲,看到了就会及时回复的

#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>
#include <stack>

using namespace std;

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

void eval()
{
    auto b = num.top(); num.pop();
    auto a = num.top(); num.pop();
    auto c = op.top(); op.pop();

    int x;
    if (c == '+') x = a + b;
    else if (c == '-') x = a - b;
    else if (c == '*') x = a * b;
    else x = a / b;
    num.push(x);
}

int main()
{
    string s;
    cin >> s;

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

    while (op.size()) eval();
    cout << num.top() << endl;

    return 0;
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

辰chen

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值