1. 程式人生 > >中綴表達式轉為後綴表達式

中綴表達式轉為後綴表達式

() 正常 如何 彈出 成了 match 字符串 斜杠 壓入

首先我們想設計的表達式支持的數:整數(正整數,0,負整數)還有小數,註意了不僅僅只支持個位整數(之前做的都太局限了)

那麽我們正常的表達式要做一下處理,讓它能區分出操作符和操作數,方便我們更好的處理

想法:如果有東西能夠隔開操作符和操作數就好了.。那行,那我們就用空格隔開吧

為什麽要用空格?

因為有時候我們輸入正常的表達式的時候會習慣性的按下空格,使用空格作為分隔,以後我們會將空格處理掉,也就無意的處理掉了習慣性而產生的問題。

那好我們直接上代碼,裏面有詳細的註釋

/**
     * 40開括號( 41閉括號) 42星號(乘號) 43加號 45減號 46句號(小數點) 47斜杠(除號) 48 數字0 57 數字9
     
*/ public static void main(String[] args) { String str = "(2+3.2)+Math.ceil(4)*(409-56+(-136/5)*9)"; StringBuilder sb = new StringBuilder(); char lastC = 0; char c = 0; for (int i = 0; i < str.length(); i++) { c = str.charAt(i); if (c > 57 || c < 48) {//
非數字 if (c == 46 && lastC <= 57 && lastC >= 48) {// 小數點 如果c為小數點,並且lastC為數字,那就直接append到sb裏面 sb.append(c); } else if (lastC == 40 && c == 45) {// 負數 如果lastC為左括號,c為減號或者負號(減號),那就直接append到sb裏面 sb.append(c); }
else if (c == 40 || c == 41 || c == 42 || c == 43 || c == 45 || c == 47) {//如果是左括號 右括號 乘號 加號 減號 除號 則空格隔開,在append到sb裏面 sb.append(" ").append(c).append(" "); }else{//其他字符直接append到sb裏面 sb.append(c); } } else {// 數字 是數字就直接append到sb裏面 sb.append(c); }//記錄上一個字符 lastC = c; } System.out.println(sb.toString()); }

運行結果:

技術分享

這個表達式(2+3.2)+Math.ceil(4)*(409-56+(-136/5)*9)幾乎涵括了所有的可能性,大家先忽略Math.ceil這個字符串,這是在下一篇用到了,為了是我們的表達式更加的豐富。

那好,我們回歸正題,如何將正常的表達式寫出逆波蘭表達式呢?

思路:

  ①我們用一個相同容量的數組strs來存儲關於逆波蘭表達式的字符串,最終將會變成逆波蘭表達式,用一個棧stack s來保存操作符

  ②從左到右遍歷字符串數組

  ③當遇到操作數時,直接存儲到數組strs裏面

  ④當遇到操作符是,就要比較其與棧頂的優先級

    1、當棧stack為空,或棧頂運算符為左括號“(”,則直接將此操作符入棧;

    2、否則,若優先級比棧頂運算符的高,也將操作符壓入S1

    3、否則,將stack棧頂的運算符彈出並存儲到strs數組中,再次轉到(③-1)與stack中新的棧頂運算符相比較;

  ⑤遇到括號:

    1、當遇到左括號"{"時,將它壓入棧裏面

    2、當遇到右括號")"時,依次彈出操作符並且添加到sb裏面,直到遇到左括號“(”,此時左右括號都作廢

  ⑥重復②~⑤的步驟

  ⑦當遍歷結束後,將棧裏面剩余的操作符依次彈出並且添加到數組strs裏面

例如

(2+3.2)+4*(40-5+(-1)*4) --------> 2 3.2 + 4 40 5 - -1 4 * + * +

( 2 + 3.2 ) + 4 * ( 40 - 5 + ( -1 ) * 4 ) ---------轉換為數組---------> [(, 2, +, 3.2, ), +, 4, *, (, 40, -, 5, +, (, -1, ), *, 4, )]

遍歷到的字符串:str

存儲關於逆波蘭字符串的數組:strs

存儲操作符的stack

  str   strs      stack        理由

    (            空            (      左括號,壓入棧中

    2            ["2"]           (      數字,直接存儲到數組strs裏面 

    +            ["2"]           ( +      操作符壓入棧中

    3.2          ["2","3.2"]         ( +      數字,直接存儲到數組strs裏面

   )           ["2,"3.2","+"]         空      右括號,將操作符依次彈出,直到左括號,這時左括號已經彈出,stack空

    +         ["2,"3.2","+"]         +      stack為空,直接壓入棧

    4        ["2,"3.2","+","4"]         + 操作數,直接存儲到strs裏面

    *        ["2,"3.2","+","4"]         + *      操作符*號比棧頂的+號高,將*壓入棧

   (        ["2,"3.2","+","4"]        + * (     左括號直接壓入棧頂

    40        ["2,"3.2","+","4","40"]       + * (     數字,直接存儲到數組strs裏面

    -        ["2,"3.2","+","4","40"]       + * ( -     棧頂為左括號,操作符直接壓入棧

   5        ["2,"3.2","+","4","40","5"]      + * ( -     數字,直接存儲到數組strs裏面

   +       ["2,"3.2","+","4","40","5","-"]     + * ( +    操作符+號並沒有比操作符-號優先,所以將-號彈出,在跟新的棧頂比較

   (       ["2,"3.2","+","4","40","5","-"]    + * ( + (    左括號直接壓入棧頂

   -1      ["2,"3.2","+","4","40","5","-","-1"]    + * ( + (    數字,直接存儲到數組strs裏面

   )       ["2,"3.2","+","4","40","5","-","-1"]     + * ( +     遇到了右括號,依次彈出,直到遇到左括號

   *       ["2,"3.2","+","4","40","5","-","-1"]    + * ( + *    操作符*號的優先級比操作符+號高,直接壓入棧

   4     ["2,"3.2","+","4","40","5","-","-1","4"]    + * ( + *    數字,直接存儲到數組strs裏面

   )     ["2,"3.2","+","4","40","5","-","-1","4","*","+"] + *     右括號,依次彈出,直到遇到左括號

  最後   ["2,"3.2","+","4","40","5","-","-1","4","*","+","*","+"] 空     依次彈出棧裏面的操作符,直到為空

那麽我們最後得到的數組["2,"3.2","+","4","40","5","-","-1","4","*","+","*","+"] 是不是跟我們要的逆波蘭表達式2 3.2 + 4 40 5 - -1 4 * + * +完全一樣

那麽接下來,上代碼

// (2+3.2)+4*(40-5+(-1)*4)
    static String strs[] = { "(", "2", "+", "3.2", ")", "+", "4", "*", "(",
            "40", "-", "5", "+", "(", "-1", ")", "*", "4", ")" };// 正常的表達式經過上面的處理,變成了這樣的數組
    static String strsBo[] = new String[strs.length];// 存儲關於逆波蘭的字符串數組
    static int index = 0;// strsBo的下一個存儲下標,從0開始
    static Stack<String> stack = new Stack<>();// 存儲操作符的棧

    public static void main(String[] args) {
        for (String str : strs) {
            if (str.matches("-?[0-9]+") || str.matches("-?[0-9]+.?[0-9]+")) {// 判斷是否是數值
                strsBo[index++] = str;
            } else {
                handleStack(str);
            }
        }
        // 當遍歷結束後,將棧裏面剩余的操作符依次彈出並且添加到數組strs裏面
        while (stack != null && !stack.empty()) {
            strsBo[index++] = stack.pop();
        }
        System.out.println(Arrays.toString(strsBo));
    }

    private static void handleStack(String str) {
        if (str.equals("(")) {//當遇到左括號"{"時,將它壓入棧裏面
            stack.push(str);
        } else if (stack.isEmpty() || stack.lastElement().equals("(")) {// 棧stack為空,或棧頂運算符為左括號“(”,則直接將此操作符入棧
            stack.push(str);
        } else if (!str.equals(")")) {// 操作符不為右括號,才比較優先級
            if (priority(str, stack.lastElement())) {// 若優先級比棧頂運算符的高,也將操作符壓入stack
                stack.push(str);
            } else {// 否則,將stack棧頂的運算符彈出並存儲到strs數組中,再次與stack中新的棧頂運算符相比較
                strsBo[index++] = stack.pop();
                handleStack(str);
            }
        } else {// 遇到了右括號,依次彈出操作符並且添加到strsBo裏面,直到遇到左括號“(”,此時左右括號都作廢
            String pop = stack.pop();
            while (!pop.equals("(")) {
                strsBo[index++] = pop;
                pop = stack.pop();
            }
        }
    }

    /**
     * @return 只有str1的優先級高於str2的優先級才返回false
     *         ,只有一種情況才返回true,那就是str1為乘除,str2為加減,其他情況都為false
     */
    public static boolean priority(String str1, String str2) {
        return (str1.equals("*") || str1.equals("/"))
                && (str2.equals("+") || str2.equals("/"));
    }

運行結果:

技術分享

沒問題,跟我們要的結果一樣。下一篇將會用面向對象的思想來將他們封裝一下,是他們更容易的擴展。

中綴表達式轉為後綴表達式