字首中綴字尾表示式以及字尾表示式簡單計算的實現
7.5 字首,中綴,字尾表示式(逆波蘭表示式)
7.5.1 字首表示式(波蘭表示式)
-
字首表示式又稱波蘭表示式,字首表示式的運算子位於運算元之前
-
舉例說明:
(3 + 4) X 5 - 6
對應的字首表示式就是- X + 3 4 5 6
7.5.1.1 字首表示式的計算機求值
從 右至左掃描 表示式,遇到數字時,將數字壓入堆疊,遇到運算子時,彈出棧頂的兩個數,用運算子對他們左相應的計算(堆頂元素 和 此頂元素), 並將結果入棧;重複上述過程直到表示式最左端,最後運算得出的值即為表示式的結果
例如:(3+4)X5-6
對應的字首表示式就是-X+3456
,針對字首表示式求值步驟如下:
-
從右至左掃描
-
遇到
+
運算子,因此彈出3和4(3為棧頂元素,4為次頂元素,減肥操作時是先出來的數減去後出來的數),計算出3+4
的值,得到7,在將7壓入棧 -
接下來就是
X
運算子,因此彈出7和5,計算出7X5=35
,將35入棧 -
最後是
-
運算子,計算出35-6
的值,即29,由此得出最終結果
7.5.2 中綴表示式
-
中綴表示式就是常見的預算表達式;如
(3+4)X5-6
-
中綴表示式的求值是我們人最熟悉的,但是對計算機來說卻不會操作,(就是之前使用陣列棧進行計算的時候,要事先將運算子的優先順序錄入,以及每次讀到運算子的時候要先獲得它的優先順序進行比較)因此,在計算結果時,往往會將中綴表示式轉成其他表示式來操作(一般轉換成字尾表示式)
7.5.3 字尾表示式(逆波蘭表示式)
-
字尾表示式又稱逆波蘭表示式,與字首表示式相似,只是運算子位於運算元之後
-
中綴表示式舉例說明:
(3+4)X5-6
對應的字尾表示式就是3 4 + 5 X 6 -
-
7.5.3.1 字尾表示式的計算機求值
從左至右掃描表示式,遇到數字時,將數字壓入堆疊,遇到運算子時,彈出棧頂的兩個數,用運算子對它們做相應的計算(此頂元素和棧頂元素),並將結果入棧:重複上述過程直到表示式最右端,最後運算得出的值即為表示式的結果
例如:(3+4)X5-6
對應的字尾表示式就是-X+3456
,針對字首表示式求值步驟如下:
-
從左至右掃描,將 3 和 4 壓入堆疊
-
遇到 + 運算子,因此彈出 4 和 3 (4為棧頂元素,3 為次頂元素),計算出 3 + 4 的值,得 7, 再將 7 入棧
-
將 5 入棧
-
接下來是 X 運算子,因此彈出 5 和 7,計算出 7 X 5 = 35, 將 35 入棧
-
將 6 入棧
-
最後是 - 運算子,計算出 35 - 6(減法運算或者除法運算的時候,字尾表示式是 次頂元素 減去或除以 堆頂元素) 的值,即 29 ,由此得出最終結果
7.6 逆波蘭計算器
我們完成一個逆波蘭表示式,要求完成如下任務:
-
輸入一個逆波蘭表示式(字尾表示式),使用棧(stack用系統提供的棧實現),計算其結果
-
支援小括號和多位數整數,以為這裡我們主要講的是資料結構,依次計算器進行簡化,支支援對整數的計算。
1 package stack; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 import java.util.Stack; 6 7 public class PolandNotation { 8 public static void main(String[] args) { 9 // 先定義 逆波蘭表示式 10 // (3+4)X5-6 => 3 4 + 5 x 6 - 11 // 4 * 5 - 8 + 60 + 8 / 2 => 4 5 * 8 - 60 + 8 2 / + 12 // 說明為了方便,逆波蘭表示式 的數字和符號使用空格隔開 13 // String expression = "30 4 + 5 * 6 -"; 14 String expression = "4 5 * 8 - 60 + 8 2 / +"; 15 // 思路: 16 // 1. 先將“3 4 + 5 x 6 -”放進ArrayList中(省的一個一個掃描) 17 // 2. 將 ArrayList 傳遞給一個方法,遍歷 Array List 配合棧完成計算 18 19 List<String> list = getListString(expression); 20 System.out.println("rpnList="+list); 21 22 int res = calculate(list); 23 System.out.println("(3+4)X 5-6"+"計算的結果是:" + res); 24 } 25 26 // 將一個逆波蘭表示式,依次將資料和運算子 放入ArrayList 27 public static List<String> getListString(String expression){ 28 // 將 expression 分割 29 String[] split = expression.split(" "); 30 List<String> list = new ArrayList<String>(); 31 for (String ele : split){ 32 list.add(ele); 33 } 34 return list; 35 } 36 // 完成對逆波蘭表示式的運算 37 /* 38 1. 從左至右掃描,將 3 和 4 壓入堆疊 39 2. 遇到 + 運算子,因此彈出 4 和 3 (4為棧頂元素,3 為次頂元素),計算出 3 + 4 的值,得 7, 再將 7 入棧 40 3. 將 5 入棧 41 4. 接下來是 X 運算子,因此彈出 5 和 7,計算出 7 X 5 = 35, 將 35 入棧 42 5. 將 6 入棧 43 6. 最後是 - 運算子,計算出 35 - 6(減法運算或者除法運算的時候,字尾表示式是 次頂元素 減去或除以 堆頂元素) 的值,即 29 ,由此得出最終結果 44 */ 45 46 public static int calculate(List<String> ls){ 47 // 建立一個棧,只需要一個棧即可 48 Stack<String> stack = new Stack<>(); 49 // 遍歷 ls 50 for(String item : ls){ 51 // 這裡使用一個正則表示式取出數 52 if (item.matches("\\d+")){ 53 // 匹配的是多位數 54 stack.push(item); 55 } else { 56 // pop 出兩個數並運算,在入棧 57 int num2 = Integer.parseInt(stack.pop()); 58 int num1 = Integer.parseInt(stack.pop()); 59 int res = 0; 60 if (item.equals("+")){ 61 res = num1 + num2; 62 } else if (item.equals("-")){ 63 res = num1 - num2; 64 } else if (item.equals("*")){ 65 res = num1 * num2; 66 } else if (item.equals("/")){ 67 res = num1 / num2; 68 } else { 69 throw new RuntimeException("符號有問題"); 70 } 71 // 把res入棧,入棧的時候要將res轉換成字元,因為我們的棧是字串型別的 72 stack.push(res+""); 73 } 74 } 75 // 最後留在stack的資料是運算結果 76 return Integer.parseInt(stack.pop()); 77 } 78 }