实现简单计算器 (逆波兰表达式)

牛客NC137 表达式求值(原题链接)

逆波兰表达式相关博客

将一个大问题分解成一个个小问题来求解,就不会被难题的复杂度给吓倒。

代码实现:

核心函数:

    /**
     * 写一个整数计算器,支持加减乘三种运算和括号
     * 返回表达式的值
     * @param s string字符串 待计算的表达式
     * @return int整型
     */
    public int solve (String s) {
        // write code here
        // 初始化运算符信息
        initOpMap();

        // 去掉字符串里的空格
        s = s.trim();
        itemList = new LinkedList<>();
        stack = new LinkedList<>();
        char[] chars = s.toCharArray();

        // 生成后缀表达式
        toPostfixExpression(chars);

        // 返回根据后缀表达式得到的计算结果
        return computeByPostfixExpression();
    }

整体实现:

/**
 * 简单计算器的实现
 * @author 49367
 * @date 2021/4/12 22:31
 */
public class ComputeExpression {
    // 分隔符枚举类
    private enum Delimiter {
        LEFT_BRACKET("("), RIGHT_BRACKET(")");

        private String type;	// 分隔符的类型
        private Delimiter(String s){
            this.type = s;
        }

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }
    }

    // 运算符枚举类
    private enum Operator {
        ADD("+", 0), SUB("-", 0), MUL("*", 1);

        private String type;    // 运算符的类型
        private int priority;   // 运算符的优先级
        private Operator(String s, int priority){
            this.type = s;
            this.priority = priority;
        }

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }

        public int getPriority() {
            return priority;
        }

        public void setPriority(int priority) {
            this.priority = priority;
        }
    }

    // key为运算符,val为优先级
    private HashMap<String, Integer> opMap;

    /**
     * 初始化运算符及其优先级信息
     */
    private void initOpMap(){
        opMap = new HashMap<>();
        for (Operator op : Operator.values()) {
            opMap.put(op.getType(), op.getPriority());
        }
    }

    // 表达式各项的线性表
    private LinkedList<String> itemList;
    // 操作栈
    private Deque<String> stack;

    /**
     * 写一个整数计算器,支持加减乘三种运算和括号
     * 返回表达式的值
     * @param s string字符串 待计算的表达式
     * @return int整型
     */
    public int solve (String s) {
        // write code here
        // 初始化运算符信息
        initOpMap();

        // 去掉字符串里的空格
        s = s.trim();
        itemList = new LinkedList<>();
        stack = new LinkedList<>();
        char[] chars = s.toCharArray();

        // 生成后缀表达式
        toPostfixExpression(chars);

        // 返回根据后缀表达式得到的计算结果
        return computeByPostfixExpression();
    }


    /**
     * 生成后缀表达式,保存在线性表itemList中
     * @param chars
     */
    private void toPostfixExpression(char[] chars) {
        int i = 0, len = chars.length;

        while (i < len){
            if(!Character.isDigit(chars[i])){
                // chars[i]为非数字字符,可以是运算符,也可以是分隔符(括号)
                itemIsNonDigit(String.valueOf(chars[i++]));
                continue;
            }
            // 如果是数字,先生成数字的字符串,然后直接加入到线性表中
            StringBuilder sb = new StringBuilder();
            while (i < len && Character.isDigit(chars[i]))
                sb.append(chars[i++]);
            itemList.addLast(sb.toString());
        }

        // 将操作栈剩余的item都弹出到itemList中
        while (!stack.isEmpty())
            itemList.addLast(stack.removeLast());
    }

    /**
     * 当item不是数字时,它可以是运算符,也可以是分隔符(括号)
     * @param item
     */
    private void itemIsNonDigit(String item) {
        // 该项是运算符
        if(opMap.containsKey(item))
            itemIsOp(item);
        // 该项是分隔符(即括号)
        else
            itemIsDelimiter(item);
    }

    /**
     * 当item是分隔符(在本题中即括号)时
     * @param item
     */
    private void itemIsDelimiter(String item) {
        // 是左括号 "("
        if(Delimiter.LEFT_BRACKET.getType().equals(item))
            stack.addLast(item);
        // 是右括号 ")"
        else if(Delimiter.RIGHT_BRACKET.getType().equals(item)){
            // 弹出括号之间的所有item并加入到线性表中(不包括括号)
            while (!stack.isEmpty() && !Delimiter.LEFT_BRACKET.getType().equals(stack.peekLast())){
                itemList.addLast(stack.removeLast());
            }
            // 弹出左括号
            stack.removeLast();
        }
    }

    /**
     * 当item是运算符时
     * @param item
     */
    private void itemIsOp(String item) {
        String peek;
        int itemPriority = opMap.get(item);

        // 操作栈顶优先级更高才出栈,加入到线性表中,
        while (!stack.isEmpty() && opMap.containsKey(peek = stack.peekLast())
                && opMap.get(peek) >= itemPriority)
            itemList.addLast(stack.removeLast());

        stack.addLast(item);
    }


    /**
     * 根据itemList所代表的后缀表达式计算结果,前提是必须保证后缀表达式是正确的
     * @return
     */
    private int computeByPostfixExpression() {
        // 操作数栈,存放将要被运算的数字
        Deque<Integer> stack = new LinkedList<>();

        for (String item : itemList) {
            // item是运算符
            if (opMap.containsKey(item)){
                int num2 = stack.removeLast();
                int num1 = stack.removeLast();
                stack.addLast(compute(num1, num2, item));
            } 
            // item是数字,直接加到操作数栈中
            else
                stack.addLast(Integer.parseInt(item));
        }

        return stack.removeLast();
    }

    /**
     * 计算
     * @param num1
     * @param num2
     * @param item  运算符
     * @return
     */
    private int compute(int num1, int num2, String item) {

        if(Operator.ADD.getType().equals(item))
            return num1 + num2;
        if(Operator.SUB.getType().equals(item))
            return num1 - num2;
        if(Operator.MUL.getType().equals(item))
            return num1 * num2;

        return 0;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值