數據結構學習(五):逆波蘭表達式(後綴表達式)

一、將中綴表達式轉換成後綴表達式的具體思路

  1. 初始化2個棧:運算符棧s1和儲存中間結果的棧s2;

  2. 從左至右掃描中綴表達式;

  3. 遇到操作數時,將其壓入s2;

  4. 遇到運算符時,比較其與s1棧頂運算符的優先級:
    (1)如果s1爲空,或棧頂運算符爲“(”,則將此運算符入棧;
    (2)否則,若優先級比棧頂運算符的高,也將運算符壓入s1;
    (3)否則,將s1棧頂的運算符彈出並壓入到s2中,再次轉到4.1與新的運算符比較。

  5. 遇到括號時:
    (1)“(”:壓入s1;
    (2)“)”:依次彈出s1棧頂的運算符,並壓入s2,直到遇到“(”爲止,此時將這一對括號丟棄;

  6. 重複步驟2至5,直到表達式最右邊;

  7. 將s1中剩餘的運算符依次彈出壓入s2;

  8. 依次彈出s2中的元素並輸出,結果的逆序即爲中綴表達式對應的後綴表達式。

二、將中綴表達式轉換成對應的List

public static List<String> toInfixExpressionList(String s) {
        //定義一個List,存放中綴表達式對應的內容
        List<String> list = new ArrayList<>();
        //用於遍歷中綴表達式字符串
        int i = 0;
        //拼接多位數
        String str;
        //遍歷一個字符就放入c
        char c;

        do{
            //如果c是一個非數字,需要加入到list
            if((c = s.charAt(i)) < 48 || (c = s.charAt(i)) > 57) {
                list.add(c + "");
                i ++;
            }else {
                //如果是一個數,要考慮多位數

                //現將str置成""
                str = "";
                //'0'[48] '9'[57]
                while (i < s.length() && (c = s.charAt(i)) >= 48 && (c = s.charAt(i)) <= 57) {
                    //拼接
                    str += c;
                    i ++;
                }
                list.add(str);
            }
        }while ( i < s.length()) ;

        return list;
    }

三、將得到的中綴表達式對應的List 轉換爲後綴表達式對應的List

public static List<String> parseSuffixExpreesionList(List<String> list) {
        //符號棧
        Stack<String> s1 = new Stack<>();
        //因爲s2在整個轉換過程中,沒有pop操作,而且後面還要逆向輸出,因此不使用Stack而是List
        //儲存中間結果的List
        List<String> s2 = new ArrayList<>();

        for (String item: list) {
            //如果是一個數
            if(item.matches("\\d+")) {
                s2.add(item);
            }else if(item.equals("(")) {
                s1.push(item);
            }else if(item.equals(")")) {
                //如果是),則依次彈出s1棧頂的運算符,並壓入s2,直到遇到(爲止,此時將這一對括號丟棄
                while (!s1.peek().equals("(")) {
                    s2.add(s1.pop());
                }
                //將(彈出s1棧,消除小括號
                s1.pop();
            }else {
                //當item的優先級小於等於s1棧頂運算符,將s1棧頂的運算符彈出並加入到s2中,再次轉到(4,1)與新的棧頂運算符比較
                while (s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item)) {
                    s2.add(s1.pop());
                }
                //將item壓入棧
                s1.push(item);
            }
        }

        //將s1中剩餘的運算符依次彈出並加入s2
        while (s1.size() != 0) {
            s2.add(s1.pop());
        }

        return s2;
    }

四、完成對逆波蘭表達式(後綴表達式)的運算

思路:以3 4 + 5 * 6 -爲例

  1. 從左至右掃描,將3和4壓入堆棧;
  2. 遇到+運算符,彈出3和4,計算3+4的值,得7,再將7入棧;
  3. 將5入棧;
  4. 接下來是×運算符,彈出5和7,計算7*5得35,將35入棧;
  5. 將6入棧;
  6. 最後是-運算符,計算出35-6的值,即29,由此得出最終結果。
public static int calculate(List<String> list) {
        Stack<String> stack = new Stack<>();
        for (String item: list) {
            //使用正則表達式匹配多位數
            if(item.matches("\\d+")) {
                //入棧
                stack.push(item);
            }else {
                int num2 = Integer.parseInt(stack.pop());
                int num1 = Integer.parseInt(stack.pop());
                int res = 0;

                if(item.equals("+")) {
                    res = num1 + num2;
                }else if(item.equals("-")) {
                    res = num1 - num2;
                }else if(item.equals("*")) {
                    res = num1 * num2;
                }else if(item.equals("/")) {
                    res = num1 / num2;
                }else {
                    throw new RuntimeException("運算符有誤");
                }
                //把res入棧
                stack.push(res + "");
            }
        }
        return Integer.parseInt(stack.pop());
    }

五、編寫一個類,返回一個運算符對應的優先級

class Operation {
    private static int ADD = 1;
    private static int SUB = 1;
    private static int MUL = 2;
    private static int DIV = 2;

    //寫一個方法,返回對應的優先級數字
    public static int getValue(String operation) {
        int result = 0;
        switch (operation) {
            case "+":
                result = ADD;
                break;
            case "-":
                result = SUB;
                break;
            case "*":
                result = MUL;
                break;
            case "/":
                result = DIV;
                break;
            default:
                break;
        }
        return result;
    }
}

六、測試

public static void main(String[] args) {

        String expression = "1+((2+3)*4)-5";
        List<String> infixExpreesionList = toInfixExpressionList(expression);
        System.out.println(infixExpreesionList);

        List<String> parseSuffixExpressionList = parseSuffixExpreesionList(infixExpreesionList);
        System.out.println(parseSuffixExpressionList);
        System.out.println(calculate(parseSuffixExpressionList));
        }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章