使用堆棧結構進行字符串表達式("7*2-5*3-3+6/3")的計算


問題:

給定字符串String str = "7*2-5*3-3+6/3", 求出字符串里面表達式的結果?

像javascript有自帶的eval()方法,可以直接計算。但java或其它語言,API並沒有提供直接計算的方法(可能是我孤陋寡聞),這時就需要我們自己寫方法實現了。

 

棧:

要實現上述功能,需要用到堆棧的概念,

棧是一種特殊的串行形式的數據結構,它的特殊在於,只能在隊列的一端進行輸入和輸出,因此按照"先入后出"的原理運行。就像一個盒子,先放進的東西在下面,后面放進的東西反而在上面。如上圖,棧可以看成是一個"倒立的數組"。有一個top索引,永遠指向最上面一個節點。當加入一個元素時,top往上移一位。取走一個元素時,top往下移一位。當棧為空時,top指向棧的下方,top=-1.

根據上面的結構,我們可以自定義一個棧,並實現入棧(push)和彈棧(pop)兩個方法:

1.入棧:將數據放入堆棧的頂端,top索引+1.

2.彈棧:將棧頂數據輸出,top索引-1.

 1 /**
 2  * 使用數組模擬棧
 3  * @author SCOTT
 4  *
 5  */
 6 public class MyStack {
 7     
 8     private int top = -1; //指向棧頂的索引
 9     private int maxSize = 100; //棧所能存儲的最大個數
10     private Object[] array = new Object[maxSize];    //數組
11     
12     /**
13      * 加入一個元素
14      * @param val
15      */
16     public void push(Object val){
17         if(top == maxSize - 1){
18             System.out.println("棧滿");
19             return;
20         }
21         array[++top] = val;
22     }
23     
24     /**
25      * 彈出一個元素
26      * @return
27      */
28     public Object pop(){
29         if(top == -1){
30             System.out.println("棧空");
31             return null;
32         }
33         return array[top--];
34     }
35     
36     /**
37      * 遍歷
38      */
39     public void toList(){
40         for(int i=top;i>-1;i--){
41             System.out.println(i+"="+array[i]);
42         }
43     }
44     
45     /**
46      * 判斷棧是否為空
47      * @return
48      */
49     public boolean isEmpty(){
50         if(top == -1)
51             return true;
52         return false;
53     }
54     
55     /**
56      * 獲取棧頂的元素,跟pop()方法的區別在於:pop()方法的top索引會減1,而getTop不會
57      */
58     public Object getTop(){
59         if(top == -1)
60             return null;
61         return array[top];
62     }
63 }

 

對棧有了了解之后,就可以計算:String str = "7*2-5*3-3+6/3".

思路:

1.初始化兩個棧,一個數棧(存放表達式中的數字),一個符號棧(用來存儲表達式中的符號).

2.遍歷字符串str,將字符一個個取出進行判斷,假定用ch存儲取出的字符.

  2.1.如果ch為數字,直接將數字放入數棧(這是一種抽象的說法,如果存在像700這種兩位以上的數字,需要自己拼接,然后再一起入棧,只占一個位置).

  2.2.如果ch為符號.

    2.2.1.如果符號棧為空,就直接將符號放入符號棧.

         2.2.2.如果符號棧不為空, 就判斷當前符號(ch)的運算級別跟符號棧棧頂的符號(放在符號棧最上面的一個運算符)運算級別誰大誰小?

      2.2.2.1 循環判斷,如果當前符號(ch)的優先級<=符號棧棧頂運算符的優先級,則進行計算。計算方式:從數棧中彈出兩個數,和符號棧彈出一個符號,進行計算並得到結果res,將res再放入數棧。直到當前運算符的優先級>符號棧棧頂運算符的優先級為止。

      2.2.2.2 將當前符號(ch)加入符號棧.

3.到此,已經將字符串str遍歷完畢。然后再將數棧和符號棧的數據取出進行計算。計算的方式:先從數棧取出兩個數,再從符號棧彈出符號,計算並得到結果res,然后將res放入數棧。依次循環,直到符號棧為空為止。

