用shunting-yard算法做表达式求解

本文介绍了如何使用shunting-yard算法将中缀表达式转换为后缀表达式,以便于计算。详细阐述了算法原理,并通过示例解释了转换过程。同时,讨论了分词问题,特别是负号的特殊处理,以及最终如何通过后缀表达式求解表达式的结果。
摘要由CSDN通过智能技术生成

背景

表达式求解这个问题绝对是非常值得搞清楚的一个问题, 一方面在面试中经常会被问到(https://leetcode-cn.com/problems/basic-calculator/), 我就曾不止一次在面试中被问到类似的问题, 然而当时回答的都不理想; 另一方面, 在我们的工作中, 其实会遇到真实的问题需要类似的算法求解, 但是一般是改头换面出现的, 比如我最近遇到一个问题, 业务端传给我一个类似于这样的表达式:

a && b && !(c || d)

我希望对这个表达式做进一步的处理, 处理的第一步就需要把这个表达式给parse成语法树, 比如可以处理成如下的json格式:

{
    "and": [
        {
            "and": [
                "a",
                "b"
            ]
        },
        {
            "not": [
                {
                    "or": [
                        "c",
                        "d"
                    ]
                }
            ]
        }
    ]
}

这个问题虽然看起来和加减乘除的那种表达式不一样, 但其实本质是完全一样的.

可以把&&看成*, 把||看成+, 把!看成-, 于是上面那个布尔表达式就变成了:

a*b*-(c+d)

我们完全可以用处理这个代数表达式的方法处理那个布尔表达式.

可见, 这个题目值得我们研究一下[https://leetcode-cn.com/problems/basic-calculator/].

后缀表达式

本题需要对给定的字符串类型的表达式进行解析并计算, 一般涉及到这种要计算中缀表达式(也就是我们一般用的表达式, 运算符在操作数中间)的问题, 一个常用的思路是用shunting-yard算法转换为后缀表达式.

4+18/(9-3)(中缀) => 4, 18, 9, 3, -, /, +(后缀)

为什么要转化为后缀表达式呢? 因为转化为后缀表达式后利于我们写算法计算结果.直观来看, 中缀表达式是含有括号的, 而后缀表达式是没有括号的; 而且还有很重要的一点: 中缀表达式是考虑运算符优先级的, 如2+3*2, 在计算时需要考虑到乘法的优先级大于加法, 但是转换为后缀表达式以后就没有优先级的问题了, 可以按照统一方式进行计算.

如何用后缀表达式求解

我们先不管中缀表达式是这么转化为后缀表达式的, 先来看一下假设我们已经转化为了后缀表达式, 那么如何用后缀表达式计算结果呢?

这里需要用到栈(stack)这种数据结构, 栈是一种先进后出的数据结构, 类似一个碗, 往里面放食物的时候是先装碗底, 再装碗中部, 最后装碗顶, 而吃的时候是反过来的, 先吃碗顶, 再吃碗中部, 最后吃碗底. 因此最先放进去的食物反而是最后被吃到的.

现在遍历后缀表达式4, 18, 9, 3, -, /, +, 因为表达式中只有两种元素, 数字和操作符, 因此我们可以定义如下算法:

  1. 创建一个空栈stack.

  2. 遍历后缀表达式, 根据元素种类做如下操作:

image-20210308143728291.png

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值