使用棧結構計算中綴表示式

頂風少年發表於2020-10-08

棧中元素的順序是先進後出,新增的元素總在棧頂,出棧也是先出棧頂,就像彈夾一樣。中綴表示式是我們人計算表示式的方式例如 (2*3-2)*(3+3*3)我們總會括號優先,* / 優先於+ -

使用棧結構計算這個表示式的核心思想就是搞兩個棧,一個存放數字,一個存放符號。

使用棧結構計算中綴表示式
package com.dfsn.cloud.eureka;

public class Stack<T> {

    private Object arr[];

    private int top = -1;

    public Stack(int capacity) {
        arr = new Object[capacity];
    }

    public void push(T t) {
        if (isFull()) {
            throw new RuntimeException("棧已滿,無法新增");
        }
        top++;
        arr[top] = t;
    }

    public T pop() {
        if (isEmpty()) {
            throw new RuntimeException("棧為空,沒有元素");
        }
        return (T) arr[top--];
    }

    public T peek() {
        if (isEmpty()) {
            throw new RuntimeException("棧為空,沒有元素");
        }
        return (T) arr[top];
    }

    public boolean isEmpty() {
        return top == -1;
    }

    public boolean isFull() {
        return top == arr.length - 1;
    }

    public void show() {
        for (int i = 0; i <= top; i++) {
            System.out.println(arr[i]);
        }
    }

    public int size() {
        return top + 1;
    }

}
View Code

 

使用棧結構計算中綴表示式
package com.dfsn.cloud.eureka;

//中綴表示式
public class NifixExpression {

    public int calculate(String expression) {

        // 限定最多10個數字
        Stack<Integer> numberStack = new Stack<>(10);
        // 10個數字需要9個字元
        Stack<String> symbolStack = new Stack<>(9);

        for (int i = 0; i < expression.length(); i++) {
            String current = expression.substring(i, i + 1);
            // 是數字還是字元
            int symbolOrNumber = symbolOrNumber(current);
            // 是數字
            if (symbolOrNumber == 0) {
                // 如果是數字,則需要判斷後邊的是不是數字,防止多位數
                int concatNumber = concatNumber(expression.substring(i));
                // 如果是多位數迴圈需要跳過比如 123+2
                // 取出123 後下一個要取 + 也就是 i+(123.length),但迴圈本身會自增1所以只能+123.length-1
                i += (concatNumber + "").length() - 1;
                // 入數字棧
                numberStack.push(concatNumber);
            } else {// 是符號
                if (symbolStack.isEmpty()) {
                    // 符號棧沒有符號,則入棧
                    symbolStack.push(current);
                } else {
                    // 如果是左括號直接入棧
                    if (current.equals("(")) {
                        symbolStack.push(current);
                        continue;
                    }
                    // 如果是右括號,則需要每次彈出一個符號和兩個數字做運算
                    // 直到碰到 ( 符號結束,並把 ( 出棧
                    if (current.equals(")")) {
                        while (true) {
                            if (symbolStack.peek().equals("(")) {
                                symbolStack.pop();
                                break;
                            } else {
                                int number2 = numberStack.pop();
                                int number1 = numberStack.pop();
                                String symbol = symbolStack.pop();
                                int result = operation(number1, number2, symbol);
                                numberStack.push(result);
                            }
                        }
                        continue;
                    }

                    // 拿出符號棧頂元素和當前符號對比,如果棧頂符號是 ( 則為0,因為它只有遇到)才有意義
                    String stackTop = symbolStack.peek();
                    int stackTopPriority = priority(stackTop);
                    int priority = priority(current);
                    // 如果當前符號優先順序大於棧頂符號優先順序,將當前符號新增到棧頂
                    if (priority > stackTopPriority) {
                        symbolStack.push(current);
                    } else {
                        // 如果當前符號優先順序小於等於棧頂運算子優先順序,則從符號棧頂彈出一個符號
                        // 從數字棧中彈出兩個數字做運算 注意:棧頂元素在右
                        // 將結果入數字棧,最後將當前運算子入符號棧
                        int number2 = numberStack.pop();
                        int number1 = numberStack.pop();
                        String symbol = symbolStack.pop();
                        int result = operation(number1, number2, symbol);
                        numberStack.push(result);
                        symbolStack.push(current);
                    }
                }
            }
        }
        // 最後兩個佇列可能還有元素,則順序彈出1個符號和兩個數字做運算,並且將結果入數字棧
        while (true) {
            if (symbolStack.isEmpty()) {
                break;
            } else {
                int number2 = numberStack.pop();
                int number1 = numberStack.pop();
                String symbol = symbolStack.pop();
                int result = operation(number1, number2, symbol);
                numberStack.push(result);
            }
        }
        if (numberStack.size() != 1) {
            throw new RuntimeException("運算異常");
        } else {
            return numberStack.pop();
        }

    }

    // 返回1表示是運算子,返回0表示是數字
    public int symbolOrNumber(String expression) {
        if (expression.equals("+") || expression.equals("-") || expression.equals("*") || expression.equals("/")
                || expression.equals("(") || expression.equals(")")) {
            return 1;
        } else if (expression.equals("0") || expression.equals("1") || expression.equals("2") || expression.equals("3")
                || expression.equals("4") || expression.equals("5") || expression.equals("6") || expression.equals("7")
                || expression.equals("8") || expression.equals("9")) {
            return 0;
        } else {
            throw new RuntimeException("不是數字也不是運算子");
        }
    }

    // 返回運算子的等級 * / 高
    public int priority(String symbol) {
        if (symbol.equals("+") || symbol.equals("-")) {
            return 1;
        } else if (symbol.equals("*") || symbol.equals("/")) {
            return 2;
        } else if (symbol.equals("(")) {
            return 0;
        } else {
            throw new RuntimeException("無法識別運算子");
        }
    }

    // 獲取字串中第一個連續數字
    public int concatNumber(String str) {
        StringBuilder strNumber = new StringBuilder();
        int index = 0;
        while (true) {
            if (index > str.length() - 1) {
                break;
            }
            String ch = str.charAt(index) + "";
            if (symbolOrNumber(ch) == 0) {
                strNumber.append(ch);
                index++;
            } else {
                break;
            }
        }
        return Integer.parseInt(strNumber.toString());
    }

    // 做運算
    public int operation(int number1, int number2, String symbol) {
        switch (symbol) {
        case "+":
            return number1 + number2;
        case "-":
            return number1 - number2;
        case "*":
            return number1 * number2;
        case "/":
            return number1 / number2;
        default:
            throw new RuntimeException("運算子不正確");
        }
    }

}
View Code

 

相關文章