1. 程式人生 > 其它 >9.中綴表示式轉成字尾表示式

9.中綴表示式轉成字尾表示式

1.編寫一個類 Operation 可以返回一個運算子 對應的優先順序

private static int ADD = 1;
private static int SUB = 1;
private static int MUL = 2;
private static int DIV = 2;

//寫一個方法,返回對應的優先順序數字
public static int getValue(String operation) {
   int result = 0;
   switch (operation) {
   case "+":
      result = ADD;
      break;
   case "-":
      result = SUB;
      break;
   case "*":
      result = MUL;
      break;
   case "/":
      result = DIV;
      break;
   default:
      System.out.println("不存在該運算子" + operation);
      break;
   }
   return result;
}

2.完成對逆波蘭表示式的運算

/*
 * 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,由此得出最終結果
 */

public static int calculate(List<String> ls) {
   // 建立給棧, 只需要一個棧即可
   Stack<String> stack = new Stack<String>();
   // 遍歷 ls
   for (String item : ls) {
      // 這裡使用正則表示式來取出數
      if (item.matches("\\d+")) { // 匹配的是多位數
         // 入棧
         stack.push(item);
      } else {
         // pop出兩個數,並運算, 再入棧
         int num2 = Integer.parseInt(stack.pop());
         int num1 = Integer.parseInt(stack.pop());
         int res = 0;
         if (item.equals("+")) {
            res = num1 + num2;
         } else if (item.equals("-")) {
            res = num1 - num2;
         } else if (item.equals("*")) {
            res = num1 * num2;
         } else if (item.equals("/")) {
            res = num1 / num2;
         } else {
            throw new RuntimeException("運算子有誤");
         }
         //把res 入棧
         stack.push("" + res);
      }
      
   }
   //最後留在stack中的資料是運算結果
   return Integer.parseInt(stack.pop());
}

3.將一個逆波蘭表示式, 依次將資料和運算子 放入到 ArrayList中

public static List<String> getListString(String suffixExpression) {
   //將 suffixExpression 分割
   String[] split = suffixExpression.split(" ");
   List<String> list = new ArrayList<String>();
   for(String ele: split) {
      list.add(ele);
   }
   return list;
   
}

4.將 中綴表示式轉成對應的List

//  s="1+((2+3)×4)-5";
public static List<String> toInfixExpressionList(String s) {
   //定義一個List,存放中綴表示式 對應的內容
   List<String> ls = new ArrayList<String>();
   int i = 0; //這時是一個指標,用於遍歷 中綴表示式字串
   String str; // 對多位數的拼接
   char c; // 每遍歷到一個字元,就放入到c
   do {
      //如果c是一個非數字,我需要加入到ls
      if((c=s.charAt(i)) < 48 ||  (c=s.charAt(i)) > 57) {
         ls.add("" + c);
         i++; //i需要後移
      } else { //如果是一個數,需要考慮多位數
         str = ""; //先將str 置成"" '0'[48]->'9'[57]
         while(i < s.length() && (c=s.charAt(i)) >= 48 && (c=s.charAt(i)) <= 57) {
            str += c;//拼接
            i++;
         }
         ls.add(str);
      }
   }while(i < s.length());
   return ls;//返回
}

5.將得到的中綴表示式對應的List => 字尾表示式對應的List

public static List<String> parseSuffixExpreesionList(List<String> ls) {
   //定義兩個棧
   Stack<String> s1 = new Stack<String>(); // 符號棧
   //說明:因為s2 這個棧,在整個轉換過程中,沒有pop操作,而且後面我們還需要逆序輸出
   //因此比較麻煩,這裡我們就不用 Stack<String> 直接使用 List<String> s2
   //Stack<String> s2 = new Stack<String>(); // 儲存中間結果的棧s2
   List<String> s2 = new ArrayList<String>(); // 儲存中間結果的Lists2
   
   //遍歷ls
   for(String item: ls) {
      //如果是一個數,加入s2
      if(item.matches("\\d+")) {
         s2.add(item);
      } else if (item.equals("(")) {
         s1.push(item);
      } else if (item.equals(")")) {
         //如果是右括號“)”,則依次彈出s1棧頂的運算子,並壓入s2,直到遇到左括號為止,此時將這一對括號丟棄
         while(!s1.peek().equals("(")) {
            s2.add(s1.pop());
         }
         s1.pop();//!!! 將 ( 彈出 s1棧, 消除小括號
      } else {
         //當item的優先順序小於等於s1棧頂運算子, 將s1棧頂的運算子彈出並加入到s2中,再次轉到(4.1)與s1中新的棧頂運算子相比較
         //問題:我們缺少一個比較優先順序高低的方法
         while(s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item) ) {
            s2.add(s1.pop());
         }
         //還需要將item壓入棧
         s1.push(item);
      }
   }
   
   //將s1中剩餘的運算子依次彈出並加入s2
   while(s1.size() != 0) {
      s2.add(s1.pop());
   }

   return s2; //注意因為是存放到List, 因此按順序輸出就是對應的字尾表示式對應的List
   
}

6.測試

public static void main(String[] args) {
   
   
   //完成將一箇中綴表示式轉成字尾表示式的功能
   //說明
   //1. 1+((2+3)×4)-5 => 轉成  1 2 3 + 4 × + 5 –
   //2. 因為直接對str 進行操作,不方便,因此 先將  "1+((2+3)×4)-5" =》 中綴的表示式對應的List
   //   即 "1+((2+3)×4)-5" => ArrayList [1,+,(,(,2,+,3,),*,4,),-,5]
   //3. 將得到的中綴表示式對應的List => 字尾表示式對應的List
   //   即 ArrayList [1,+,(,(,2,+,3,),*,4,),-,5]  =》 ArrayList [1,2,3,+,4,*,+,5,–]
   
   String expression = "1+((2+3)*4)-5";//注意表示式 
   List<String> infixExpressionList = toInfixExpressionList(expression);
   System.out.println("中綴表示式對應的List=" + infixExpressionList); // ArrayList [1,+,(,(,2,+,3,),*,4,),-,5]
   List<String> suffixExpreesionList = parseSuffixExpreesionList(infixExpressionList);
   System.out.println("字尾表示式對應的List" + suffixExpreesionList); //ArrayList [1,2,3,+,4,*,+,5,–] 
   
   System.out.printf("expression=%d", calculate(suffixExpreesionList)); // ?
   
   
   
   /*
   
   //先定義給逆波蘭表示式
   //(30+4)×5-6  => 30 4 + 5 × 6 - => 164
   // 4 * 5 - 8 + 60 + 8 / 2 => 4 5 * 8 - 60 + 8 2 / + 
   //測試 
   //說明為了方便,逆波蘭表示式 的數字和符號使用空格隔開
   //String suffixExpression = "30 4 + 5 * 6 -";
   String suffixExpression = "4 5 * 8 - 60 + 8 2 / +"; // 76
   //思路
   //1. 先將 "3 4 + 5 × 6 - " => 放到ArrayList中
   //2. 將 ArrayList 傳遞給一個方法,遍歷 ArrayList 配合棧 完成計算
   
   List<String> list = getListString(suffixExpression);
   System.out.println("rpnList=" + list);
   int res = calculate(list);
   System.out.println("計算的結果是=" + res);
   
   */
}