C语言学习学习笔记20260704-中缀表达式求值(双栈法)

C语言学习学习笔记20260704-中缀表达式求值(双栈法)

1. 题目概述

  • 目标 :计算包含 +-*() 的整数算术表达式的值。
  • 输入 :字符串 s(长度 ≤ \le ≤ 100),可能包含空格。
  • 输出:计算结果(整型)。
  • 难点
    • 需要处理运算符优先级(先乘除后加减)。
    • 需要处理括号改变优先级。
    • 需要解析多位数字(如 "123")。

2. 核心算法:双栈模拟

这是解决此类问题的经典 O ( n ) O(n) O(n) 算法。我们需要维护两个栈:

栈名称 作用 存储内容
nums (操作数栈) 暂存等待计算的数字 int 类型的数值
ops (运算符栈) 暂存等待执行的运算符号 char 类型的 +, -, *, (

算法流程图

  1. 扫描字符:从左向右遍历字符串。
  2. 数字处理 :遇到数字则连续读取,拼接成完整整数压入 nums
  3. 左括号 ( :直接压入 ops,作为优先级的"屏障"。
  4. 右括号 ) :触发计算,不断弹出 ops 中的运算符进行计算,直到遇到匹配的 ( 为止。
  5. 运算符 (+, -, *)
    • 比较当前运算符与 ops 栈顶运算符的优先级
    • 栈顶优先级 高于 当前优先级 ,说明栈顶的运算应该先执行(例如栈顶是 *,当前是 +;或者栈顶是 *,当前也是 *)。此时弹出并计算。
    • 重复上述过程直到栈空或栈顶是 ( 或栈顶优先级更低。
    • 将当前运算符压入 ops
  6. 收尾 :遍历结束后,依次弹出 ops 中剩余运算符计算,nums 栈顶即为最终结果。

3. 代码实现详解

以下是基于 C 语言的完整实现:

c 复制代码
#include <stdio.h>
#include <string.h>
#include <ctype.h>

// 定义栈最大容量,根据题目约束预留空间
#define MAXN 1005 

/**
 * @brief 计算带括号、加减乘的中缀整数表达式
 */
int solve(char* s) {
    int nums[MAXN];    // 操作数栈
    char ops[MAXN];    // 运算符栈
    int top_num = 0;   // 数字栈指针
    int top_op = 0;    // 运算符栈指针
    
    int len = strlen(s);
    int i = 0;         

    while (i < len) {
        char c = s[i];
        
        // 1. 跳过空格
        if (c == ' ') {
            i++;
            continue;
        }
        
        // 2. 解析数字(处理多位数)
        if (isdigit(c)) {
            int num = 0;
            while (i < len && isdigit(s[i])) {
                num = num * 10 + (s[i] - '0');
                i++;
            }
            nums[top_num++] = num;
            continue; // 注意:这里已经移动了 i,不需要再 i++
        }
        
        // 3. 左括号直接入栈
        if (c == '(') {
            ops[top_op++] = c;
        } 
        // 4. 右括号:触发括号内计算
        else if (c == ')') {
            while (top_op > 0 && ops[top_op - 1] != '(') {
                // 执行一次计算逻辑
                char op = ops[--top_op];
                int b = nums[--top_num];
                int a = nums[--top_num];
                int res = (op == '+') ? a + b : ((op == '-') ? a - b : a * b);
                nums[top_num++] = res;
            }
            // 弹出对应的左括号
            if (top_op > 0) top_op--; 
        } 
        // 5. 处理普通运算符
        else {
            // 定义优先级:* 为 2,+ - 为 1
            int curr_pri = (c == '*') ? 2 : 1;
            
            // 当栈非空且栈顶不是左括号时
            while (top_op > 0 && ops[top_op - 1] != '(') {
                char top_c = ops[top_op - 1];
                int top_pri = (top_c == '*') ? 2 : 1;
                
                // 如果栈顶优先级 >= 当前优先级,先算栈顶的
                if (top_pri >= curr_pri) {
                    char op = ops[--top_op];
                    int b = nums[--top_num];
                    int a = nums[--top_num];
                    int res = (op == '+') ? a + b : ((op == '-') ? a - b : a * b);
                    nums[top_num++] = res;
                } else {
                    break; // 栈顶优先级低,停止循环
                }
            }
            // 当前运算符入栈
            ops[top_op++] = c;
        }
        i++; 
    }
    
    // 6. 处理栈中剩余的运算符
    while (top_op > 0) {
        char op = ops[--top_op];
        int b = nums[--top_num];
        int a = nums[--top_num];
        int res = (op == '+') ? a + b : ((op == '-') ? a - b : a * b);
        nums[top_num++] = res;
    }
    
    return nums[0];
}

4. 关键细节与易错点

  1. 多位数解析

    • 不能只读一个字符就认为是数字。必须使用 while(isdigit(...)) 循环读取,并通过 num = num * 10 + ... 拼接。
  2. 运算顺序(减法/除法)

    • 栈是后进先出(LIFO)。
    • 对于表达式 a - b,入栈顺序是先 ab
    • 出栈计算时,先弹出的是 b(右操作数),后弹出的是 a(左操作数)。
    • 代码体现int b = nums[--top_num]; int a = nums[--top_num]; res = a - b;
  3. 优先级判断

    • 只有当 栈顶优先级高于当前优先级 时才弹栈计算。
    • 例如:栈顶是 * (2),当前是 * (2)。因为乘法是从左往右算的,所以先算前面的 *,条件成立。
    • 例如:栈顶是 + (1),当前是 * (2)。因为乘法优先级高,后面的 * 应该先算,所以不弹栈,直接把 * 压进去。
  4. 括号的处理

    • 左括号 ( 在栈内时,它的优先级被视为最低(或者说是一个特殊的边界),任何运算符都可以压在它上面。
    • 只有遇到右括号 ) 时,才会强制清空括号内的所有运算。
相关推荐
星夜夏空991 小时前
C++学习(3) —— C++输入输出流
c++·学习
智者知已应修善业1 小时前
【 LM358AD方波】2024-12-31
驱动开发·经验分享·笔记·硬件架构·硬件工程
什仙1 小时前
电感规格书全部专业术语完整释义(村田原厂标准定义)
笔记·电感器
wuminyu2 小时前
markword在高并发场景下变化剖析
java·linux·c语言·jvm·c++
星夜夏空992 小时前
C++学习(1) ——C与C++
c语言·c++·学习
生活爱好者!2 小时前
AI加持的笔记工具,比备忘录好用,NAS一键部署blinko
人工智能·笔记
24计网1王仔寿2 小时前
Linux 系统运维全栈学习路线|从 Shell 脚本到容器云 OpenStack 完整学习指南
linux·学习·openstack
摇滚侠2 小时前
Apache Skywalking 实战 阅读笔记 第一章
笔记·apache·skywalking
AOwhisky2 小时前
Kubernetes(K8s)学习笔记(第十四期):集群存储与有状态应用(下篇):StatefulSet 有状态应用管理
redis·笔记·mysql·云原生·kubernetes·云计算·k8s