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
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;
|
|
}
|
|
}
|
|
} |