数据结构:栈 (基础计算器,中缀表达式)

问题描述

给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。

  • 输入:s = “1 + 1”
  • 输出:2
  • 输入:s = " 2-1 + 2 "
  • 输出:3
  • 输入的字符串中只有 + , -, *, /这些除去数字之外的字符串, 且舒服的数字只有1-9。

思路分析

  1. 使用两个栈,一个是数字栈用来存在数字,一个是符号栈用来存放操作符(+,-,*,/)
  2. 从0开始遍历整个输入字符串,
    • 如果当前index获取到的是数字,则push到数字栈中
    • 如果当前index返回的是操作符。
      • 如果操作符栈为空,则直接将操作符push到操作符栈中
      • 如果当前操作符栈不为空,则对比当前操作符和栈顶操作符的计算优先级。
      • 如果栈顶元素的优先级大于等于当前符号。则从数字栈中依次pop出两个元素v1, v2 ;然后从字符栈中pop出一个字符 ,计算出v2、v1 在该运算中的值val。将val压入数字栈顶,将当前的操作符压入操作符栈顶
      • 如果栈顶元素的优先级小于当前的符号,则将当前符号压入符号栈
  3. 遍历完整个字符串后。 每次从符号栈中弹出一个运算符,从数字栈中弹出依次弹出两个值 v1, v2。 v2, v1 按照弹出的计算符运算之后得到v,将v压入数字栈
    直到操作符栈为空,则数字栈栈顶的元素则为最终的值。

代码实现

package stack;

/**
 * 基本计算器 (中缀表达式1)
 * 给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
 * 输入:s = "1 + 1"
 * 输出:2
 * 输入:s = " 2-1 + 2 "
 * 输出:3
 * <p>
 * 输入的字符串中只有 + , -, *, /这些除去数字之外的字符串, 且舒服的数字只有1-9。
 */
public class BasicCalculator1 {

    /**
     * 数字栈,用来存在数字
     */
    private java.util.Stack<Integer> numberStack = new java.util.Stack<>();

    /**
     * 符号栈,用来存放运算符号
     */
    private java.util.Stack<Character> operatorStack = new java.util.Stack<>();


    /**
     * 实现逻辑,使用两个栈,一个是数字栈用来存在数字,一个是符号栈用来存放符号
     * 从0开始遍历整个自负串,如果当前index获取到的是数字,则push到数字栈中
     * 如果当前index返回的符号。
     * 如果符号栈为空,则直接将符号push到符号栈中
     * 如果当前符号栈不为空,则对比当前符号和栈顶符号的计算优先级。
     * 如果栈顶元素的优先级大于等于当前符号。则从数字栈中依次pop出两个元素v1, v2 ;然后从字符栈中pop出一个字符 ,计算出v2、v1 在该运算中的值val。
     * 将val压入数字栈顶,将当前的符号压入栈顶
     * 如果栈顶元素的优先级小于当前的符号,则将当前符号压入符号栈
     * 遍历完整个字符串后。 每次从符号栈中弹出一个运算符,从数字栈中弹出依次弹出两个值 v1, v2。 v2, v1 按照弹出的计算符运算之后得到v,将v压入数字栈
     * 直到符号栈为空,则数字栈栈顶的元素则为最终的值。
     *
     * @param str
     * @return
     */
    public int calculate(String str) {
        if (str == null || str.length() <= 0) {
            return 0;
        }

        for (int i = 0; i < str.length(); i++) {
            char curOperator = str.charAt(i);
            if (isNumber(curOperator)) {
                numberStack.push(Character.getNumericValue(curOperator));
                continue;
            }

            /**
             * 如果栈为空,则直接压入栈
             */
            if (operatorStack.isEmpty()){
                operatorStack.push(curOperator);
                continue;
            }

            char topOperator = operatorStack.peek();
            int topPriority = getPriority(topOperator);
            int curPriority = getPriority(curOperator);

            //如果符号栈栈顶的操作符的优先级高于当前操作符的优先级,则依次将数据栈中pop出两个数字,按照操作符栈顶的元素进行运算,并且将运算结果
            //压入到数据栈中,然后将当前操作符压入到
            if (topPriority >= curPriority){
                Character operator = operatorStack.pop();
                Integer num1 = numberStack.pop();
                Integer num2 = numberStack.pop();
                int res = calculate(num1, num2, operator);
                numberStack.push(res);
                operatorStack.push(curOperator);
                continue;
            }

            //如果当前操作符的优先级高于操作栈顶的操作符的优先级,则将操作符压入操作数栈中
            operatorStack.push(curOperator);
        }

        //遍历完成之后,每次从操作符栈中弹出一个操作符,从数据栈中依次弹出两个数字,进行运算,然后将运算结果压入数据栈中
        while (!operatorStack.isEmpty()){
            Character operator = operatorStack.pop();
            Integer num1 = numberStack.pop();
            Integer num2 = numberStack.pop();
            int res = calculate(num1, num2, operator);
            numberStack.push(res);
        }
        return numberStack.pop();
    }

