棧中元素的順序是先進後出,新增的元素總在棧頂,出棧也是先出棧頂,就像彈夾一樣。中綴表示式是我們人計算表示式的方式例如 (2*3-2)*(3+3*3)我們總會括號優先,* / 優先於+ -
使用棧結構計算這個表示式的核心思想就是搞兩個棧,一個存放數字,一個存放符號。
package com.dfsn.cloud.eureka; public class Stack<T> { private Object arr[]; private int top = -1; public Stack(int capacity) { arr = new Object[capacity]; } public void push(T t) { if (isFull()) { throw new RuntimeException("棧已滿,無法新增"); } top++; arr[top] = t; } public T pop() { if (isEmpty()) { throw new RuntimeException("棧為空,沒有元素"); } return (T) arr[top--]; } public T peek() { if (isEmpty()) { throw new RuntimeException("棧為空,沒有元素"); } return (T) arr[top]; } public boolean isEmpty() { return top == -1; } public boolean isFull() { return top == arr.length - 1; } public void show() { for (int i = 0; i <= top; i++) { System.out.println(arr[i]); } } public int size() { return top + 1; } }
package com.dfsn.cloud.eureka; //中綴表示式 public class NifixExpression { public int calculate(String expression) { // 限定最多10個數字 Stack<Integer> numberStack = new Stack<>(10); // 10個數字需要9個字元 Stack<String> symbolStack = new Stack<>(9); for (int i = 0; i < expression.length(); i++) { String current = expression.substring(i, i + 1); // 是數字還是字元 int symbolOrNumber = symbolOrNumber(current); // 是數字 if (symbolOrNumber == 0) { // 如果是數字,則需要判斷後邊的是不是數字,防止多位數 int concatNumber = concatNumber(expression.substring(i)); // 如果是多位數迴圈需要跳過比如 123+2 // 取出123 後下一個要取 + 也就是 i+(123.length),但迴圈本身會自增1所以只能+123.length-1 i += (concatNumber + "").length() - 1; // 入數字棧 numberStack.push(concatNumber); } else {// 是符號 if (symbolStack.isEmpty()) { // 符號棧沒有符號,則入棧 symbolStack.push(current); } else { // 如果是左括號直接入棧 if (current.equals("(")) { symbolStack.push(current); continue; } // 如果是右括號,則需要每次彈出一個符號和兩個數字做運算 // 直到碰到 ( 符號結束,並把 ( 出棧 if (current.equals(")")) { while (true) { if (symbolStack.peek().equals("(")) { symbolStack.pop(); break; } else { int number2 = numberStack.pop(); int number1 = numberStack.pop(); String symbol = symbolStack.pop(); int result = operation(number1, number2, symbol); numberStack.push(result); } } continue; } // 拿出符號棧頂元素和當前符號對比,如果棧頂符號是 ( 則為0,因為它只有遇到)才有意義 String stackTop = symbolStack.peek(); int stackTopPriority = priority(stackTop); int priority = priority(current); // 如果當前符號優先順序大於棧頂符號優先順序,將當前符號新增到棧頂 if (priority > stackTopPriority) { symbolStack.push(current); } else { // 如果當前符號優先順序小於等於棧頂運算子優先順序,則從符號棧頂彈出一個符號 // 從數字棧中彈出兩個數字做運算 注意:棧頂元素在右 // 將結果入數字棧,最後將當前運算子入符號棧 int number2 = numberStack.pop(); int number1 = numberStack.pop(); String symbol = symbolStack.pop(); int result = operation(number1, number2, symbol); numberStack.push(result); symbolStack.push(current); } } } } // 最後兩個佇列可能還有元素,則順序彈出1個符號和兩個數字做運算,並且將結果入數字棧 while (true) { if (symbolStack.isEmpty()) { break; } else { int number2 = numberStack.pop(); int number1 = numberStack.pop(); String symbol = symbolStack.pop(); int result = operation(number1, number2, symbol); numberStack.push(result); } } if (numberStack.size() != 1) { throw new RuntimeException("運算異常"); } else { return numberStack.pop(); } } // 返回1表示是運算子,返回0表示是數字 public int symbolOrNumber(String expression) { if (expression.equals("+") || expression.equals("-") || expression.equals("*") || expression.equals("/") || expression.equals("(") || expression.equals(")")) { return 1; } else if (expression.equals("0") || expression.equals("1") || expression.equals("2") || expression.equals("3") || expression.equals("4") || expression.equals("5") || expression.equals("6") || expression.equals("7") || expression.equals("8") || expression.equals("9")) { return 0; } else { throw new RuntimeException("不是數字也不是運算子"); } } // 返回運算子的等級 * / 高 public int priority(String symbol) { if (symbol.equals("+") || symbol.equals("-")) { return 1; } else if (symbol.equals("*") || symbol.equals("/")) { return 2; } else if (symbol.equals("(")) { return 0; } else { throw new RuntimeException("無法識別運算子"); } } // 獲取字串中第一個連續數字 public int concatNumber(String str) { StringBuilder strNumber = new StringBuilder(); int index = 0; while (true) { if (index > str.length() - 1) { break; } String ch = str.charAt(index) + ""; if (symbolOrNumber(ch) == 0) { strNumber.append(ch); index++; } else { break; } } return Integer.parseInt(strNumber.toString()); } // 做運算 public int operation(int number1, int number2, String symbol) { switch (symbol) { case "+": return number1 + number2; case "-": return number1 - number2; case "*": return number1 * number2; case "/": return number1 / number2; default: throw new RuntimeException("運算子不正確"); } } }