中缀表达式求值是非常经典的题目,主要考察stack的使用,本文主要介绍如何使用stack解决中缀表达式求值(包含±*/与括号)的问题。
解题思路
设置两个stack,分别用来存储操作数与操作符,我们分别称之为op_num与op_ch。
接下来就是遍历表达式啦:
- 如果遇到了数字,那就把数字整个取出来,放到op_num中
- 如果遇到了空格,跳过就好了
- 如果遇到了操作符,那就看操作符op的优先级:
- 如果比栈顶的运算符优先级低,那就压入栈中
- 如果比栈顶的运算符优先级相等或者高,那么就取出两个操作数与一个运算符,运算后把结果放入op_num中(这里注意取出的运算数依次为a和b,那么运算的时候顺序要反过来: b 运算符 a),重复此过程,直到栈顶运算符优先级比运算符op低,把op压入栈。
- 遍历完后,如果栈不为空,那么不断去除运算符与操作数,不断运算,如果表达式是正常合法的,那么当op_ch空的时候,op_num应该只剩下一个结果,就是最终的表达式运算结果。
TIPS: 建议事先在op_ch中压入一个特殊的运算符,比如’.’,并定义它的优先级为最低,这样在上面的第三步就不用判断栈op_ch是否为空了,只要判断op的优先级与栈顶的运算符优先级的关系就好了。
TIPS:建议事先在字符串后面加上一个空格,不影响运算,但是在从表达式里面取出操作数时,可以避免判断下标是否越界。(主要针对以下这种取出操作数的方式)
if (s[i] >= '0' && s[i] <= '9') {
// number
int number = 0;
int p = i;
while (s[p] >= '0' && s[p] <= '9') {
//如果遇到最后一个字符是数字的时候,有可能因为越界造成危险,
// c++ stl的string越界不会返回错误
number = number * 10 + (s[p] - '0');
p++;
}
i = p - 1;
op_num.push(number);
continue;
}
遇到括号怎么办呢?
定义左括号的优先级为最低,这么做是为了在上面的第三步中比较断op的优先级与栈顶的运算符优先级的关系时不会受到左括号的影响,继续阅读可以更深入地理解这一点。
- 如果遇到了左括号,不说别的,直接压入栈op_ch就好了
- 如果遇到了右括号,不断取出操作数与运算符进行计算,直到遇到了左括号,把左括号从栈里取出来,什么也不干,继续遍历就好了。
附上Basic Calculator的代码,针对Basic Calculator和Basic Calculator II
int get_priority(char op) {
switch (op)
{
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
case '('