數據結構與算法之計算器實現(中綴轉後綴,用後綴表達式實現)

/**
 * 後綴表達式實現計算器
 */
public class SuffixExpressionCalculator {

    /**
     * 計算方法
     *
     * @param infixExpr 中綴表達式
     * @return 結果
     */
    public int calculate(String infixExpr) {
        Stack<Integer> stack = new Stack<>();
        List<String> suffixExprList = infixToSuffix(infixExpr);
        System.out.println("後綴表達式: " + suffixExprList);
        for (String str : suffixExprList) {
            char ch = str.charAt(0);
            if (!isOperator(ch)) {
                //stack.push((int) ch); 這裏出問題, 舉個例子: 本來應該是數字類型的5, 現在是char類型的 '5' 轉換成int之後是53,肯定就不對了
                stack.push(Integer.parseInt(str));
            } else {
                int num1 = stack.pop();
                int num2 = stack.pop();
                stack.push(operate(num1, num2, ch));
            }
        }
        return stack.pop();
    }

    /**
     * 加減乘除四則運算
     *
     * @param num1     值1
     * @param num2     值2
     * @param operator 操作符
     * @return 結果
     */
    private int operate(int num1, int num2, char operator) {
        int result = 0;
        switch (operator) {
            case '+':
                result = num1 + num2;
                break;
            case '-':
                result = num2 - num1;
                break;
            case '*':
                result = num1 * num2;
                break;
            case '/':
                result = num2 / num1;
                break;
        }
        return result;
    }

    /**
     * 中綴轉後綴
     *
     * @param infixExpr 中綴表達式
     * @return 後綴表達式
     */
    private List<String> infixToSuffix(String infixExpr) {
//        Stack<Integer> stackNum = new Stack<>(); 這裏出現問題:如果泛型都是Integer那最終結果輸出的字符char也會轉爲int, 導致無法分辨出數字和符號
//        Stack<Integer> stackOpe = new Stack<>();
        Stack<String> stackNum = new Stack<>();
        Stack<String> stackOpe = new Stack<>();
        int len = infixExpr.length();
        for (int i = 0; i < len; ) {
            char ch = infixExpr.charAt(i);
            String chStr = String.valueOf(ch);
            // 判斷是否是操作符
            if (isOperator(ch)) { // 是操作符
                if (stackOpe.empty()) { // 是操作符且棧爲空,則符號直接入棧
                    stackOpe.push(chStr);
                } else { // 如果符號棧不爲空
                    char top = stackOpe.peek().charAt(0);
                    // 判斷當前符號與棧頂符號的優先級
                    if (priority(ch) <= priority(top)) { // 當前符號優先級小於等於棧頂符號
                        if (top != '(') { // 棧頂符號不是左括號
                            stackNum.push(stackOpe.pop()); // 此時, 將棧頂符號取出壓入數字棧
                        }
                        stackOpe.push(chStr); // 再將當前符號壓入符號棧, 這裏還包含一種情況是如果top=='(',則符號直接入棧
                    } else { // 當前符號優先級大於棧頂符號
                        if (ch == ')') { // 當前符號是右括號, 需要依次彈出棧中符號壓入數字棧,直到左括號爲止, 注意: 左括號也需要彈出,但是不入數字棧
                            while (true) {
                                String cha = stackOpe.pop();
                                if (cha.charAt(0) == '(') {
                                    //stackOpe.pop();  這裏出現問題: 多取了一次
                                    break;
                                }
                                stackNum.push(cha);
                            }
                        } else { // 當前符號不是右括號, 且當前符號優先級大於棧頂符號, 則當前符號直接入棧
                            stackOpe.push(chStr);
                        }
                    }
                }
                i++; // 循環 + 1
            } else { // 字符是數字
                StringBuilder sb = new StringBuilder();
                sb.append(ch);
                // 數字有可能不是個位數, 有可能是多位數, 所以按照char遍歷就會出問題, 這裏while循環就是處理這種情況
                while (true) {
                    i++; // 循環 + 1
                    if (i == len) { // 處理多位數在表達式最後的情況, 如果等於了表達式的長度就退出
                        break;
                    }
                    char cha = infixExpr.charAt(i);
                    if (isOperator(cha)) { // 處理多位數在表達式中間的情況, 如果是操作符就退出
                        break;
                    }
                    sb.append(cha);
                }
                // 把得到的數字壓入數字棧
                stackNum.push(sb.toString());
            }
        }
        while (!stackOpe.isEmpty()) {
            stackNum.push(stackOpe.pop());
        }
        List<String> list = new ArrayList<>();
        List<String> listData = new ArrayList<>();
        while (!stackNum.isEmpty()) {
            list.add(stackNum.pop());
        }
        // 轉爲逆序(逆波蘭)
        for (int i = list.size() - 1; i > -1; i--) {
            listData.add(list.get(i));
        }
        return listData;
    }

    private boolean isOperator(char ch) {
        return ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '(' || ch == ')';
    }

    private int priority(char ch) {
        if (ch == '+' || ch == '-') {
            return 0;
        }
        if (ch == '*' || ch == '/') {
            return 1;
        }
        if (ch == '(' || ch == ')') {
            return 2;
        }
        return -1;
    }

    public static void main(String[] args) {
        SuffixExpressionCalculator sec = new SuffixExpressionCalculator();
        System.out.println(sec.calculate("5*(3+4)-6+80"));
    }
}
打印結果:

後綴表達式: [5, 3, 4, +, *, 6, -, 80, +]
109

之前的博客中已經把思路寫出來了,這篇博客用代碼來實現一下,也算自己的學習筆記。祝大家週末愉快~~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章