跳转至

表达式计算

表达式计算 是对表达式按照预定规则进行计算求值的过程,因此,表达式计算也称作表达式求值。我们使用表达式表示方法的一般有三种。

下令一个数、一个操作符或一个括号都是一个单位。

前缀表达式

本节只考虑加减乘除四种运算。

一种操作符写在操作数前的表达式表示法,不需要考虑计算顺序。

例子

中缀表达式(见下文)\(a \times (b + c) \div d\) 可变为前缀表达式 \(\div \times a + b \ c \ d\)

一般用递归计算。令表达式字符串为 \(s\)\(s(i)\)\(s\) 的第 \(i\) 个单位,\(q\) 为当前应处理到的单位编号,初始 \(q = 1\)

每次进入递归函数,若 \(s(q)\) 是数字,返回数字;否则 \(q \gets q + 1\),从 \(q\) 递归一次;再 \(q \gets q + 1\),从 \(q\) 递归一次(第一次递归后的 \(q\) 已经改变了),得到两个数字进行计算,返回。

后缀表达式

本节只考虑加减乘除四种运算。

一种操作符写在操作数后的表达式表示法,不需要考虑计算顺序。

例子

中缀表达式(见下文)\(a \times (b + c) \div d\) 可变为前缀表达式 \(a \ b \ c + \times \ d \ \div\)

一般用栈计算。令表达式字符串为 \(s\)\(s(i)\)\(s\) 的第 \(i\) 个单位,\(i\) 为当前处理到的单位编号。

\(i = 1\) 开始正序遍历 \(s\)。若 \(s(i)\) 是数字,直接压入栈中;否则取出栈中两个数字进行计算,然后压入栈中,注意先取出的是在后面的操作数。

中缀表达式

本节只考虑加减乘除四种运算。

这是我们最常用的表达式表示法,操作符写在操作数中间。计算时先算括号,内侧括号优先,再算乘除法,最后算加减法,同级操作从左到右计算。这里的括号只有小括号 ()

例子

\(a \times (b + c) \div d\)

\(3 \times (5 + 7) \div 2 = 18\)

递归计算

令当前表达式字符串为 \(s\)\(s(i)\)\(s\) 的第 \(i\) 个单位。

  1. \(s\) 首尾有多余的括号,去除;
  2. 找到优先级最低的一个运算符 \(s(x)\),即在以 \(s(x)\) 为界分开后计算再拼接的答案不会发生改变;
  3. 递归计算以 \(s(x)\) 为界分开的两个表达式;
  4. 合并计算完的两个表达式,让 \(s(x)\) 为操作符对这两个数进行计算,返回。

得到的答案就是表达式计算后的结果。

转为后缀表达式

令当前表达式字符串为 \(s\)\(s(i)\)\(s\) 的第 \(i\) 个单位,\(t\) 是处理出的后缀表达式,\(i\) 为当前处理到的单位编号。

维护一个符号栈。

\(i = 1\) 开始正序遍历 \(s\)。若 \(s(i)\) 为数字,直接加入 \(t\) 中;若 \(s(i)\) 为左括号,压入栈中;

\(s(i)\) 是右括号,则一直让栈弹出直到第一个左括号被弹出,弹出的数字按弹出顺序加入 \(t\)

\(s(i)\) 是符号,则一直让栈弹出直到栈顶的符号优先级小于 \(s(i)\) 或为左括号,弹出的符号入栈,左括号不弹出。

以上(前中后缀表达式)的计算方法若要加入新的符号则只需考虑优先级即可。