/**
* 後綴表達式實現計算器
*/
public class SuffixExpressionCalculator {
/**
* 計算方法
*
* @param infixExpr 中綴表達式
* @return 結果
*/
public int calculate(String infixExpr) {
Stack<Integer> stack = new Stack<>();
List<String> suffixExprList = infixToSuffix(infixExpr);
System.out.println("後綴表達式: " + suffixExprList);
for (String str : suffixExprList) {
char ch = str.charAt(0);
if (!isOperator(ch)) {
//stack.push((int) ch); 這裏出問題, 舉個例子: 本來應該是數字類型的5, 現在是char類型的 '5' 轉換成int之後是53,肯定就不對了
stack.push(Integer.parseInt(str));
} else {
int num1 = stack.pop();
int num2 = stack.pop();
stack.push(operate(num1, num2, ch));
}
}
return stack.pop();
}
/**
* 加減乘除四則運算
*
* @param num1 值1
* @param num2 值2
* @param operator 操作符
* @return 結果
*/
private int operate(int num1, int num2, char operator) {
int result = 0;
switch (operator) {
case '+':
result = num1 + num2;
break;
case '-':
result = num2 - num1;
break;
case '*':
result = num1 * num2;
break;
case '/':
result = num2 / num1;
break;
}
return result;
}
/**
* 中綴轉後綴
*
* @param infixExpr 中綴表達式
* @return 後綴表達式
*/
private List<String> infixToSuffix(String infixExpr) {
// Stack<Integer> stackNum = new Stack<>(); 這裏出現問題:如果泛型都是Integer那最終結果輸出的字符char也會轉爲int, 導致無法分辨出數字和符號
// Stack<Integer> stackOpe = new Stack<>();
Stack<String> stackNum = new Stack<>();
Stack<String> stackOpe = new Stack<>();
int len = infixExpr.length();
for (int i = 0; i < len; ) {
char ch = infixExpr.charAt(i);
String chStr = String.valueOf(ch);
// 判斷是否是操作符
if (isOperator(ch)) { // 是操作符
if (stackOpe.empty()) { // 是操作符且棧爲空,則符號直接入棧
stackOpe.push(chStr);
} else { // 如果符號棧不爲空
char top = stackOpe.peek().charAt(0);
// 判斷當前符號與棧頂符號的優先級
if (priority(ch) <= priority(top)) { // 當前符號優先級小於等於棧頂符號
if (top != '(') { // 棧頂符號不是左括號
stackNum.push(stackOpe.pop()); // 此時, 將棧頂符號取出壓入數字棧
}
stackOpe.push(chStr); // 再將當前符號壓入符號棧, 這裏還包含一種情況是如果top=='(',則符號直接入棧
} else { // 當前符號優先級大於棧頂符號
if (ch == ')') { // 當前符號是右括號, 需要依次彈出棧中符號壓入數字棧,直到左括號爲止, 注意: 左括號也需要彈出,但是不入數字棧
while (true) {
String cha = stackOpe.pop();
if (cha.charAt(0) == '(') {
//stackOpe.pop(); 這裏出現問題: 多取了一次
break;
}
stackNum.push(cha);
}
} else { // 當前符號不是右括號, 且當前符號優先級大於棧頂符號, 則當前符號直接入棧
stackOpe.push(chStr);
}
}
}
i++; // 循環 + 1
} else { // 字符是數字
StringBuilder sb = new StringBuilder();
sb.append(ch);
// 數字有可能不是個位數, 有可能是多位數, 所以按照char遍歷就會出問題, 這裏while循環就是處理這種情況
while (true) {
i++; // 循環 + 1
if (i == len) { // 處理多位數在表達式最後的情況, 如果等於了表達式的長度就退出
break;
}
char cha = infixExpr.charAt(i);
if (isOperator(cha)) { // 處理多位數在表達式中間的情況, 如果是操作符就退出
break;
}
sb.append(cha);
}
// 把得到的數字壓入數字棧
stackNum.push(sb.toString());
}
}
while (!stackOpe.isEmpty()) {
stackNum.push(stackOpe.pop());
}
List<String> list = new ArrayList<>();
List<String> listData = new ArrayList<>();
while (!stackNum.isEmpty()) {
list.add(stackNum.pop());
}
// 轉爲逆序(逆波蘭)
for (int i = list.size() - 1; i > -1; i--) {
listData.add(list.get(i));
}
return listData;
}
private boolean isOperator(char ch) {
return ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '(' || ch == ')';
}
private int priority(char ch) {
if (ch == '+' || ch == '-') {
return 0;
}
if (ch == '*' || ch == '/') {
return 1;
}
if (ch == '(' || ch == ')') {
return 2;
}
return -1;
}
public static void main(String[] args) {
SuffixExpressionCalculator sec = new SuffixExpressionCalculator();
System.out.println(sec.calculate("5*(3+4)-6+80"));
}
}
打印結果:
後綴表達式: [5, 3, 4, +, *, 6, -, 80, +]
109
之前的博客中已經把思路寫出來了,這篇博客用代碼來實現一下,也算自己的學習筆記。祝大家週末愉快~~~