java 栈的应用 - 实现简单的加减乘除的计算器

对于一个简单的加减乘除表达式,怎么去计算其结果呢? 比如 21 + 3 - 5 * 0|不包含 (,)|

这里使用的实现思路是:

  • 准备两个栈,分别用于存放 数字和 操作符。(为了便于后续表达,分别命名为numStack, opStack);
  • 然后就是遍历这个字符串,从前往后的提取里面的数字和符号,进行下一步的操作:
    • 如果提取到的是数字,直接存入numStack;
    • 如果提取到的是符号,就先判断符号栈是否为空:
      • 如果是空的,直接存入到opStack
      • 如果符号栈不是空,就比较符号栈的栈顶元素与当前符号的优先级:
        • 如果当前符号的优先级更高,直接存入符号栈;
        • 如果当前的不是更高,就取出opStack的栈顶符号,以及numStack的两个栈顶元素,进行数据的+-*/的操作,并将计算结果继续存到numStack中;(比如取出的数字先是a1,然后是a2,取出的符号是/,就进行 a2 / a1)并且当前的符号存入到opStack中;
    • (这时候已经完成对输入的字符串的遍历了,不过opStack 目前不是空,还得继续处理。)然后就开始出栈的处理:循环遍历这个符号栈opNums, 取出一个符号的时候,立即取出两个数据,进行数据的+-*/的操作,然后把这个计算结果继续存入到 numStack 中,直到 opStack 里面没有元素了为止;
    • 这时候,opStack#size() == 0, 但是 numStack.size() ==1, 这个 numStack 里面的这个唯一的元素就是计算结果了。

这里给出对应的实现:

考虑到精度问题,这里使用了BigDemical, 然后封装了一下操作符逻辑。然后在提取数字的时候,使用了一点正则表达式;
这里有一个问题需要注意,这里默认运算符是+-*/ 这样的只占一位的字符,比如要用 ** 这表示次方(a^b)的话, 就会出问题。~


import java.math.BigDecimal;
import java.math.RoundingMode;

enum Operator {
    ADD("+", 1),
    REDUCE("-", 1),
    MULTI("*", 2),
    DIVIDE("/", 2);

    private final String operate;
    private final int priority;

    Operator(String operate, int priority) {
        this.operate = operate;
        this.priority = priority;
    }

    public String getOperate() {
        return operate;
    }

    public int getPriority() {
        return priority;
    }

    public static Operator convert(String operate)
            throws IllegalOperationException {
        return switch (operate) {
            case "+" -> ADD;
            case "-" -> REDUCE;
            case "*" -> MULTI;
            case "/" -> DIVIDE;
            default -> throw new IllegalOperationException("illegal operator.");
        };
    }

    public static int calculate(Operator op, int prev, int cur) {
        return switch (op) {
            case ADD -> prev + cur;
            case REDUCE -> prev - cur;
            case MULTI -> prev * cur;
            case DIVIDE -> prev / cur;
        };
    }

    public static BigDecimal calculate(Operator op, BigDecimal prev, BigDecimal cur) {
        return switch (op) {
            case ADD -> prev.add(cur);
            case REDUCE -> prev.subtract(cur);
            case MULTI -> prev.multiply(cur);
            case DIVIDE -> prev.divide(cur, RoundingMode.HALF_UP);
        };
    }

    static class IllegalOperationException extends Exception {

        public IllegalOperationException(String message) {
            super(message);
        }
        
    }
}


import java.math.BigDecimal;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SimpleCalculator {

    private final Stack<BigDecimal> numbers = new Stack<>();
    private final Stack<Operator> operations = new Stack<>();
    private final Pattern numPattern = Pattern.compile("\\d*\\.?\\d*");

  
    public String apply(String input) {

        input = input.replaceAll(" ", "");
        Matcher numMatcher = numPattern.matcher(input);
        while (numMatcher.find()) {
            int start = numMatcher.start();
            int end = numMatcher.end();
            if (start != end) {
                double num = Double.parseDouble(input.substring(start, end));
                numbers.push(BigDecimal.valueOf(num));
                if (end + 1 < input.length()) {
                    String sub = input.substring(end, end + 1);
                    try {
                        Operator action = Operator.convert(sub);
                        if (operations.isEmpty()) {
                            operations.push(action);
                        } else {
                            Operator old = operations.pop();
                            boolean higher = action.getPriority() - old.getPriority() > 0;
                            if (higher) {
                                operations.push(old);
                                operations.push(action);
                            } else {
                                // current operation is lower than old
                                // so do op(prev, current);
                                BigDecimal current = numbers.pop();
                                BigDecimal prev = numbers.pop();
                                BigDecimal result = Operator.calculate(old, prev, current);
                                numbers.push(result);
                                operations.push(action);
                            }
                        }
                    } catch (Operator.IllegalOperationException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        // after loop
        while (!operations.isEmpty()) {
            Operator op = operations.pop();
            BigDecimal cur = numbers.pop();
            BigDecimal prev = numbers.pop();
            BigDecimal result = Operator.calculate(op, prev, cur);
            numbers.push(result);
        }
        System.out.println("=== result---:");
        System.out.printf("numbers: %s\n", numbers);
        System.out.printf("operations : %s\n", operations);
        return numbers.pop().stripTrailingZeros().toPlainString();
    }

    public static void main(String[] args) {
        SimpleCalculator cal = new SimpleCalculator();
        String input = "2+3 -5";
        String result = cal.apply(input);
        System.out.printf("result of [%s]--:[%s]\n", input, result);

        String other = "3.5 * 2 + 5/2";
        String result2 = cal.apply(other);
        System.out.printf("result of [%s]--:[%s]\n", other, result2);
    }
}

实现的部分结束了,可以看一下输出效果:

=== result—:
result of [2+3 -5]–:[0]
=== result—:
result of [3.5 * 2 + 5/2]–:[9.5]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值