用 Stack 計算四則運算表達式的值

大家都知道四則運算表達式是有優(yōu)先條件的 。比如先乘除再加減。而且如果有括號的話還要先計算括號里面。有沒有想過現(xiàn)在的高級計算器是如何實現(xiàn)這一功能的呢?

這里面的困難就在于乘除有時候在后面卻要先計算,在加上有括號的情況就更加復雜了。

  • 后綴表達式

類似 9 + (3 - 1) * 3 + 10 / 2 是我們常見的表達式,叫『中綴表達式』。后綴表達式不同與中綴表達式,之所以叫“后綴表達式”是因為所有的運算符都在數(shù)字后面出現(xiàn)。所以9 + (3 - 1) * 3 + 10 / 2的后綴表達式為:9 3 1 - 3 * + 10 2 / +
顯然,是沒有括號的。

  • 后綴表達式計算結(jié)果

后綴表達式為:9 3 1 - 3 * + 10 2 / +

規(guī)則:從左到右遍歷遍歷表達式的每一個數(shù)字和符號,遇到數(shù)字就進棧 ,遇到符號就棧頂?shù)膬蓚€數(shù)字出棧,然后進行運算,然后將運算結(jié)果進棧 。一直到最后,棧里面的值即為最終結(jié)果。

  1. 初始化空棧, 9 3 1 依次進棧。棧內(nèi)從下到上依次是:9,3,1
  2. 然后 - 號進棧,3 - 1 = 2, 2 進棧。棧內(nèi)從下到上依次是:9,2
  3. 接著 3 進棧。棧內(nèi)從下到上依次是:9,2,3
  4. * 號進棧,2 * 3 = 6,6 進棧。棧內(nèi)從下到上依次是:9,6
  5. + 號進棧,9 + 6 = 15, 15 進棧。棧內(nèi)從下到上依次是: 15
  6. 10, 2 依次進棧。棧內(nèi)從下到上依次是: 15,10,2
  7. / 號進棧,10 / 2 = 5, 5 進棧。棧內(nèi)從下到上依次是: 15,5
  8. + 號進棧,15 + 5 = 20。20 進棧。

至此結(jié)束,表達式最終結(jié)果:20

看來計算機果然適合計算后綴表達式求值,那么現(xiàn)在的問題就是如何把我們常見的中綴表達式轉(zhuǎn)換為后綴表達式呢?


  • 中綴表達式轉(zhuǎn)后綴表達式

規(guī)則:從左到右遍歷表達式的每個數(shù)字和符號

  1. 遇到數(shù)字直接輸出,成為后綴表達式的一部分。
  2. 棧為空時,遇到運算符,直接入棧
  3. 當前符號是 (, 則直接進棧
  4. 當前符號是 ), 則把棧中的符號依次出棧,直到遇到 )為止。) 不輸出。
  5. 若是 + - * / 運算符號,彈出所有優(yōu)先級大于或者等于該運算符的棧頂元素,然后將該運算符入棧;直到遇到棧頂符號為 ) 或棧空 [+ - 為一級,* / 為 二級]

中綴表達式 9 + (3 - 1) * 3 + 10 / 2 轉(zhuǎn)后綴表達式為: 9 3 1 - 3 * + 10 2 / +

  1. 9 直接輸出。結(jié)果集:9;
  2. + 入棧。結(jié)果集:9;棧內(nèi)從下到上依次是:+
  3. ( 直接入棧。結(jié)果集:9;棧內(nèi)從下到上依次是:+,(
  4. 3 直接輸出。結(jié)果集:9,3;棧內(nèi)從下到上依次是:+,(
  5. - 入棧,優(yōu)先級低于棧頂符號 (,直接入棧。結(jié)果集:9,3;棧內(nèi)從下到上依次是:+,(,-
  6. 1 直接輸出。結(jié)果集:9,3,1;棧內(nèi)從下到上依次是:+,(,-
  7. 下一個符號是 ),因此循環(huán)出棧,直到遇到 (.結(jié)果集:9,3,1,-;棧內(nèi)從下到上依次是:+
  8. * 入棧。因為棧頂是 +,優(yōu)先級低于 *, 所以 * 直接入棧。結(jié)果集:9,3,1,-;棧內(nèi)從下到上依次是:+,*
  9. 3 直接輸出。結(jié)果集:9,3,1,-,3;棧內(nèi)從下到上依次是:+,*
  10. + 入棧,棧頂 * 優(yōu)先級高于 +,固 * 出棧并輸出。下一個是 +, 優(yōu)先級等于 +。出棧,+ 入棧。結(jié)果集:9,3,1,-,3,*,+;棧內(nèi)從下到上依次是:+
    此時棧底的+是3+10的+,表達式里面的+是第一個+
  11. 10 直接輸出。結(jié)果集:9,3,1,-,3,*,+,10;棧內(nèi)從下到上依次是:+
  12. / 入棧,優(yōu)先級高于棧頂符號 +。直接入棧。結(jié)果集:9,3,1,-,3,*,+,10;棧內(nèi)從下到上依次是:+,/
  13. 2 直接輸出。結(jié)果集:9,3,1,-,3,*,+,10,2;棧內(nèi)從下到上依次是:+,/
  14. 循環(huán)出棧。結(jié)果集:9,3,1,-,3,*,+,10,2,/,+
代碼如下:
/**
     * 根據(jù)后綴表達式計算結(jié)果集
     * @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());
    }


/**
     * 將中綴表達式轉(zhuǎn)換為后綴表達式
     *
     * @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);

            // 上一個字符 和 當前字符 都是數(shù)字的話
            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:當前符號是 + - * /, 彈出所有優(yōu)先級大于或者等于該運算符的棧頂元素,然后將該運算符入棧
                 * 3:當前符號是 ), 則把棧中的符號依次出棧,直到遇到 )為止。
                 */

                if ("(".equals(currentChar)) {
                    stack.push(currentChar);
                } else if (operation.contains(currentChar)) {
                    /*while (true) {
                        // 棧空、棧頂符號為"("、當前符號優(yōu)先級 > 棧頂符號優(yōu)先級。當前符號入棧
                        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;
    }
    
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容