使用棧實現解析算術表達式
阿新 • • 發佈:2018-06-24
加減乘除 put @param 其他 max operator HR rgs code
目的
1. 使用棧將中綴表達式轉換成後綴表達式
2. 使用後綴表達式求算術值
註意:
因為是簡單實踐,所以代碼邏輯已經簡化,比如只能對個位數的加減乘除進行解析、沒有設異常處理等
一:需要實現一個棧
這個沒什麽好說的,只是一個結構很簡單的棧
1 public class Stack { 2 3 private int maxSize; 4 private int top; 5 private Object[] stackArr; 6 7 public Stack(int maxSize) { 8 this.maxSize = maxSize;View Code9 stackArr = new Object[maxSize]; 10 top = -1; 11 } 12 13 public void push(Object i){ 14 stackArr[++top] = i; 15 } 16 17 public Object pop(){ 18 return stackArr[top--]; 19 } 20 21 public Object peek(){ 22 return stackArr[top]; 23 }24 25 public Object peekN(int n) { 26 return stackArr[n]; 27 } 28 29 public boolean isEmpty(){ 30 return (top == -1); 31 } 32 33 public boolean isFull(){ 34 return (top == maxSize-1); 35 } 36 37 public int size(){ 38 return top+1; 39 }40 41 public void dispaly(String s) { 42 System.out.print(s + "\t\t" + "Stack {bottom-->top}: "); 43 for (int i = 0; i < size(); i++) { 44 System.out.print(peekN(i) + "\t"); 45 } 46 System.out.println(); 47 } 48 }
二:將中綴表達式轉換成後綴表達式
這裏需要處理的操作符有:"+"、"-"、 "*"、 "/"、 "(" 、")"
需要關註的有四點:
(1)操作符的優先級: "( )" > "* /" > "+ -"
(2)同級操作符的操作順序是無所謂的,只要操作數順序不變即可
(3)遇到高優先級操作時,棧的壓棧和出棧的實現
(4)棧存的是操作符
1 public class InfixToPostfix { 2 3 private Stack stack; 4 private String input; 5 private StringBuilder output; 6 /** 7 * 加減類型 8 */ 9 private static final int ADD_SUB_TYPE = 1; 10 /** 11 * 乘除類型 12 */ 13 private static final int MUL_DIV_TYPE = 2; 14 15 public InfixToPostfix(String input) { 16 this.input = input; 17 stack = new Stack(input.length()); 18 output = new StringBuilder(); 19 } 20 21 public String doTransform() { 22 String[] split = input.split(""); 23 for (int i = 0; i < split.length; i++) { 24 stack.dispaly("FOR\t\t" + split[i]); 25 switch (split[i]) { 26 case "+": 27 case "-": 28 // 對"+"、"-"操作符進行處理 29 manageOperator(split[i], ADD_SUB_TYPE); 30 break; 31 case "*": 32 case "/": 33 // 對"*"、"/"操作符進行處理 34 manageOperator(split[i], MUL_DIV_TYPE); 35 break; 36 case "(": 37 // 左括號表示下一個計算塊擁有更高一級優先級,直接入棧即可 38 stack.push(split[i]); 39 break; 40 case ")": 41 // 對")"操作符進行處理 42 manageParen(split[i]); 43 break; 44 default: 45 // 拼接輸出結果 46 output.append(split[i]); 47 break; 48 } 49 } 50 // 將棧內剩余的元素全部出棧 51 while (!stack.isEmpty()) { 52 stack.dispaly("WHILE\t"); 53 String pop = (String) stack.pop(); 54 output.append(pop); 55 } 56 stack.dispaly("END\t\t"); 57 return output.toString(); 58 } 59 60 /** 61 * 對右括號操作符進行處理 62 * @param rightParen 63 */ 64 private void manageParen(String rightParen) { 65 // 取出當前棧頂元素 66 while (!stack.isEmpty()) { 67 String top = (String) stack.pop(); 68 // 有兩種情況: 69 // 1. 取出的是 "(",說明被括號括起來的計算塊已經結束,直接break掉循環即可。 70 // 2. 取出來的是其他操作符(+-*/),出棧並打印即可。這裏不能break,因為操作符可能有多個,要一直出棧,直到取到 "(" 71 if (top.equals("(")) { 72 break; 73 } else { 74 output.append(top); 75 } 76 } 77 } 78 79 /** 80 * 對加減乘除操作符進行處理 81 * @param operator 82 * @param type 83 */ 84 private void manageOperator(String operator, int type) { 85 // 當棧不為空時,需要判斷 86 while (!stack.isEmpty()) { 87 // 先取出棧頂元素 88 String top = (String) stack.pop(); 89 // 此時,有兩種情況: 90 // 1. 取出的是 "(" 左括號,說明此時正在進行更高優先級的計算(也就是括號內的計算),所以需要把出棧 "(" 重新入棧,並break掉循環。最後將傳過來的的操作符入棧。 91 // 2. 取出的是其他操作符(+-*/),需要進行優先級判斷。 92 // 2.1 取出操作符優先級比讀取的(即傳過來的)高,說明應該執行上一個計算塊,所以要將取出的操作符出棧並打印,break掉循環。最後將傳過來的的操作符入棧。 93 // 2.2 取出操作符優先級比讀取的(即傳過來的)低或者相等,說明應該或可以先執行下一個計算塊,所以要將取出的操作符重新入棧,並break掉循環。最後將傳過來的的操作符入棧。 94 if (top.equals("(")) { 95 stack.push(top); 96 break; 97 } else { 98 // 確定取出來的操作符的類型 99 int topType = 0; 100 if (top.equals("+") || top.equals("-")) { 101 // 類型為加減 102 topType = 1; 103 } else { 104 // 類型為乘除 105 topType = 2; 106 } 107 // 與傳過來的類型比較 108 if (topType > type) { 109 output.append(top); 110 } else { 111 stack.push(top); 112 break; 113 } 114 } 115 } 116 // 將傳過來的操作符入棧 117 stack.push(operator); 118 } 119 }View Code
測試:
1 @Test 2 public void fun1(){ 3 // String input = "A+B-C"; 4 String input = "A*(B+C)-D/(E+F)"; 5 InfixToPostfix2 trans = new InfixToPostfix2(input); 6 String output = trans.doTransform(); 7 System.out.println("----------------------"); 8 System.out.println("後綴表達式為: " + output); 9 }
結果:
FOR A Stack {bottom-->top}: FOR * Stack {bottom-->top}: FOR ( Stack {bottom-->top}: * FOR B Stack {bottom-->top}: * ( FOR + Stack {bottom-->top}: * ( FOR C Stack {bottom-->top}: * ( + FOR ) Stack {bottom-->top}: * ( + FOR - Stack {bottom-->top}: * FOR D Stack {bottom-->top}: - FOR / Stack {bottom-->top}: - FOR ( Stack {bottom-->top}: - / FOR E Stack {bottom-->top}: - / ( FOR + Stack {bottom-->top}: - / ( FOR F Stack {bottom-->top}: - / ( + FOR ) Stack {bottom-->top}: - / ( + WHILE Stack {bottom-->top}: - / WHILE Stack {bottom-->top}: - END Stack {bottom-->top}: ---------------------- 後綴表達式為: ABC+*DEF+/-
三:使用後綴表達式求算術值
需要註意的是:
棧存的是操作數,和上面的相反
1 public class ParsePostfix { 2 3 private Stack stack; 4 private String input; 5 private StringBuilder sb; 6 7 public ParsePostfix(String input) { 8 this.input = input; 9 stack = new Stack(input.length()); 10 sb = new StringBuilder(); 11 } 12 13 public int doParse(){ 14 for (int i = 0; i < input.length(); i++) { 15 char c = input.charAt(i); 16 // 兩種情況: 17 // 1. 傳過來的是一個數字,直接壓入棧 18 // 2. 傳過來的是一個操作符,那就取兩個棧內元素,進行算術處理,並將結果壓入棧 19 if (c >= ‘0‘ && c <= ‘9‘) { 20 // 直接壓入棧,需要轉成int,網上找的,-‘0‘ 即可 21 stack.push(c - ‘0‘); 22 } else { 23 int result = 0; 24 // 取兩個棧內元素,進行算術處理 25 int num1 = (int) stack.pop(); 26 int num2 = (int) stack.pop(); 27 switch (c) { 28 case ‘+‘: 29 result = num2 + num1; 30 break; 31 case ‘-‘: 32 result = num2 - num1; 33 break; 34 case ‘*‘: 35 result = num2 * num1; 36 break; 37 case ‘/‘: 38 result = num2 / num1; 39 break; 40 } 41 stack.push(result); 42 } 43 } 44 int finalResult = (int) stack.pop(); 45 return finalResult; 46 } 47 }View Code
測試:
1 @Test 2 public void fun2(){ 3 String input = "531-+"; 4 ParsePostfix pp = new ParsePostfix(input); 5 int i = pp.doParse(); 6 System.out.println(i); 7 }
結果:
7
四:兩者結合測試
1 public static void main(String[] args) { 2 String input = "5+3-5*8/2"; 3 InfixToPostfix trans = new InfixToPostfix(input); 4 String output = trans.doTransform(); 5 System.out.println("----------------------"); 6 System.out.println("後綴表達式為: " + output); 7 System.out.println("----------------------"); 8 ParsePostfix pp = new ParsePostfix(output); 9 int result = pp.doParse(); 10 System.out.println("最終結果為: " + result); 11 }
結果:
FOR 5 Stack {bottom-->top}: FOR + Stack {bottom-->top}: FOR 3 Stack {bottom-->top}: + FOR - Stack {bottom-->top}: + FOR 5 Stack {bottom-->top}: + - FOR * Stack {bottom-->top}: + - FOR 8 Stack {bottom-->top}: + - * FOR / Stack {bottom-->top}: + - * FOR 2 Stack {bottom-->top}: + - * / WHILE Stack {bottom-->top}: + - * / WHILE Stack {bottom-->top}: + - * WHILE Stack {bottom-->top}: + - WHILE Stack {bottom-->top}: + END Stack {bottom-->top}: ---------------------- 後綴表達式為: 53582/*-+ ---------------------- 最終結果為: -12
使用棧實現解析算術表達式