用 Stack 计算四则运算表达式的值

大家都知道四则运算表达式是有优先条件的 。比如先乘除再加减。而且如果有括号的话还要先计算括号里面。有没有想过现在的高级计算器是如何实现这一功能的呢?

这里面的困难就在于乘除有时候在后面却要先计算,在加上有括号的情况就更加复杂了。

  • 后缀表达式

类似 9 + (3 - 1) * 3 + 10 / 2 是我们常见的表达式,叫『中缀表达式』。后缀表达式不同与中缀表达式,之所以叫“后缀表达式”是因为所有的运算符都在数字后面出现。所以9 + (3 - 1) * 3 + 10 / 2的后缀表达式为:9 3 1 - 3 * + 10 2 / +
显然,是没有括号的。

  • 后缀表达式计算结果

后缀表达式为:9 3 1 - 3 * + 10 2 / +

规则:从左到右遍历遍历表达式的每一个数字和符号,遇到数字就进栈 ,遇到符号就栈顶的两个数字出栈,然后进行运算,然后将运算结果进栈 。一直到最后,栈里面的值即为最终结果。

  1. 初始化空栈, 9 3 1 依次进栈。栈内从下到上依次是:9,3,1
  2. 然后 - 号进栈,3 - 1 = 2, 2 进栈。栈内从下到上依次是:9,2
  3. 接着 3 进栈。栈内从下到上依次是:9,2,3
  4. * 号进栈,2 * 3 = 6,6 进栈。栈内从下到上依次是:9,6
  5. + 号进栈,9 + 6 = 15, 15 进栈。栈内从下到上依次是: 15
  6. 10, 2 依次进栈。栈内从下到上依次是: 15,10,2
  7. / 号进栈,10 / 2 = 5, 5 进栈。栈内从下到上依次是: 15,5
  8. + 号进栈,15 + 5 = 20。20 进栈。

至此结束,表达式最终结果:20

看来计算机果然适合计算后缀表达式求值,那么现在的问题就是如何把我们常见的中缀表达式转换为后缀表达式呢?


  • 中缀表达式转后缀表达式

规则:从左到右遍历表达式的每个数字和符号

  1. 遇到数字直接输出,成为后缀表达式的一部分。
  2. 栈为空时,遇到运算符,直接入栈
  3. 当前符号是 (, 则直接进栈
  4. 当前符号是 ), 则把栈中的符号依次出栈,直到遇到 )为止。) 不输出。
  5. 若是 + - * / 运算符号,弹出所有优先级大于或者等于该运算符的栈顶元素,然后将该运算符入栈;直到遇到栈顶符号为 ) 或栈空 [+ - 为一级,* / 为 二级]

