后缀表达式的运算 以及 最详细的中缀表达式转为后缀表达式

中缀表达式是最为常见、也是我们平时使用的表达式。例如,4+3*2 就是中缀表达式。可以理解为运算符放在了两个需要运算的数中间,而后缀表达式,可以理解为:把运算符放在了需要运算的数后面。后缀表达式也称为逆波兰表达式。

【注意】后缀表达式没有括号

计算一个后缀表达式

在计算之前,我认为有必要介绍一个将中缀表达式转换为后缀表达式的方法,但这个方法无法使用编程描述起来,需要依靠人去观察 。能够使用编程语言实现,而且也是考研的方法,我放在了本文的下半部分。
例一

中缀表达式:4 + 3 * 2
优先级越高的越先处理,3 * 2 👉3 2 *
3 2 *当成一个整体,43 2 *看作两个需要运算的数,4 + 3 2 * 👉 4 3 2*+

例二

中缀表达式:(4 + (13 / 5))
按照优先级来慢慢处理,13/5 👉13 5 /
413 5 /看作两个需要运算的数,+放在两个需要数的后面,化为逆波兰表达式为4 13 5 / +

例三

中缀表达式:6 / ((9 + 3) * -11)
优先级越高的优先处理,9 + 3👉 9 3 +
下一个处理 (9 + 3) * -11, 9 3 +-11看作两个需要运算的数,化为9 3 + -11 *
69 3 + -11 *看作两个需要运算的数,把/放在两个数的后面
最终化为6 9 3 + -11 * /

既然我们能够将一个中缀表达式转化为后缀表达式,那当然也能够将后缀转化为中缀表达式。
按照中缀表达式转化为后缀表达式的方法,运算符放在两个运算数的后面。所以给出一个逆波兰表达式,从左至右开始,一个运算符和它前面的两个运算数,构成一个子表达式或者全部表达式。

6 9 3 + -11 * /为例,将它化成一个中缀表达式

从左至右,找到第一个运算符,为+
那么它前面的两个数93,和+构成一个子表达式,即9 + 3
构成一个子表达式的那一堆,看作一个数、一个整体。
继续往后面找运算符,为*
前面的两个数为9 3 +-11, 即9 + 3-11*构成一个子表达式(9 + 3) * -11
继续往后面找运算符,为/
前面的两个数为 6(9 + 3) * -11,所以化为中缀表达式为6 / ((9 + 3) * -11)

有一道经典的题目,根据 逆波兰表示法,求一个后缀表达式的计算结果。还是以6 9 3 + -11 * /为例,点开解题思路。
有两种我能想到的思路,第一种是按照上面的方法,将它完完整整地化为中缀表达式后,进行计算;第二种思路,是在转化为中缀表达式的同时计算结果,过程如下:

【1】从左至右,找到第一个运算符,为+
那么它前面的两个数93,和+构成一个子表达式,9 + 3, 即为12。
此时这个后缀表达式形式:6 12 -11 * /
【2】继续往后面找运算符,为*
前面的两个数为12-11, 即12-11*构成一个子表达式12 * -11, 即-144。
此时这个后缀表达式形式:6 -144 /
【3】继续往后面找运算符,为/
前面的两个数为 6-144,表达式变成6/-144

综合第二种思想,实际实现的时候,借助栈来实现,简直再合适不过了。

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        //前提:给的逆波兰表达式总是合法的
        stack<int> st; 
        int LeftNum = 0, RightNum = 1, num = 0;
        for(string e : tokens) 
        {
            //如果e是运算符,取出栈顶的两个数据出来运算
            if(e == "+" || e == "-" || e == "*" || e == "/")
            {
                //注意哪一个作为左运算数、哪一个作为右运算数
                RightNum = st.top();
                st.pop();
                LeftNum = st.top();
                st.pop();

                //运算,运算的结果压入栈
                if(e == "+")
                    num = LeftNum + RightNum;
                else if(e == "-")
                    num = LeftNum - RightNum;
                else if(e == "*")
                    num = LeftNum * RightNum;
                else
                    num = LeftNum / RightNum;
                //运算结果压入栈里面
                st.push(num);
            }
            else{
                //e属于运算数,入栈
                st.push(stoi(e));
            }   
        }
        //栈里面只剩下一个数据,这就是最终结果
        return st.top();
    }
};

在这里插入图片描述

中缀表达式转为后缀表达式

