題目:
問題描述
輸入一個只包含加減乖除和括號的合法表達式,求表達式的值。其中除表示整除。
輸入格式
輸入一行,包含一個表達式。
輸出格式
輸出這個表達式的值。
樣例輸入
1-2+3*(4-5)
樣例輸出
-4
數據規模和約定
表達式長度不超過100,表達式運算合法且運算過程都在int內進行。
初看此題,從人的直觀角度來說很簡單,先遍歷括號內的運算完再重新遍歷,但是很麻煩。
回憶起了后綴表達式的知識
中綴表達式轉后綴表達式的方法:
1.遇到操作數:直接輸出(添加到后綴表達式中)
2.棧為空時,遇到運算符,直接入棧
3.遇到左括號:將其入棧
4.遇到右括號:執行出棧操作,並將出棧的元素輸出,直到彈出棧的是左括號,左括號不輸出。
5.遇到其他運算符:加減乘除:彈出所有優先級大於或者等於該運算符的棧頂元素,然后將該運算符入棧
6.最終將棧中的元素依次出棧,輸出。
后綴表達式的計算機求值:
與前綴表達式類似,只是順序是從左至右:
從左至右掃描表達式,遇到數字時,將數字壓入堆棧,遇到運算符時,彈出棧頂的兩個數,用運算符對它們做相應的計算(次頂元素 op 棧頂元素),並將結果入棧;重復上述過程直到表達式最右端,最后運算得出的值即為表達式的結果。
例如后綴表達式“3 4 + 5 × 6 -”:
(1) 從左至右掃描,將3和4壓入堆棧;
(2) 遇到+運算符,因此彈出4和3(4為棧頂元素,3為次頂元素,注意與前綴表達式做比較),計算出3+4的值,得7,再將7入棧;
(3) 將5入棧;
(4) 接下來是×運算符,因此彈出5和7,計算出7×5=35,將35入棧;
(5) 將6入棧;
(6) 最后是-運算符,計算出35-6的值,即29,由此得出最終結果。
一開始,我先把中綴表達式轉換為后綴表達式,再對后綴表達式求值。
有一個很大的問題,數字的保存,轉化為后綴表達式時保存為char字符,對於大於9的數字保存很麻煩。
后來想了想,可以直接借用后綴表達式的計算方法。
代碼如下
1 public class Main { 2 public static void main(String[] args) { 3 // TODO Auto-generated method stub 4 Scanner scanner = new Scanner(System.in); 5 Stack<Integer> nums = new Stack<Integer>(); // 保存數字 6 Stack<Character> opes = new Stack<Character>(); // 保存操作符 7 String string = scanner.nextLine(); 8 int n = 0; // 保存每一個數字 9 char[] cs = string.toCharArray(); 10 for (int i = 0; i < cs.length; i++) { 11 char temp = cs[i]; 12 if (Character.isDigit(cs[i])) { 13 n = 10 * n + Integer.parseInt(String.valueOf(cs[i])); // 大於10的數字保存 14 } else { 15 if (n != 0) { 16 nums.push(n); 17 n = 0; 18 } 19 if (temp == '(') { 20 opes.push(temp); 21 } else if (temp == ')') { 22 while (opes.peek() != '(') { // 括號里面運算完 23 int t = cal(nums.pop(), nums.pop(), opes.pop()); 24 nums.push(t); 25 } 26 opes.pop(); 27 } else if (isType(temp) > 0) { 28 if (opes.isEmpty()) { // 棧為空直接入棧 29 opes.push(temp); 30 } else { 31 // 若棧頂元素優先級大於或等於要入棧的元素,將棧頂元素彈出並計算,然后入棧 32 if (isType(opes.peek()) >= isType(temp)) { 33 int t = cal(nums.pop(), nums.pop(), opes.pop()); 34 nums.push(t); 35 } 36 opes.push(temp); 37 } 38 } 39 } 40 } 41 // 最后一個字符若是數字,未入棧 42 if (n != 0) { 43 nums.push(n); 44 } 45 while (!opes.isEmpty()) { 46 int t = cal(nums.pop(), nums.pop(), opes.pop()); 47 nums.push(t); 48 } 49 System.out.println(nums.pop()); 50 } 51 52 // 返回的是運算符的優先級,數字和()不需要考慮 53 public static int isType(char c) { 54 if (c == '+' || c == '-') { 55 return 1; 56 } else if (c == '*' || c == '/') { 57 return 2; 58 } else { 59 return 0; 60 } 61 } 62 63 // 運算次序是反的,跟入棧出棧次序有關 64 public static int cal(int m, int n, char c) { 65 int sum = -987654321; 66 if (c == '+') { 67 sum = n + m; 68 } else if (c == '-') { 69 sum = n - m; 70 } else if (c == '*') { 71 sum = n * m; 72 } else if (c == '/') { 73 sum = n / m; 74 } 75 return sum; 76 } 77 }