1. 程式人生 > >使用棧實現解析算術表達式

使用棧實現解析算術表達式

加減乘除 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;
9 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 }
View Code


二:將中綴表達式轉換成後綴表達式

這裏需要處理的操作符有:"+"、"-"、 "*"、 "/"、 "(" 、")"

需要關註的有四點:

(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


使用棧實現解析算術表達式