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.
mathStudyAPP/src/model/ExpressionEvaluator.java

106 lines
3.2 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package model;
import java.util.*;
public class ExpressionEvaluator {
private static final Map<String, Integer> PRECEDENCE = new HashMap<>();
static {
PRECEDENCE.put("+", 1);
PRECEDENCE.put("-", 1);
PRECEDENCE.put("*", 2);
PRECEDENCE.put("/", 2);
PRECEDENCE.put("^", 3);
}
// 判断是否是运算符
private static boolean isOperator(String token) {
return PRECEDENCE.containsKey(token);
}
// 运算符优先级
private static int precedence(String op) {
return PRECEDENCE.get(op);
}
// 将中缀表达式转为逆波兰表达式RPN
private static List<String> toRPN(String expr) {
List<String> output = new ArrayList<>();
Stack<String> stack = new Stack<>();
// 正则拆分 token数字、函数、符号、括号
StringTokenizer tokenizer = new StringTokenizer(expr, "+-*/^() ", true);
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken().trim();
if (token.isEmpty()) continue;
if (token.matches("[0-9.]+")) { // 数字
output.add(token);
} else if (token.matches("[a-zA-Z]+")) { // 函数
stack.push(token);
} else if (isOperator(token)) { // 运算符
while (!stack.isEmpty() && isOperator(stack.peek())
&& precedence(stack.peek()) >= precedence(token)) {
output.add(stack.pop());
}
stack.push(token);
} else if (token.equals("(")) {
stack.push(token);
} else if (token.equals(")")) {
while (!stack.isEmpty() && !stack.peek().equals("(")) {
output.add(stack.pop());
}
if (!stack.isEmpty() && stack.peek().equals("(")) {
stack.pop();
}
// 如果栈顶是函数,弹出函数
if (!stack.isEmpty() && stack.peek().matches("[a-zA-Z]+")) {
output.add(stack.pop());
}
}
}
while (!stack.isEmpty()) {
output.add(stack.pop());
}
return output;
}
// 计算逆波兰表达式
private static double evalRPN(List<String> rpn) {
Stack<Double> stack = new Stack<>();
for (String token : rpn) {
if (token.matches("[0-9.]+")) {
stack.push(Double.parseDouble(token));
} else if (isOperator(token)) {
double b = stack.pop();
double a = stack.pop();
switch (token) {
case "+": stack.push(a + b); break;
case "-": stack.push(a - b); break;
case "*": stack.push(a * b); break;
case "/": stack.push(a / b); break;
case "^": stack.push(Math.pow(a, b)); break;
}
} else { // 函数
double a = stack.pop();
switch (token.toLowerCase()) {
case "sin": stack.push(Math.sin(Math.toRadians(a))); break;
case "cos": stack.push(Math.cos(Math.toRadians(a))); break;
case "tan": stack.push(Math.tan(Math.toRadians(a))); break;
case "sqrt": stack.push(Math.sqrt(a)); break;
default: throw new RuntimeException("未知函数: " + token);
}
}
}
return stack.pop();
}
// 对外接口:传入表达式字符串,返回计算结果
public static double evaluate(String expr) {
List<String> rpn = toRPN(expr);
return evalRPN(rpn);
}
}