当前位置 博文首页 > XSES_yasuoman的博客:中缀表达式转后缀表达式算法

    XSES_yasuoman的博客:中缀表达式转后缀表达式算法

    作者:[db:作者] 时间:2021-08-31 22:23

    💯中缀表达式转后缀表达式(机算)

    思路:

    根据 括号 > 乘除 > 加减 的原则,在从左往右扫描表达式的过程中,确定表达式操作符的运算顺序,

    先初始化一个栈,栈中用来存储“暂时无法确定运算顺序的操作符” 和 “左括号”。

    机器扫描顺序是从左往右,因此每得到一个运算顺序,就可以确定一部分后缀表达式,

    • 在不遇到括号情况下,需要多次判断加减乘除计算顺序,在每一次判断依赖当前扫描到的操作符和前面一个操作符,将整个表达式看做[已经转换为后缀表达式的部分——NumA] [前一个运算符op_prior] [一个单独的数字 NumB] [当前扫描到的运算符op_present] [尚未参与转换的部分 NumC] 的样式。

      [NumA] [op_prior] [NumB] [op_present] [NumC]			// 每一步的形式
      

      此时 op_prior 在栈顶(后面会解释为什么它在栈顶),循环扫描至 op_present 操作符

      每一步中,两个操作符的优先级将决定 op_prior是否能弹出栈参与运算。(这也是每一步的本质工作

      若 op_prior 运算优先级 >= op_present(另一种情况便是不能弹出 op_prior,此时它的有缘人便是右括号或循环结束),按照左优先原则,需先计算前面 A op_prior B 部分,从而op_prior 能弹出栈参与运算,将 op_prior 弹出并加入后缀表达式尾部NumA NumB op_prior,这部分可视作一个操作数 NumA1

      此时整体表达式形式变为 [NumA1] [op_present] [NumC]

      前面提到过 NumC 是尚未参与转换的部分(形式为Num1 op1 Num2 op2 ...),我们将再 NumC 中 num1、op1 和剩余部分视作 [Num1] [op1] [剩余部分Num2 op2 ...] 的形式。

      此时整体表达式便可视作 [NumA1] [op_present] [Num1] [op1] [Num2 op2 ...]

      这就变成了 我们最开始想要的 [NumA] [op_prior] [NumB] [op_present] [NumC] 的形式。

      此时原先的 op_present 将被视作新的 “op_prior” ,如果不依靠后面的操作符,无法得出**“NumA NumB”以何种顺序进行计算**,因此它是上面初始化栈时提到的“暂时无法确定运算顺序的操作符”,将其入栈。

      开始新的循环,重复以上步骤直至结束。

      【注】虽然每一步形式如 [NumA] [op_prior] [NumB] [op_present] [NumC] ,但是实质上每次比较的是 当前扫描的运算符和栈中暂时无法确定运算顺序的运算符

    • 在遇到括号时,遇到左括号压入栈顶,括号内部格式仍然符合上述形式,按上述执行,直至遇到右括号,弹出栈中运算符加入到后缀表达式中,再弹出左括号,表明结束了该组括号的匹配。


    算法如下:

    初始化一个栈,栈中用来存储“暂时无法确定运算顺序的操作符” 和 “左括号”。

    1. 从左往右扫描表达式的每一个元素,有 3 种情况:

      • 遇到 操作数 ,直接加入后缀表达式中。

      • 遇到 界限符(括号):

        • 括号:

          直接压入栈顶,等待一个右括号与其匹配,匹配到后,便可将括号里内容看做一个操作数加入到后缀表达式中。

        • 括号:

          弹出栈顶操作符并将其加入后缀表达式,重复,直至遇到与其匹配的左括号将左括号弹出左括号不加入后缀表达式

      • 遇到 操作符 :依次弹出栈中 优先级高于或等于 当前操作符的所有操作符,弹出时依次加入后缀表达式,直至栈顶元素为左括号或栈空为止。此时将当前操作符入栈。

        【注】上面的优先级指的是:* = / > + = -

    2. 扫描结束后,将栈中剩余运算符依次弹出、加入后缀表达式。


    cs