    private int calculate(int num1, int num2, char operation){
        switch (operation){
            case '+':
                return num1 + num2;
            case '-':
                return num2 - num1;
            case '*':
                return num1 * num2;
            case '/':
                return num2 / num1;
            default:
                System.out.println("错误的输入");
        }

        throw new RuntimeException("错误的输入");
    }

    /**
     * 判断是否是数字
     *
     * @param cur
     * @return
     */
    private boolean isNumber(char cur) {
        return Character.isDigit(cur);
    }

    /***
     * 获取操作符的优先级, 数字越大优先级越高
     * @param ch
     * @return
     */
    private int getPriority(char ch){
        if (ch == '+' || ch == '-'){
            return 1;
        }

        if (ch == '*' || ch == '/'){
            return 2;
        }

        return -1;
    }

    public static void main(String[] args) {
        System.out.println();
        BasicCalculator1 calculator = new BasicCalculator1();
        int res = calculator.calculate("2+3*5+4/4-6");
        System.out.println(res);
    }

}

题目升级

给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。

  • 输入:s = “1 + 1”
  • 输出:2
  • 输入:s = " 2-1 + 2 "
  • 输出:3
  • 输入的字符串中只有 + , -, *, /这些除去数字之外的字符串, 输入的数字不在只限制1-9,可以是任意数字

思路分析

  • 实现逻辑,使用两个栈,一个是数字栈用来存在数字,一个是操作符栈用来存放操作符
    • 从0开始遍历整个字符串串
    • 如果当前index获取到的是数字,使用一个临时变脸temp将数字存储起来,temp的初始值为0, 每次遇到数字后 temp = temp * 10 + curNum;
    • 如果当前index返回的操作符。
    •  首先 将temp的数值压入数字栈中,然后再考虑操作符。
      
    •  如果操作符栈为空,则直接将操作符push到操作符栈中
      
    •  如果当前操作符栈不为空,则对比当前操作符和栈顶操作符的计算优先级。
      
    •  如果栈顶元素的优先级大于等于当前操作符。则从数字栈中依次pop出两个元素v1, v2 ;然后从字符栈中pop出一个字符 ,计算出v2、v1 在该运算中的值val。将val压入数字栈顶,将当前的操作符压入栈顶
      
    •  如果栈顶元素的优先级小于当前的操作符,则将当前操作符压入操作符栈
      
    • 遍历完整个字符串后。将temp压入到数字栈中 每次从操作符栈中弹出一个运算符,从数字栈中弹出依次弹出两个值 v1, v2。 v2, v1 按照弹出的计算符运算之后得到v,将v压入数字栈
    • 直到操作符栈为空,则数字栈栈顶的元素则为最终的值。

代码实现

package stack;

/**
 * 基本计算器 (中缀表达式1)
 * 给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
 * 输入:s = "1 + 1"
 * 输出:2
 * 输入:s = " 2-1 + 2 "
 * 输出:3
 * <p>
 * 输入的字符串中只有 + , -, *, /这些除去数字之外的字符串,输入的数字不再仅限制为1-9
 */
public class BasicCalculator2 {

    /**
     * 数字栈,用来存在数字
     */
    private java.util.Stack<Integer> numberStack = new java.util.Stack<>();

    /**
     * 操作符栈,用来存放运算操作符
     */
    private java.util.Stack<Character> operatorStack = new java.util.Stack<>();


