前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >栈在表达式求值中的应用——逆波兰表达式求值+中缀表达式转后缀表达式

栈在表达式求值中的应用——逆波兰表达式求值+中缀表达式转后缀表达式

作者头像
YIN_尹
发布2024-05-05 08:34:54
730
发布2024-05-05 08:34:54
举报
文章被收录于专栏:YIN_尹的博客YIN_尹的博客

1. 逆波兰表达式(后缀表达式)求值

链接: link

这道题目叫做逆波兰表达式求值,那什么是逆波兰表达式呢? 我们可以一起来了解一下:

结合题目中给的测试用例给大家解释一下:

我们正常写的表达式,就比如题目中的这个:(2 + 1) * 3 这种写法叫做中缀算术表达式,即运算符写在操作数的中间,但是这种写法计算机是不能直接计算的,因为涉及运算符优先级的问题,比如1+2*3,应该先算*。 所以呢,这里就需要我们做一件事情,就是把它变成后缀表达式,其实就是根据优先级对表达式中的运算符排一个序,并且放到对应的操作数后面。 就比如题目中给的这个示例:((2 + 1) * 3)这个表达式对应的后缀表达式就是["2","1","+","3","*"](题中是把它放到一个字符串数组中了)。 即1和2先进行后面的+,得到的结果再和3进行后面的*,得到最终结果。这样就直接从前往后算,不用考虑优先级的问题了。

那现在大家对逆波兰表达式应该有一个大致的了解了。

思路讲解

但是呢,单要解这道题目的话,其实很好搞:

我们只需要借助一个栈就搞定了。 具体怎么做呢? 我们去遍历给的逆波兰表达式对应的字符串数组,如果对应的元素是数字,我们就让该操作数入栈,如果遇到操作符,我们就去取栈顶的前两个元素(并pop掉)进行对应的运算(第一个是右操作数,第二个是左操作数),然后将结果入栈,后续重复上述操作,最终栈里面唯一的那个元素就是要求的结果。 举个栗子:

遍历tokens,2 1入栈,接着遇到+,取出 1 2相加,得到结果3入栈,后面又是一个3入栈,接着遇到* ,取出3 3相乘,结果9入栈。 最终栈里面唯一的元素9就是结果。

AC代码

代码语言:javascript
复制
class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> st;
        for(auto& str:tokens)
        {
            if(str=="+"||str=="-"||str=="*"||str=="/")
            {
                int right=st.top();
                st.pop();
                int left=st.top();
                st.pop();
                switch(str[0])
                {
                    case '+':
                        st.push(left+right);
                        break;
                    case '-':
                        st.push(left-right);
                        break;
                    case '*':
                        st.push(left*right);
                        break;
                    case '/':
                        st.push(left/right);
                        break;
                }
            }
            else
            {
                st.push(stoi(str));
            }
        }
        return st.top();
    }
};

2. 中缀表达式转后缀表达式

那现在大家再来思考一个问题: 如果给我们一个中缀表达式,我们如何把它转换成对应的后缀表达式

分析

中缀转后缀呢,也是需要借助一个栈,具体怎么做呢? 比如现在有这样一个中缀表达式1+2*3-4 怎么把它转成后缀呢? ?,我们还是从头去遍历这个表达式,如果遇到的是操作数,就输出

如果遇到的是的是操作符,那这时要分情况进行分析: 如果此时栈为空,就让该操作符进栈;

如果遇到的是操作符,且此时栈不为空,则取栈顶的操作符与当前操作符比较,比较啥呢——优先级: 如果比栈顶操作符优先级高,就让该操作符进栈,为什么是进栈而不是拿它进行运算呢? 因为后面有可能还有优先级更高的,所以先进栈。

那进栈之后呢?继续取下一个进行判断是操作数还是操作符。

如果比栈顶操作符优先级低或者相等,则出栈顶的操作符输出(即此时栈顶的这个操作符可以进行运算了)

然后再去判断栈是否为空,不为空再拿当前操作符和栈顶操作符比较,进行相应操作,为空就入栈。

遍历结束后,如果栈不为空,将剩余操作符输出。

此时,就得到对应的后缀表达式了。

但是,如果是带括号的情况呢?

比如1+2*(4-5)+6/7,怎么处理? ?,那如果按照上面的分析,1输出,+入栈,2输出,*的优先级比栈顶的+高,*也入栈,接着遇到了括号,怎么办?

如果不加括号的话,后面-比*优先级低,那应该让*先出栈运算,但是现在-在括号里面,所以-应该先运算,所以要认为-的优先级更高。 那我们可以怎么处理呢?当然这里的方法可能不止一种,我们可以这样做: 遇到(,我们认为它的优先级很低,但是我们不拿(做比较,直接让它入栈

然后遇到括号里的-,栈不为空,比较,因为我们说了认为(的优先级很低,所以-也入栈

那继续往后走遇到)怎么办? ?,)呢我们也认为它的优先级很低,但是)我们要拿它去比较,因为我们认为)优先级很低,所以此时栈顶的-是不是就被成功弹出了。

然后栈不为空继续跟栈顶比,那此时) 就遇到 (了,拿这时怎么做呢? 这时直接把(pop掉,不输出,然后跳过) 继续看下一个,因为后缀表达式优先级都排好了就不需要括号了。

拿继续往后走遇到+,栈不为空,跟栈顶比,比栈顶优先级低,栈顶操作符*输出,继续栈还不为空,继续比,优先级相等,出栈顶操作符+

然后栈空了,+入栈

然后遇到6输出,遇到/优先级比+高,入栈,然后7输出

就遍历完了,再把剩余操作符输出

就得出结果后缀表达式了,大家可以验证一下。

当然处理括号可能有很多种方法,我们这里提供的只是其中一种,而且我们这种方法如果遇到有些极端的情况可能也不一定处理的了,可能还需要加一些特殊处理。 另外我们会发现就是遇到(是不是好像去开了一个新栈,在这个新栈里去处理括号里的这个子表达式,所以如果这样的问题也可以考虑递归去搞,每次遇到(就递归去处理这个子表达式,处理完回去递归调用的地方继续处理后面的。

方法总结

3. 中缀表达式求值

那大家再来思考一下,如果给一个中缀表达式,我们该如何求它的值呢?

?,是不是就是上面两种操作的结合啊。

本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-05-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 逆波兰表达式(后缀表达式)求值
    • 思路讲解
      • AC代码
      • 2. 中缀表达式转后缀表达式
        • 分析
          • 方法总结
          • 3. 中缀表达式求值
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档


          http://www.vxiaotou.com