4.計算完畢后,在數棧會存在一個唯一的值,這個值就是我們需要的結果。

具體實現:

  1 /**
  2  * 計算字符串表達式
  3  * @author SCOTT
  4  *
  5  */
  6 public class StackApp {
  7 
  8     public static void main(String[] args) {
  9         
 10         String str = "7*2-5*3-3+6/3";
 11         //str的索引,默認指向第一位
 12         int index = 0;
 13         //用於拼接連續數字
 14         String tempStr = "";
 15         //數棧
 16         MyStack numStatck = new MyStack();
 17         //符號棧
 18         MyStack operStatck = new MyStack();
 19         
 20         while(true){
 21             char ch = str.charAt(index);
 22             if(isNum(ch)){
 23                 //先進行拼接,滿足條件,在放入數棧
 24                 tempStr += ch;
 25                 //如果到了字符串末尾,或者下一位是符號,則放入數棧
 26                 if(index == str.length() - 1 || !isNum(str.charAt(index+1))){
 27                     numStatck.push(tempStr);
 28                 }
 29             }else{
 30                 tempStr = "";
 31                 if(operStatck.isEmpty()){
 32                     //如果符號棧為空,則直接將運算符放入符號棧
 33                     operStatck.push(ch);
 34                 }else{
 35                     //循環判斷:如果當前運算符的級別<=棧頂運算符的級別,則計算
 36                     while(!operStatck.isEmpty() && getLevel(ch+"") <= getLevel(operStatck.getTop().toString())){
 37                         int res = calculate(numStatck, operStatck);
 38                         //將res入數棧
 39                         numStatck.push(res);
 40                     }
 41                     //將符號放入符號棧
 42                     operStatck.push(ch);
 43                 }
 44             }
 45             
 46             index++;
 47             //判斷條件,break
 48             if(index == str.length())
 49                 break;
 50         }
 51         
 52         //遍歷完成后,進行計算
 53         while(!operStatck.isEmpty()){
 54             int res = calculate(numStatck, operStatck);
 55             //將運算結果放入數棧
 56             numStatck.push(res);
 57         }
 58         
 59         //最后在數棧肯定會存在唯一的結果
 60         System.out.println(numStatck.pop());//-2
 61         
 62     }
 63     
 64     /**
 65      * 判斷截取位,是否是數字
 66      * @param ch
 67      * @return
 68      */
 69     public static boolean isNum(char ch){
 70         if(ch == '+' || ch == '-' || ch == '*' || ch == '/')
 71             return false;
 72         return true;
 73     }
 74     
 75     /**
 76      * *和/級別為1,+和-級別為0
 77      * @return
 78      */
 79     public static int getLevel(String oper){
 80         if("*".equals(oper) || "/".equals(oper))
 81             return 1;
 82         return 0;
 83     }
 84     
 85     /**
 86      * 計算結果://從數棧中取出兩位,從符號棧中取出一位
 87      * @param numStatck
 88      * @param operStatck
 89      * @return
 90      */
 91     public static int calculate(MyStack numStatck, MyStack operStatck){
 92         int num1 = 0;
 93         if(numStatck.getTop() != null)
 94             num1 = Integer.parseInt(numStatck.pop().toString());
 95         int num2 = 0;
 96         if(numStatck.getTop() != null){
 97             num2 = Integer.parseInt(numStatck.pop().toString());
 98         }
 99         String str = "";
100         if(operStatck.getTop() != null){
101             str = operStatck.pop().toString();
102         }
103         
104         int res = 0;
105         switch (str.charAt(0)) {
106             case '+':
107                 res = num1 + num2;
108                 break;
109             case '-':
110                 res = num2 - num1;//注意順序,棧是先入后出的結構
111                 break;
112             case '*':
113                 res = num1 * num2;
114                 break;
115             case '/':
116                 res = num2 / num1;//注意順序,棧是先入后出的結構
117                 break;
118             default:
119                 throw new RuntimeException("運算符不正確");
120         }
121         
122         return res;
123     }
124 }

上面的步驟,並沒有實現帶有()、[]、{}的復雜運算,還有待后續研究.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM