简单四则运算解析器| 青训营X豆包MarsCode 技术训练营

49 阅读3分钟

题目分析

小F需要实现一个基本的计算器,该计算器能够解析并计算包含数字(0-9)、运算符(+、-)、乘除(*、/)以及括号(())的字符串表达式。需要注意的是,除法运算应只保留整数结果,且不使用任何内置的eval函数。

代码实现

为了解决这个问题,我们可以使用栈这种数据结构来实现一个解析器。以下是Java语言的实现代码

import java.util.Stack;

public class Main {
    public static int solution(String expression) {
        Stack<Integer> numStack = new Stack<>();
        Stack<Character> opStack = new Stack<>();

        // 遍历表达式
        for (int i = 0; i < expression.length(); i++) {
            char c = expression.charAt(i);

            // 如果是数字,将其转换为整数并压入数字栈
            if (Character.isDigit(c)) {
                int num = 0;
                while (i < expression.length() && Character.isDigit(expression.charAt(i))) {
                    num = num * 10 + (expression.charAt(i) - '0');
                    i++;
                }
                i--;
                numStack.push(num);
            }
            // 如果是左括号,直接压入运算符栈
            else if (c == '(') {
                opStack.push(c);
            }
            // 如果是右括号,进行计算直到遇到左括号
            else if (c == ')') {
                while (opStack.peek() != '(') {
                    char op = opStack.pop();
                    int num2 = numStack.pop();
                    int num1 = numStack.pop();

                    if (op == '+') {
                        numStack.push(num1 + num2);
                    } else if (op == '-') {
                        numStack.push(num1 - num2);
                    } else if (op == '*') {
                        numStack.push(num1 * num2);
                    } else if (op == '/') {
                        numStack.push(num1 / num2);
                    }
                }
                opStack.pop();
            }
            // 如果是运算符,根据优先级进行处理
            else if (isOperator(c)) {
                while (!opStack.isEmpty() && precedence(c) <= precedence(opStack.peek())) {
                    char op = opStack.pop();
                    int num2 = numStack.pop();
                    int num1 = numStack.pop();

                    if (op == '+') {
                        numStack.push(num1 + num2);
                    } else if (op == '-') {
                        numStack.push(num1 - num2);
                    } else if (op == '*') {
                        numStack.push(num1 * num2);
                    } else if (op == '/') {
                        numStack.push(num1 / num2);
                    }
                }
                opStack.push(c);
            }
        }

        // 处理剩余的运算符
        while (!opStack.isEmpty()) {
            char op = opStack.pop();
            int num2 = numStack.pop();
            int num1 = numStack.pop();

            if (op == '+') {
                numStack.push(num1 + num2);
            } else if (op == '-') {
                numStack.push(num1 - num2);
            } else if (op == '*') {
                numStack.push(num1 * num2);
            } else if (op == '/') {
                numStack.push(num1 / num2);
            }
        }

        // 返回数字栈的栈顶元素即为结果
        return numStack.pop();
    }

    // 判断是否为运算符
    public static boolean isOperator(char c) {
        return c == '+' || c == '-' || c == '*' || c == '/';
    }

    // 定义运算符的优先级
    public static int precedence(char op) {
        if (op == '+' || op == '-') {
            return 1;
        } else if (op == '*' || op == '/') {
            return 2;
        }
        return -1;
    }

    public static void main(String[] args) {
        // You can add more test cases here
        System.out.println(solution("1+1") == 2);
        System.out.println(solution("3+4*5/(3+2)") == 7);
        System.out.println(solution("4+2*5-2/1") == 12);
        System.out.println(solution("(1+(4+5+2)-3)+(6+8)") == 23);
    }
}

代码分析

数字解析

代码中首先对字符串中的每个字符进行遍历。如果遇到数字,就将其转换为整数并压入数字栈中。

括号处理

如果遇到左括号,直接压入运算符栈。如果遇到右括号,则开始计算,直到遇到左括号为止。

运算符处理

如果遇到运算符,根据运算符的优先级进行处理。如果当前运算符的优先级高于栈顶运算符的优先级,则将当前运算符压入栈中;否则,从栈中弹出运算符并执行相应的运算,直到遇到优先级较低的运算符或栈为空。

运算符优先级

我们定义了一个precedence函数来确定运算符的优先级。加法和减法的优先级为1,乘法和除法的优先级为2。

最终结果

最后,处理完所有的运算符后,数字栈的栈顶元素即为表达式的值。

难点分析

  • 运算符优先级处理:在处理运算符时,需要正确地根据优先级来决定是否执行运算或将运算符压栈。
  • 括号处理:括号内的运算需要优先处理,这要求我们在遇到右括号时能够正确地处理括号内的运算。
  • 整数除法:在执行除法运算时,需要确保结果为整数,这可能需要对结果进行取整处理。