看了一下我的播客, 自從加入培訓班後就沒怎麼更新了, 主要還是覺得代碼水準有所提升, 之前寫的一些非常基礎的代碼已經變的沒有太大價值了.
繼續寫這一類代碼, 用處也不大, 以後可能會上一些品質比較高的代碼. 最起碼對我而言還是有一定難度的.
這裡上一段逆波蘭運算式的代碼.
需求是這樣的: 將String math = "12.8 + (2 - 3.55)*4+10/5.0"這個中綴表達式的字符串轉換為逆波蘭表達式(後綴表達式), 並計算出結果.
轉換后的逆波蘭表達式應該是這樣的: 12.8, 2, 3.55, -, 4, *, +, 10, 5.0, /, +
這個代碼涉及到了集合, 和棧的一些基本操作. 這裏就不詳細記錄了. 主要還是記錄一下大體的思路
思路如下:
1, 定義運算符的優先級, 並將優先級計算方法寫出來.
2, 掃描中綴表達式,順序進行判斷, 在判斷的過程中用棧存儲計算結果, 用一個集合存儲後綴表達式.
3, 計算的邏輯是這樣的: 從左往右掃描, 如果第一個拿到的不是括號或者數字, 抛異常, 掃描第一個數字, 并且掃描後面的並判斷,
如果還是數字, 或者小數點, 拿到后做拼接, 直到掃描到運算符停止, 將拼接的結果入棧; 掃描到第一個符號, 直接入棧,再往下,
遇到左括號也直接入棧, 繼續掃描, 重複上一個邏輯, 直到遇到右括號, 遇到右括號后, 將前面兩個數彈出, 再從符號棧彈出左括號和一個運算符,
計算后得到一個數, 再次入棧.(這裏要將左右括號丟掉). 如果上一個邏輯中有多個數和多個運算符, 計算運算符的優先級, 根據優先級做彈棧和計算,
這樣一直掃描計算, 最終棧裏只剩下一個數字時, 就是計算結果. 縂的來説思路就是判斷是數字還是運算符, 運算符計算優先級,
計算離優先級高的運算符的進棧數字, 重複這個邏輯到全部掃描計算完.
寫代碼需要注意的是: 思路一定要清晰, 且連貫. 使用循環進行判斷時一定要區分清楚每一個判斷邏輯的進, 出, 終止的條件. 一旦判斷邏輯不正確, 代碼必然出錯.
切記, 切記
看過的相關視頻資料的大神或許會説我只是搬磚工, 這一點我沒法反駁, 我也不想分辨什麽, 寫這個博客本來的目的也只是做個筆記, 給自己看看, 順帶復習所學
開心就好, o(* ̄▽ ̄*)ブ
package com.stack; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Stack; import java.util.regex.Pattern; public class ReversePolishMultiCalc { static final String SYMBOL = "\\+|-|\\*|/|\\(|\\)"; static final String LEFT = "("; static final String RIGHT = ")"; static final String ADD = "+"; static final String MINUS = "-"; static final String TIMES = "*"; static final String DIVISION = "/"; static final int LEVEL_01 = 1; static final int LEVEL_02 = 2; static final int LEVEL_HIGH = Integer.MAX_VALUE; static Stackstack = new Stack<>(); static List data = Collections.synchronizedList(new ArrayList ()); /** * 去除所有空白字符 * @param s * @return */ public static String replaceAllBlank(String s) { //去空白 return s.replaceAll("\\s+", ""); } /** * 判斷是否是數字 * @param s * @return */ public static boolean isNumber(String s) { Pattern pattern = Pattern.compile("^[-\\+]?[.\\d]*$"); return pattern.matcher(s).matches(); } /** * 判斷運算符 * @param s * @return */ public static boolean isSymbol(String s) { return s.matches(SYMBOL); } public static int calLevel(String s) { if ("+".equals(s) || "-".equals(s)) { return LEVEL_01; } else if ("*".equals(s) || "/".equals(s)) { return LEVEL_02; } return LEVEL_HIGH; } public static List doMath (String s) throws Exception { if (s == null || "".equals(s.trim())) throw new RuntimeException("表達式不能為空"); if (!isNumber(s.charAt(0)+"")) throw new RuntimeException("數據類型錯誤"); s = replaceAllBlank(s); String each; int start = 0; for (int i = 0; i < s.length(); i++) { if (isSymbol(s.charAt(i) + "")) { each = s.charAt(i) + ""; //判斷1 if (stack.isEmpty() || LEFT.equals(each) || ((calLevel(each) > calLevel(stack.peek())) && calLevel(each) < LEVEL_HIGH)) { stack.push(each); //判斷2 } else if (!stack.isEmpty() && calLevel(each) <= calLevel(stack.peek())) { //棧非空,操作符優先級小於等於棧頂優先級時出棧入集合,直到棧空,或者遇到(,最後操作符入棧 while (!stack.isEmpty() && calLevel(each) <= calLevel(stack.peek())) { if (calLevel(stack.peek()) == LEVEL_HIGH) { break; } data.add(stack.pop()); } stack.push(each); } else if (RIGHT.equals(each)) { //判斷3 while (!stack.isEmpty() && LEVEL_HIGH >= calLevel(stack.peek())) { if (LEVEL_HIGH == calLevel(stack.peek())) { stack.pop(); break; } data.add(stack.pop()); } } start = i; }else if (i == s.length() - 1 || isSymbol(s.charAt(i + 1) + "")) { //!!! each = start == 0 ? s.substring(start, i + 1) : s.substring(start + 1, i + 1); if (isNumber(each)) { data.add(each); continue; } throw new RuntimeException("表達式類型不匹配數字"); } } Collections.reverse(stack); data.addAll(new ArrayList<>(stack)); //測試打印後綴表達式 System.out.println(data); return data; } //算結果 public static Double doCalc(List list) { Double d = 0d; if (list == null || list.isEmpty()) { return null; } if (list.size() == 1) { System.out.println(list); d = Double.valueOf(list.get(0)); return d; } ArrayList list1 = new ArrayList<>(); for (int i = 0; i < list.size(); i++) { list1.add(list.get(i)); if (isSymbol(list.get(i))) { //丟失break會導致運算出錯 Double d1 = doTheMath(list.get(i - 2), list.get(i - 1), list.get(i)); list1.remove(i); list1.remove(i - 1); list1.set(i - 2, d1 + ""); list1.addAll(list.subList(i + 1, list.size())); break; } } doCalc(list1); return d; } public static Double doTheMath(String s1, String s2, String symbol) { // System.out.println(s1 + "++"+s2 ); Double result; switch (symbol) { case ADD: result = Double.valueOf(s1) + Double.valueOf(s2); break; case MINUS: result = Double.valueOf(s1) - Double.valueOf(s2); break; case TIMES: result = Double.valueOf(s1) * Double.valueOf(s2); break; case DIVISION: result = Double.valueOf(s1) / Double.valueOf(s2); break; default : result = null; } return result; } public static void main(String[] args) { String math = "12.8 + (2 - 3.55)*4+10/5.0"; try { doCalc(doMath(math)); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }