本文主要內容:
- 表達式的三種形式
- 中綴表達式與后綴表達式轉換算法
一、表達式的三種形式:
- 中綴表達式:運算符放在兩個運算對象中間,如:(2+1)*3。我們從小做數學題時,一直使用的就是中綴表達式。
- 后綴表達式:不包含括號,運算符放在兩個運算對象的后面,所有的計算按運算符出現的順序,嚴格從左向右進行(不再考慮運算符的優先規則),如:2 1 + 3 *。又比如3+(6-4/2)*5=23的后綴表達式為:3642/-5*+# (#符號為結束符)
- 前綴表達式:同后綴表達式一樣,不包含括號,運算符放在兩個運算對象的前面,如:* + 2 1 3 。前綴表達式和后綴表達式其實是差不多的,只不過符號位置不同而已,前綴表達式不是很常見。
二、中綴表達式轉換為后綴表達式:(思路)
1、將中綴表達式轉換為后綴表達式:(步驟,有點難理解)
(1)當讀到數字直接送至輸出隊列中;
(2)當讀到運算符t時:
a.將棧中所有優先級高於或等於t的運算符彈出,送到輸出隊列中;
注:這句話不好理解,可以說成這樣,從棧頂開始,依次彈出比當前處理的運算符優先級高的運算符,直到一個比它優先級低的或者遇到了一個左括號就停止。
b.t進棧;
(3)讀到左括號時總是將它壓入棧中;
(4)讀到右括號時,將靠近棧頂的第一個左括號上面的運算符全部依次彈出,送至輸出隊列后,再丟棄左括號;
(5)中綴表達式全部讀完后,若棧中仍有運算符,將其送到輸出隊列中。
舉例:
上圖中,左側的那一列為輸出序列,右側的那一列為棧。
2、運用后綴表達式進行計算:
(1)建立一個棧S;
(2)從左到右讀后綴表達式,讀到數字就將它轉換為數值壓入棧S中,讀到運算符則從棧中依次彈出兩個數分別到Y和X,然后以“X 運算符 Y”的形式計算機出結果,再壓加棧S中;
(3)如果后綴表達式未讀完,就重復上面過程,最后輸出棧頂的數值則為結束。
舉例:
3+(2-5)*6/3=-3 ,其后綴表達式為:325-6*3/+。其運算結果如下:
三、代碼實現:將中綴表達式轉換為后綴表達式
- JDK Stack類使用
- 使用泛型
代碼實現:
(1)StringToArithmetic.java:(中綴表達式轉化為后綴表達式的工具類)
1 /** 2 * Created by smyhvae on 2015/9/7. 3 * 工具類: 4 * 1、中綴表達式轉化為后綴表達式 5 * 2、給出一個算術表達式(中綴表達式),直接得到計算結果 6 */ 7 8 import java.util.Stack; 9 import java.util.regex.Pattern; 10 11 public class StringToArithmetic { 12 13 private StringToArithmetic() { 14 } 15 16 //方法:給出一個算術表達式(中綴表達式),得到計算結果。 例如 (5+8+10)*1,返回23 17 public static double stringToArithmetic(String string) { 18 return suffixToArithmetic(infixToSuffix(string)); 19 } 20 21 /** 22 * 中綴表達式轉后綴表達式 只處理了+,-,*,/和括號,沒有處理負號及其它運算符,也沒對前綴表達式驗證。 23 * 如要處理負號,可對表達式進行預轉義處理,當下面條件成立時,將負號換成單目運算符"!" infix.charAt[i]=='-'&&( 24 * i==0||infix.charAt[i-1]=='(') 25 * 3*6/4+3 26 * 3+6-4 3 6 + 4 - 27 * 3+(6-4/2)*5 3 6 4 2 / - 5 * + 28 */ 29 //方法:中綴表達式轉成后綴表達式 30 public static String infixToSuffix(String infix) { 31 Stack<Character> stack = new Stack<Character>(); 32 String suffix = ""; 33 int length = infix.length(); 34 for (int i = 0; i < length; i++) { 35 Character temp; 36 char c = infix.charAt(i); 37 switch (c) { 38 // 忽略空格 39 case ' ': 40 break; 41 // 碰到'(',push到棧 42 case '(': 43 stack.push(c); 44 break; 45 // 碰到'+''-',將棧中所有運算符彈出,送到輸出隊列中 46 case '+': 47 case '-': 48 while (stack.size() != 0) { 49 temp = stack.pop(); 50 if (temp == '(') { 51 stack.push('('); 52 break; 53 } 54 suffix += " " + temp; 55 } 56 stack.push(c); 57 suffix += " "; 58 break; 59 // 碰到'*''/',將棧中所有乘除運算符彈出,送到輸出隊列中 60 case '*': 61 case '/': 62 while (stack.size() != 0) { 63 temp = stack.pop(); 64 if (temp == '(' || temp == '+' || temp == '-') { 65 stack.push(temp); 66 break; 67 } else { 68 suffix += " " + temp; 69 } 70 } 71 stack.push(c); 72 suffix += " "; 73 break; 74 // 碰到右括號,將靠近棧頂的第一個左括號上面的運算符全部依次彈出,送至輸出隊列后,再丟棄左括號 75 case ')': 76 while (stack.size() != 0) { 77 temp = stack.pop(); 78 if (temp == '(') 79 break; 80 else 81 suffix += " " + temp; 82 } 83 // suffix += " "; 84 break; 85 //如果是數字,直接送至輸出序列 86 default: 87 suffix += c; 88 } 89 } 90 91 //如果棧不為空,把剩余的運算符依次彈出,送至輸出序列。 92 while (stack.size() != 0) { 93 suffix += " " + stack.pop(); 94 } 95 return suffix; 96 } 97 98 99 /** 100 * postfix 101 * 102 * @return double 103 */ 104 //方法:通過后綴表達式求出算術結果 105 public static double suffixToArithmetic(String postfix) { 106 107 Pattern pattern = Pattern.compile("\\d+||(\\d+\\.\\d+)"); //使用正則表達式 匹配數字 108 String strings[] = postfix.split(" "); //將字符串轉化為字符串數組 109 for (int i = 0; i < strings.length; i++) 110 strings[i].trim(); //去掉字符串首尾的空格 111 Stack<Double> stack = new Stack<Double>(); 112 113 for (int i = 0; i < strings.length; i++) { 114 115 if (strings[i].equals("")) 116 continue; 117 118 //如果是數字,則進棧 119 if ((pattern.matcher(strings[i])).matches()) { 120 121 stack.push(Double.parseDouble(strings[i])); 122 } else { 123 //如果是運算符,彈出運算數,計算結果。 124 double y = stack.pop(); 125 double x = stack.pop(); 126 stack.push(caculate(x, y, strings[i])); //將運算結果重新壓入棧。 127 } 128 } 129 return stack.pop(); //彈出棧頂元素就是運算最終結果。 130 131 } 132 133 private static double caculate(double x, double y, String simble) { 134 if (simble.trim().equals("+")) 135 return x + y; 136 if (simble.trim().equals("-")) 137 return x - y; 138 if (simble.trim().equals("*")) 139 return x * y; 140 if (simble.trim().equals("/")) 141 return x / y; 142 return 0; 143 } 144 }
(2)Test.java:(測試類)
1 public class Test { 2 public static void main(String[] args) { 3 4 String str = "3+(2-5)*6/3"; //其后綴表達式為325-6*3/+ 5 6 //調用方法:中綴表達式轉成后綴表達式 7 System.out.println(StringToArithmetic.infixToSuffix(str)); 8 9 //調用方法:給出一個算術表達式(中綴表達式),得到計算結果 10 System.out.println(StringToArithmetic.stringToArithmetic(str)); 11 12 } 13 14 }
上方代碼中,第07行是根據中綴表達式算出后綴表達式。
第10行:是給出一個中綴表達式,直接的到計算結果,其實它的步驟是:先根據中綴表達式得到后綴表達式,然后根據后綴表達式去計算結果。
運行效果: