中綴表達式轉為後綴表達式
首先我們想設計的表達式支持的數:整數(正整數,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("/")); }
運行結果:
沒問題,跟我們要的結果一樣。下一篇將會用面向對象的思想來將他們封裝一下,是他們更容易的擴展。
中綴表達式轉為後綴表達式