1. java使用双栈实现一个计算器
基本逻辑
- 双栈分别存储数值(
nums
)和操作符(ops
) - 在实现时需要注意优先级
- 如果当前操作符是 ‘
)
’ 时,需要在遍历过程中把括号内数据做一次计算 - 如果当前遍历的操作符如果是
+ -
,且操作符栈ops的操作符是* /
,则需要优先计算*
和/
的逻辑
- 如果当前操作符是 ‘
- 上边都做完的话,最终都是简单的
+ -
逻辑了,直接计算即可
BigDicemal版本
public class calculatorBigdecimal {
public static BigDecimal calculate(String expression) {
Stack<BigDecimal> nums = new Stack<>();
Stack<Character> ops = new Stack<>();
//记录是否需要把 - 作为 负数存储
boolean isOperatorPre = false;
for (int i = 0; i < expression.length(); i++) {
char c = expression.charAt(i);
if (Character.isDigit(c)) {
int j = i;
while (j < expression.length() && (Character.isDigit(expression.charAt(j)) || '.' == expression.charAt(j))) {
j++;
}
isOperatorPre = false;
nums.push(new BigDecimal(expression.substring(i, j)));
i = j - 1;
} else if (c == '(') {
isOperatorPre = true;
ops.push(c);
} else if (c == ')') {
while (ops.peek() != '(') {
isOperatorPre = false;
nums.push(calculateByOps(ops.pop(), nums.pop(), nums.pop()));
}
ops.pop();
} else if (isOperator(c)) {
if (c == '-' && (isOperatorPre || ops.empty())) {
int j = i + 1;
while (j < expression.length() && (Character.isDigit(expression.charAt(j)) || '.' == expression.charAt(j))) {
j++;
}
nums.push(new BigDecimal(expression.substring(i + 1, j)).negate());
i = j - 1;
isOperatorPre = false;
} else {
while (!ops.empty() && needCalculatePre(c, ops.peek())) {
nums.push(calculateByOps(ops.pop(), nums.pop(), nums.pop()));
}
isOperatorPre = true;
ops.push(c);
}
}
}
while (!ops.empty()) {
nums.push(calculateByOps(ops.pop(), nums.pop(), nums.pop()));
}
return nums.pop();
}
private static boolean isOperator(char c) {
return c == '+' || c == '-' || c == '*' || c == '/';
}
private static boolean needCalculatePre(char op1, char op2) {
if (op2 == '(' || op2 == ')') {
return false;
}
return (op2 == '*' || op2 == '/') && (op1 == '+' || op1 == '-') || (op2 == '+' || op2 == '-') && (op1 == '+' || op1 == '-');
}
private static BigDecimal calculateByOps(char op, BigDecimal b, BigDecimal a) {
switch (op) {
case '+':
return a.add(b);
case '-':
return a.subtract(b);
case '*':
return a.multiply(b).setScale(4, BigDecimal.ROUND_HALF_UP);
case '/':
if (b.compareTo(BigDecimal.ZERO) == 0) {
throw new UnsupportedOperationException("Cannot divide by zero");
}
return a.divide(b, 4, RoundingMode.HALF_UP);
default:
throw new UnsupportedOperationException("Unknown operator " + op);
}
}
把一个表达式传入上面的方法即可完成计算
如: (2*5+5)*2-3 = 27
如果再来点难度,把这个表达式的数字依次替换成其他的数值,并完成计算,该怎么做呢?
- 依次取到原表达式的数据
public static List<Long> findNumbers(String expression) {
List<Long> numberList = new ArrayList<>();
Matcher matcher = Pattern.compile("\\d+").matcher(expression);
while (matcher.find()) {
Long number = Long.parseLong(matcher.group());
numberList.add(number);
}
return numberList;
}
- 根据映射关系获取表达式的数据所对应的真实数据
- 把真实数据按指定位置替换到表达式中,调用上面的方法完成计算
public static String replaceNumbers(String expression, List<Long> nums, Map<Long, BigDecimal> idAmountMap) {
StringBuilder newExpression = new StringBuilder(expression);
for (Long id : nums) {
BigDecimal amount = idAmountMap.get(id);
if (amount == null) {
amount = BigDecimal.ZERO;
}
String numberStr = amount.toString();
// 构建数字的正则表达式,确保匹配的数字是一个独立的单词
String regex = "(?<![\\d.])" + id + "(?![\\d.])";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(newExpression);
// 逐个查找并替换匹配的数字
while (matcher.find()) {
int start = matcher.start();
int end = matcher.end();
newExpression.replace(start, end, numberStr);
// 更新偏移量,避免重复替换同一个数字
matcher.region(start + numberStr.length(), newExpression.length());
}
}
return newExpression.toString();
}
main方法测试:
public static void main(String[] args) {
HashMap<Long, BigDecimal> map = new HashMap<>();
map.put(1l, new BigDecimal("100.7563"));
map.put(2l, new BigDecimal("200.2131"));
map.put(3l, new BigDecimal("300.7908"));
map.put(4l, new BigDecimal("400.2128"));
map.put(10l, new BigDecimal("1000.4338"));
map.put(10000000000l, new BigDecimal("5.0000"));
String expressionaaa = "(10000000000-5+5)*2-3";
List<Long> numbers = findNumbers(expressionaaa);
System.out.println(numbers);
String exP = replaceNumbers(expressionaaa, numbers, map);
System.out.println(exP);
System.out.println();
String expression0 = "(-2+-5+5)*2-3";
List<Long> numbers0 = findNumbers(expression0);
System.out.println(numbers0);
String exP0 = replaceNumbers(expression0, numbers0, map);
System.out.println(exP0);
System.out.println("(2-5+5)*2-3 = " + calculate(exP0));
System.out.println();
String expression1 = "(-2*5+5)*2-3";
List<Long> numbers1 = findNumbers(expression1);
System.out.println(numbers1);
String exP1 = replaceNumbers(expression1, numbers1, map);
System.out.println(exP1);
System.out.println("(2*5+5)*2-3 = " + calculate(exP1));
System.out.println();
String expression2 = "-10+-5*(2-2)";
System.out.println("10+5*(2-2) = " + calculate(expression2));
String expression3 = "10+5/(4-1)"; //除不尽转化为BigDecimal
List<Long> numbers3 = findNumbers(expression3);
System.out.println(numbers3);
String exP3 = replaceNumbers(expression3, numbers3, map);
System.out.println(exP3);
System.out.println("10+5/(4-1) = " + calculate(exP3));
System.out.println();
String expression6 = "2-5+2-3";
System.out.println("2-5+2-3 = " + calculate(expression6));
}
输出结果