中缀表达式 9 + (3 - 1) * 3 + 10 / 2 转后缀表达式为: 9 3 1 - 3 * + 10 2 / +

  1. 9 直接输出。结果集:9;
  2. + 入栈。结果集:9;栈内从下到上依次是:+
  3. ( 直接入栈。结果集:9;栈内从下到上依次是:+,(
  4. 3 直接输出。结果集:9,3;栈内从下到上依次是:+,(
  5. - 入栈,优先级低于栈顶符号 (,直接入栈。结果集:9,3;栈内从下到上依次是:+,(,-
  6. 1 直接输出。结果集:9,3,1;栈内从下到上依次是:+,(,-
  7. 下一个符号是 ),因此循环出栈,直到遇到 (.结果集:9,3,1,-;栈内从下到上依次是:+
  8. * 入栈。因为栈顶是 +,优先级低于 *, 所以 * 直接入栈。结果集:9,3,1,-;栈内从下到上依次是:+,*
  9. 3 直接输出。结果集:9,3,1,-,3;栈内从下到上依次是:+,*
  10. + 入栈,栈顶 * 优先级高于 +,固 * 出栈并输出。下一个是 +, 优先级等于 +。出栈,+ 入栈。结果集:9,3,1,-,3,*,+;栈内从下到上依次是:+
    此时栈底的+是3+10的+,表达式里面的+是第一个+
  11. 10 直接输出。结果集:9,3,1,-,3,*,+,10;栈内从下到上依次是:+
  12. / 入栈,优先级高于栈顶符号 +。直接入栈。结果集:9,3,1,-,3,*,+,10;栈内从下到上依次是:+,/
  13. 2 直接输出。结果集:9,3,1,-,3,*,+,10,2;栈内从下到上依次是:+,/
  14. 循环出栈。结果集:9,3,1,-,3,*,+,10,2,/,+
代码如下:
/**
     * 根据后缀表达式计算结果集
     * @param result
     * @return
     */
    private double getResult(List<String> result) {
        if (null == result || result.size() == 0) {
            throw new RuntimeException("表达式不合法!");
        }
        Stack<String> stack = new Stack<>();
        Set<String> operation = new HashSet<>(Arrays.asList("+", "-", "*", "/"));
        double d = 0.0d;
        for (String str : result) {
            if (!operation.contains(str)) {
                stack.push(str);
            } else {
                double up = Double.parseDouble(stack.pop());
                double down = Double.parseDouble(stack.pop());
                switch (str) {
                    case "+":
                        d = down + up;
                        break;
                    case "-":
                        d = down - up;
                        break;
                    case "*":
                        d = down * up;
                        break;
                    case "/":
                        d = down / up;
                        break;
                    default:
                        break;
                }
                stack.push(String.valueOf(d));
            }
        }
        return Double.parseDouble(stack.pop());
    }


/**
     * 将中缀表达式转换为后缀表达式
     *
     * @param operationExpression
     * @return
     */
    private List<String> operationExpressionToRPN(String operationExpression) {
        if (null == operationExpression || "".equals(operationExpression)) {
            throw new RuntimeException("表达式不合法!");
        }
        List<String> result = new LinkedList<>();

        char[] chars = operationExpression.toCharArray();

        Set<String> operation = new HashSet<>(Arrays.asList("+", "-", "*", "/"));
        Set<String> numbers = new HashSet<>(Arrays.asList("0", "1", "2", "3", "4", "5", "6", "7", "8", "9"));


        Stack<String> stack = new Stack<>();
        StringBuffer sb = new StringBuffer();
        String lastChar = "";
        for (char c : chars) {

            String currentChar = String.valueOf(c);

            // 上一个字符 和 当前字符 都是数字的话
            if (numbers.contains(lastChar) && numbers.contains(currentChar)) {
                String lastestChar = result.get(result.size() - 1);
                result.remove(result.size() - 1);
                result.add(lastestChar + currentChar);
                lastChar = currentChar;
                continue;
            }
            if (numbers.contains(currentChar)) {
                sb.append(currentChar);
            } else {
                /**
                 *
                 * 1:当前符号是 (, 则直接进栈
                 * 2:当前符号是 + - * /, 弹出所有优先级大于或者等于该运算符的栈顶元素,然后将该运算符入栈
                 * 3:当前符号是 ), 则把栈中的符号依次出栈,直到遇到 )为止。
                 */

                if ("(".equals(currentChar)) {
                    stack.push(currentChar);
                } else if (operation.contains(currentChar)) {
                    /*while (true) {
                        // 栈空、栈顶符号为"("、当前符号优先级 > 栈顶符号优先级。当前符号入栈
                        if (stack.isEmpty() || getOperationLevel(stack.peek()) < getOperationLevel(currentChar) || "(".equals(stack.peek())) {
                            stack.push(currentChar);
                            break;
                        } else {
                            result.add(stack.pop());
                        }
                    }*/
                    while(!stack.isEmpty() && (getOperationLevel(stack.peek()) >= getOperationLevel(currentChar)) && !"(".equals(stack.peek())){
                        result.add(stack.pop());
                    }
                    stack.push(currentChar);
                } else if (")".equals(currentChar)) {
                    String str;
                    while (!stack.isEmpty() && !"(".equals(str = stack.pop())) {
                        result.add(str);
                    }
                }
            }

            if (!"".equals(sb.toString())) {
                result.add(sb.toString());
                sb.delete(0, sb.length());
            }
            lastChar = currentChar;
        }
        // 最后清空栈
        while (!stack.isEmpty()) {
            result.add(stack.pop());
        }
        return result;
    }
    
    private int getOperationLevel(String operation) {
        int result;
        switch (operation) {
            case "+":
                result = 1;
                break;
            case "-":
                result = 1;
                break;
            case "*":
                result = 2;
                break;
            case "/":
                result = 2;
                break;
            default:
                result = 0;
                break;
        }
        return result;
    }
    
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容