简单四则运算解析器 | 豆包MarsCode AI 刷题

70 阅读3分钟

题目背景与理解

计算器是计算机科学中最基础且富有挑战性的问题之一。这道题目要求我们从零实现一个能够解析和计算简单算术表达式的解析器,不仅考验编程技巧,更是对算法和数据结构理解的深度检验。

题目要求

  1. 支持数字(0-9)
  2. 支持加法+和减法-运算符
  3. 支持括号()
  4. 不使用eval()函数
  5. 整数除法(保留整数结果)
  6. 输入字符串中不包含空格

解题难点

  • 表达式解析
  • 运算符优先级处理
  • 括号嵌套的递归处理
  • 字符串到数值的转换
  • 错误边界情况处理

解题思路

表达式解析策略

我选择使用「双栈法」(操作数栈和运算符栈)来解决这个问题。主要步骤包括:

  1. 词法分析

    • 将输入字符串逐字符扫描
    • 识别数字、运算符和括号
    • 构建token序列
  2. 语法解析

    • 使用调度场算法(Shunting Yard Algorithm)
    • 将中缀表达式转换为后缀表达式
    • 处理运算符优先级
  3. 表达式求值

    • 计算后缀表达式
    • 使用栈进行最终运算

算法核心流程

def calculate(s):
    def parse_num(idx):
        # 解析数字
        num = 0
        while idx < len(s) and s[idx].isdigit():
            num = num * 10 + int(s[idx])
            idx += 1
        return num, idx

    def priority(op):
        # 运算符优先级
        return 1 if op in '+-' else 2 if op in '*/' else 0

    nums, ops = [], []
    i = 0
    while i < len(s):
        if s[i].isdigit():
            # 数字处理
            num, i = parse_num(i)
            nums.append(num)
        elif s[i] in '+-*/':
            # 运算符处理
            while ops and priority(ops[-1]) >= priority(s[i]):
                compute()
            ops.append(s[i])
            i += 1
        elif s[i] == '(':
            # 左括号入栈
            ops.append(s[i])
            i += 1
        elif s[i] == ')':
            # 右括号处理
            while ops and ops[-1] != '(':
                compute()
            ops.pop()  # 弹出左括号
            i += 1

    # 处理剩余运算
    while ops:
        compute()

    return nums[0]

def compute():
    # 执行具体运算
    b = nums.pop()
    a = nums.pop()
    op = ops.pop()
    if op == '+': nums.append(a + b)
    elif op == '-': nums.append(a - b)
    elif op == '*': nums.append(a * b)
    elif op == '/': nums.append(int(a / b))  # 整数除法

解题关键点详解

1. 数字解析

  • 使用parse_num()函数处理多位数字
  • 通过num * 10 + digit构建完整数字
  • 返回解析后的数字和当前索引

2. 运算符优先级

  • 定义priority()函数
  • 加减优先级为1
  • 乘除优先级为2
  • 括号优先级最低

3. 括号处理

  • 遇到左括号直接入运算符栈
  • 遇到右括号触发计算直到左括号
  • 弹出左括号

4. 计算逻辑

  • 使用compute()函数处理运算
  • 从数字栈弹出两个数
  • 根据运算符执行具体计算
  • 结果压回数字栈

算法复杂度分析

  • 时间复杂度:O(n),线性扫描
  • 空间复杂度:O(n),辅助栈存储

知识点总结

1. 编译原理基础

  • 词法分析
  • 语法解析
  • 表达式求值

2. 栈的高级应用

  • 双栈法解析复杂表达式
  • 动态处理运算符优先级

3. 数据结构灵活运用

  • 栈的push/pop操作
  • 临时存储和恢复现场

个人思考

算法的可扩展性

这个解决方案不仅限于基本四则运算。通过调整compute()priority()函数,我们可以:

  • 支持更多运算符
  • 实现更复杂的表达式解析
  • 构建领域特定语言(DSL)解析器

工程实践启示

  1. 将复杂问题拆解为可管理的子问题
  2. 使用清晰、模块化的代码结构
  3. 预先考虑边界情况和异常处理

拓展思考

  • 如何支持浮点数计算?
  • 如何处理更复杂的表达式,如三角函数?
  • 可以引入哪些优化提高性能?

结语

计算器实现看似简单,实则蕴含丰富的计算机科学知识。它不仅是一个编程练习,更是理解编译原理和算法设计的绝佳切入点。

通过这个项目,我不仅学习了具体的技术实现,更重要的是培养了将复杂问题系统化、模块化的思维方式。每一行代码背后都是对计算机科学深层原理的探索与理解。