You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

95 lines
2.7 KiB

package mathpuzzle.service;
import static mathpuzzle.service.PrimarySchoolGenerator.isNumeric;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
/**
* 小学数学表达式计算器,用于计算小学级别的数学表达式。
*
* <p>该类使用双栈算法实现中缀表达式的计算,支持加减乘除四则运算和括号。
* 运算符优先级:乘除高于加减,括号具有最高优先级。
*
* @author 杨博文
* @version 1.0
* @since 2025
*/
public class CaculatePrimary {
/** 数字栈,用于存储操作数。 */
private final Stack<Double> numStack = new Stack<>();
/** 操作符栈,用于存储运算符和括号。 */
private final Stack<String> opStack = new Stack<>();
/** 运算符优先级映射表,数字越大优先级越高。 */
private final Map<String, Integer> precedence = new HashMap<>();
/**
* 计算给定的数学表达式。
*
* <p>该方法使用双栈算法计算表达式的值,支持四则运算和括号。
*
* @param expression 表达式元素列表,包含数字、运算符和括号
* @return 表达式的计算结果
*/
public double caculate(List<String> expression) {
precedence.put("+", 1);
precedence.put("-", 1);
precedence.put("*", 2);
precedence.put("/", 2);
for (String opOrNum : expression) {
if (isNumeric(opOrNum)) {
numStack.push(Double.parseDouble(opOrNum));
} else if (opOrNum.equals("(")) {
opStack.push(opOrNum);
} else if (opOrNum.equals(")")) {
while (!opStack.peek().equals("(") && !opStack.isEmpty()) {
doCaculte();
}
opStack.pop();
} else if (precedence.containsKey(opOrNum)) {
while (!opStack.isEmpty() && !opStack.peek().equals("(")
&& precedence.get(opOrNum) <= precedence.get(opStack.peek())) {
doCaculte();
}
opStack.push(opOrNum);
}
}
while (!opStack.isEmpty()) {
doCaculte();
}
return numStack.pop();
}
/**
* 执行一次基本的二元运算操作。
*
* <p>从数字栈中弹出两个操作数,从操作符栈中弹出一个运算符,
* 执行相应的运算,并将结果压入数字栈。
*/
public void doCaculte() {
String op = opStack.pop();
double num2 = numStack.pop();
double num1 = numStack.pop();
switch (op) {
case "+":
numStack.push(num1 + num2);
break;
case "-":
numStack.push(num1 - num2);
break;
case "*":
numStack.push(num1 * num2);
break;
case "/":
numStack.push(num1 / num2);
break;
default:
break;
}
}
}