    /**
     * 实现逻辑,使用两个栈,一个是数字栈用来存在数字,一个是操作符栈用来存放操作符
     * 从0开始遍历整个字符串串
     * 如果当前index获取到的是数字,使用一个临时变脸temp将数字存储起来,temp的初始值为0, 每次遇到数字后 temp = temp * 10 + curNum;
     * 如果当前index返回的操作符。
     *  首先 将temp的数值压入数字栈中,然后再考虑操作符。
     *  如果操作符栈为空,则直接将操作符push到操作符栈中
     *  如果当前操作符栈不为空,则对比当前操作符和栈顶操作符的计算优先级。
     *  如果栈顶元素的优先级大于等于当前操作符。则从数字栈中依次pop出两个元素v1, v2 ;然后从字符栈中pop出一个字符 ,计算出v2、v1 在该运算中的值val。
     *      将val压入数字栈顶,将当前的操作符压入栈顶
     *  如果栈顶元素的优先级小于当前的操作符,则将当前操作符压入操作符栈
     * 遍历完整个字符串后。将temp压入到数字栈中 每次从操作符栈中弹出一个运算符,从数字栈中弹出依次弹出两个值 v1, v2。 v2, v1 按照弹出的计算符运算之后得到v,将v压入数字栈
     * 直到操作符栈为空,则数字栈栈顶的元素则为最终的值。
     *
     * @param str
     * @return
     */
    public int calculate(String str) {
        if (str == null || str.length() <= 0) {
            return 0;
        }

        int temp = 0;
        for (int i = 0; i < str.length(); i++) {
            char curCh = str.charAt(i);

            /**
             * 如果是数字
             */
            if (isNumber(curCh)) {
                temp = temp * 10 + Character.getNumericValue(curCh);
                continue;
            }

            numberStack.push(temp);
            temp = 0;
            /**
             * 如果栈为空,则直接压入栈
             */
            if (operatorStack.isEmpty()){
                operatorStack.push(curCh);
                continue;
            }

            char topOperator = operatorStack.peek();
            int topPriority = getPriority(topOperator);
            int curPriority = getPriority(curCh);

            //如果操作符栈栈顶的操作符的优先级高于当前操作符的优先级,则依次将数据栈中pop出两个数字,按照操作符栈顶的元素进行运算,并且将运算结果
            //压入到数据栈中,然后将当前操作符压入到
            if (topPriority >= curPriority){
                Character operator = operatorStack.pop();
                Integer num1 = numberStack.pop();
                Integer num2 = numberStack.pop();
                int res = calculate(num1, num2, operator);
                numberStack.push(res);
                operatorStack.push(curCh);
                continue;
            }

            //如果当前操作符的优先级高于操作栈顶的操作符的优先级,则将操作符压入操作数栈中
            operatorStack.push(curCh);
        }

        //遍历完成之后,每次从操作符栈中弹出一个操作符,从数据栈中依次弹出两个数字,进行运算,然后将运算结果压入数据栈中
        numberStack.push(temp);
        while (!operatorStack.isEmpty()){
            Character operator = operatorStack.pop();
            Integer num1 = numberStack.pop();
            Integer num2 = numberStack.pop();
            int res = calculate(num1, num2, operator);
            numberStack.push(res);
        }
        return numberStack.pop();
    }

    private int calculate(int num1, int num2, char operation){
        switch (operation){
            case '+':
                return num1 + num2;
            case '-':
                return num2 - num1;
            case '*':
                return num1 * num2;
            case '/':
                return num2 / num1;
            default:
                System.out.println("错误的输入");
        }

        throw new RuntimeException("错误的输入");
    }

    /**
     * 判断是否是数字
     *
     * @param cur
     * @return
     */
    private boolean isNumber(char cur) {
        return Character.isDigit(cur);
    }

    /***
     * 获取操作符的优先级, 数字越大优先级越高
     * @param ch
     * @return
     */
    private int getPriority(char ch){
        if (ch == '+' || ch == '-'){
            return 1;
        }

        if (ch == '*' || ch == '/'){
            return 2;
        }

        return -1;
    }

    public static void main(String[] args) {
        System.out.println();
        BasicCalculator2 calculator = new BasicCalculator2();
        int res = calculator.calculate("12+3*5+4/4-6");
        System.out.println(res);
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值