四则运算的栈实现重要的一点就是把中缀表达式转换为后缀表达式。转换规则如下:
1. 遇到数字直接输出
2. 左括号直接压栈
3. 右括号则将将栈中在左括号以上的所有运算符弹出
4. 若是运算符,判断是否优先级比栈顶元素小或相等,若是,则将在左括号前或优先级大于或等于待压栈元素的栈中元素出栈。若不是,则正常压栈,正常压栈过程中需判断是否负数
5. 遍历中缀表达式结束后,将栈中还存在的所有元素进行出栈
下面的demo版本不支持负数和小数
package wz.ido.algorithm;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
public class StackCalculator {
private static Map<String, Integer> priorityMap = new HashMap<>();
//设置操作符优先级
static {
priorityMap.put("+", 10);
priorityMap.put("-", 10);
priorityMap.put("*", 20);
priorityMap.put("/", 20);
priorityMap.put("(", 100);
priorityMap.put(")", 100);
}
public static void main(String[] args) {
String express = "(20+3*(4 - 2) + 1)/3";
int result = calculte(express);
System.out.println(result);
}
private static int calculte(String express) {
//后缀表达式序列
List suffixExp = getSuffixExp(express);
System.out.println(express);
System.out.println(suffixExp);
//计算表达式结果
Integer result = getResult(suffixExp);
return result;
}
private static Integer getResult(List suffixExp) {
Stack<Integer> numStack = new Stack<Integer>();
for (Object element : suffixExp) {
if (element instanceof Integer) {
numStack.push((Integer)element);
} else {
Integer secondNum = numStack.pop();
Integer firstNum = numStack.pop();
String operator = (String)element;
Integer temResult = simpleCalculte(operator, firstNum, secondNum);
numStack.push(temResult);
}
}
return numStack.pop();
}
private static Integer simpleCalculte(String operator, Integer firstNum, Integer secondNum) {
Integer result = 0;
switch (operator) {
case "+":
result = firstNum + secondNum;
break;
case "-":
result = firstNum - secondNum;
break;
case "*":
result = firstNum * secondNum;
break;
case "/":
result = firstNum / secondNum;
break;
default:
break;
}
return result;
}
private static List getSuffixExp(String express) {
Stack<String> operatorStack = new Stack<String>();
//后缀表达式序列
List rtn = new ArrayList();
StringBuffer numStr = new StringBuffer();
String temChar;
for (int i = 0; i < express.length(); i++) {
temChar = express.substring(i, i + 1);
//数字 字符时
if (isNum(temChar)) {
numStr.append(temChar);
continue;
}
//空字符时
if (" ".equals(temChar)) {
continue;
}
//操作符时
if (numStr.length() > 0) {
Integer num = Integer.parseInt(numStr.toString());
//中缀转后缀规则:1. 遇到数字直接输出,
rtn.add(num);
//置为空
numStr = new StringBuffer();
}
//中缀转后缀规则:2. 空栈直接将操作符压栈,
if (operatorStack.isEmpty()) {
operatorStack.push(temChar);
}
//中缀转后缀规则:3. 右括号则将将栈中在左括号以上的所有运算符弹出
else if (temChar.equals(")")) {
while (!operatorStack.lastElement().equals("(")) {
rtn.add(operatorStack.pop());
}
operatorStack.pop();
} else {
/**
* 中缀转后缀规则: 4. 左括号直接压栈(优先级实现)
* 5. 若是运算符,判断是否优先级比栈顶元素小或相等,若是,
* 则将在左括号前或优先级大于或等于待压栈元素的栈中元素出栈。
* 若不是,则正常压栈(暂未处理负数)
*
*/
while (!operatorStack.isEmpty()) {
String lastOperator = operatorStack.lastElement();
int lastPriority = priorityMap.get(lastOperator);
int currentPriotity = priorityMap.get(temChar);
if (currentPriotity <= lastPriority && !"(".equals(lastOperator) ) {
rtn.add(operatorStack.pop());
} else {
break;
}
}
operatorStack.push(temChar);
}
}
//处理最后一个字符是数字的情况
if (numStr.length() > 0) {
Integer num = Integer.parseInt(numStr.toString());
rtn.add(num);
}
// 6.遍历中缀表达式结束后,将栈中还存在的所有元素进行出栈
while (!operatorStack.isEmpty()) {
rtn.add(operatorStack.pop());
}
return rtn;
}
private static boolean isNum(String temp) {
return temp.matches("[0-9]");
}
}