需要借助栈,同时牢记下面几条规则,这几条规则是我简单总结出来的。

  1. 在比较时,保持栈顶优先级最高, 并且以当前优先级作为基础。
  2. 普通运算符(除了“()”),进栈后优先级等比例变高。等比例也就是说,即使+在栈里面,优先级也不会比栈外的*、/高。
  3. 左括号(, 在栈外优先级最高,在栈内优先级最低;右括号), 在栈外优先级最低。
  4. 遇到)直接进栈, 栈内如果出现一对(), 将()以及()里的全部内容出栈。实际上)不用进栈, 反正也会直接退出来。
  5. 第一个运算符直接入栈。
  6. 后缀表达式没有括号

使用一个例子来讲解它的过程
例一:将中缀表达式a+b-a*((c+d)/e-f)+g转换为后缀表达式。

从左到右依次扫描,如果是运算数,直接输出。如果是运算符, 则按照上述规则操作。
🍬扫描到运算数a, 直接输出。
在这里插入图片描述
🍭扫描到运算符+, 是第一个运算符,直接进栈。
在这里插入图片描述
🍡扫描到运算数b, 直接输出。
在这里插入图片描述
🍮扫描到运算符--此时在栈外, 要和栈顶元素比较。由于普通运算符进栈后优先级变高,所以当前优先级+-高。在比较时,要求栈顶元素优先级最高, 并且以当前优先级作为基础。为了保持栈顶元素优先级最高, 需要把+先退栈,然后让 -进来。
在这里插入图片描述
🍯扫描到运算数a, 直接输出。
在这里插入图片描述
🍼扫描到运算符*。开始和栈顶元素比较。当前*在栈外, -在栈内。当前优先级*高于-, 直接进栈没有任何问题。
在这里插入图片描述
🥛扫描到运算符(。开始比较, 当前(在栈外,* 为栈顶元素。由于(在栈外优先级最高, 所以当前优先级(比栈顶元素*高。直接进栈, 没有任何问题。
在这里插入图片描述
☕扫描到运算符(。开始和栈顶元素比较, 当前(在栈外, 栈顶元素也为(。但我们要记住, (在栈内优先级最低, 而在栈外优先级最高, 所以当前优先级栈外(优先级高于栈内(。直接进栈,没有任何问题。
在这里插入图片描述
🍵扫描到运算数c, 直接输出。
在这里插入图片描述
🍶扫描到运算符+。开始比较, 当前+在栈外, 栈顶元素为(。因为(在栈内优先级最低,所以当前优先级+高于(。 直接进栈,没有任何问题。
在这里插入图片描述
🍾扫描到运算数d, 直接输出。
在这里插入图片描述
🍷扫描到运算符))并不需要进入栈内, 假设让它直接进栈,那么栈内就构成了一对() , 将()以及()内的元素全部依次出栈, 并且输出。但是后缀表达式没有括号, 所以括号不要输出。
在这里插入图片描述
🍸扫描到运算符/。开始比较, 当前/在栈外,栈顶元素为(。因为(进栈后优先级最低, 所以当前优先级/高于(。直接进栈,没有任何问题。
在这里插入图片描述
🍹扫描到e,直接输出
在这里插入图片描述

🍍扫描到-。开始比较 ,当前栈顶元素为/-在栈外。当前优先级/高于-。为了保持栈顶优先级最高, -不能直接进栈, 需要先把/退栈,退栈后栈顶元素为(-在栈外, (在栈内优先级最低, 当前优先级(低于-, 此时直接进栈, 没有任何问题。
在这里插入图片描述
🍎扫描到运算数f, 直接输出。
在这里插入图片描述
🍏扫描到运算符))不需要真正进栈, 假设让)直接进栈, 栈内就存在一对(),将()以及()内的全部内容依次退栈输出。要注意,后缀表达式没有括号。
在这里插入图片描述
🍐扫描到运算符+。开始比较, 当前+在栈外, 栈顶元素为*。普通运算符进栈后优先级会变高, *在栈外时就比它高, 那么进栈后优先级仍然比它高。所以+不能直接进栈, 需要先把*退栈输出,此时栈顶元素为-。普通运算符进栈后优先级会变高, 当前优先级-高于栈外的+, 所以-也需要退栈并输出。
在这里插入图片描述
🍑扫描到运算数g, 直接输出
在这里插入图片描述

🍒全部扫描完成, 将栈内还剩余的元素依次退栈并输出。
在这里插入图片描述
所以a+b-a*((c+d)/e-f)+g转换为后缀表达式就是ab+acd+e/f-*-g+

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小小酥诶

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

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

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

打赏作者

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

抵扣说明:

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

余额充值