使用堆栈评估算术表达式

151 阅读3分钟

在这篇文章中,我们已经解释了如何使用堆栈评估算术表达式(如2*3+4)。我们介绍了算法和时间/空间复杂性。

内容表

  1. 算术表达式的介绍
  2. 评估算术表达式的算法
  3. 一步一步的例子
  4. 实施
  5. 时间和空间复杂性

我们现在将直接进入这个问题。

算术表达式简介

算术表达式可以用3种形式表示。

  1. 英缀符号法
  2. 后缀符号法(反向波兰符号法
  3. 前缀符号法(波兰符号法

Infix记号的形式是 操作数1 操作符 操作符2
Eg: 5 + 3
后缀符号可以表示为_操作数1_ 操作数 2
Eg: 5 3 +
前缀符号可以表示为操作数 1

操作数

2
Eg: + 5 3
我们在日常工作中最经常使用infix符号。然而,机器发现infix符号比prefic/postfix符号更难处理。因此,编译器在表达式被评估之前将英缀符号转换为前缀/后缀。

操作符的优先级需要考虑到案例。

Exponentiation(^) > 
        Multiplication( * ) or Division(/) > 
        Addition(+) or Subtraction(-)

括号具有最高的优先级,它们的存在可以覆盖优先级顺序。

为了评估一个infix表达式,我们需要执行2个主要任务。

  1. 将infix转换为postfix

  2. 评估后缀
    让我们逐一讨论这两个步骤。
    关于步骤1,请参考这篇文章:使用Stack将infix转换为后缀表达式
    一旦表达式被转换为后缀符号,就可以执行步骤2。

评估算术表达式的算法

步骤。

  1. 遍历表达式:
    1.1 如果字符是操作数,将其推入堆栈。
    1.2 如果字符是操作数,从堆栈中取出最上面的两个元素并进行操作。将结果推回堆栈。

  2. 一旦表达式被完全遍历,堆栈中的元素就是结果。

一步一步的例子

第1步是将这个不定式表达式改为后缀:5 3 7 * +
第2步:堆栈S = [],遍历字符串:
5:操作数,推入堆栈,S = [5],top = 5
3:操作数,推入堆栈,S = [5, 3],top = 3
7。操作数,推入堆栈,S = [5, 3, 7], top = 7
* :操作符,弹出最上面的两个元素,op1=7,op2=3。 弹出操作后的堆栈S=[5],top=5。现在,我们将op1 * op2的结果,即7 * 3 = 21推入堆栈。S = [5, 21], top = 21
+ : 操作者,弹出最上面的两个元素,op1 = 21, op2 = 5。pop操作后的堆栈S = []。将op1 + op2的结果推入堆栈,即21 + 5 = 26,S = [26] 。

字符串已被完全遍历,堆栈只包含1个元素,即表达式=26的结果。

实施

在Java中实现。

    public static int postfixEval(String str)
    {
        Stack<Integer> st = new Stack<>();
        for(int i=0;i<str.length();i++)
        {
            char x = str.charAt(i);
            if(x >= '0' && x <= '9')
            {
                st.push(Character.getNumericValue(str.charAt(i)));
            }
            else
            {
                int op1 = st.pop();
                int op2 = st.pop();
                switch(x)
                {
                    case '+' : st.push(op2 + op1);
                                break;
                    case '-' : st.push(op2 - op1);
                                break;
                    case '*' : st.push(op2 *  op1);
                                break;
                    case '/' : st.push(op2 / op1);
                                break;
                }
            }
        }
        return st.pop();
    }

在C++中实现。

    int postfix_eval(string str)
    {
        stack<int> st;
        for(int i=0;i<str.length();i++)
        {
            char x = str[i];
            if(isdigit(x))
            {
                st.push(x - '0');
            }
            else
            {
                int op1 = st.pop();
                int op2 = st.pop();
                switch(x)
                {
                    case '+' : st.push(op2 + op1);
                                break;
                    case '-' : st.push(op2 - op1);
                                break;
                    case '*' : st.push(op2 *  op1);
                                break;
                    case '/' : st.push(op2 / op1);
                                break;
                }
             }
          }
          return st.pop();
      }

时间和空间复杂度

时间复杂度。O(N)

我们正好遍历整个字符串一次。另外,我们最多执行2n次推/拉操作,这意味着一个元素进入堆栈,又从堆栈中出来(n个元素的2n次操作)。这导致了时间复杂度为O(n)。

空间复杂度。O(N)

我们使用一个辅助堆栈,它最多可以包含N/2个元素。因此,该算法的空间复杂度为O(N)。

通过OpenGenus的这篇文章,你一定对使用堆栈的算术表达式评估有了完整的认识。