C语言如何实现遵循PEMDAS优先级的多运算符算术表达式解析
实现可行性结论
完全不需要依赖任何外部第三方库,仅用C标准库就能实现符合PEMDAS优先级规则、支持括号嵌套的算术表达式求值,你已经掌握了单运算符运算的基础逻辑,实现这个功能的门槛很低。
推荐实现方案:双栈法
这是对入门者最友好、逻辑最直观的实现方式,不需要复杂的算法基础,核心是维护两个独立的栈结构:
- 操作数栈:存储解析过程中提取到的数字,建议用
double类型存储,兼容小数计算同时减少整数溢出问题 - 运算符栈:存储解析到的运算符、左右括号
首先先给不同运算符定义好优先级,严格匹配PEMDAS规则:
- 左括号
(优先级设为0(只有匹配到右括号时才触发括号内的计算) - 乘号
*、除号/优先级设为2 - 加号
+、减号-优先级设为1
之后逐字符遍历从stdin读取到的表达式字符串,按以下规则处理:
- 如果当前字符是数字(要支持小数的话就把小数点也算作数字部分的标识),就连续向后读取直到遇到非数字/非小数点字符,把这段字符串转成数值压入操作数栈
- 如果遇到左括号
(,直接压入运算符栈 - 如果遇到右括号
),循环执行:弹出运算符栈顶的一个运算符,再从操作数栈弹出两个操作数完成对应计算,把计算结果压回操作数栈,直到弹出的运算符是左括号(为止,丢弃这对匹配的括号即可 - 如果遇到加减乘除普通运算符,先做循环判断:只要运算符栈不为空、栈顶元素不是左括号、且栈顶运算符的优先级大于等于当前运算符的优先级,就弹出栈顶运算符和两个操作数计算,结果压回操作数栈;循环结束后把当前运算符压入运算符栈
整个字符串遍历完成后,运算符栈里还会残留未计算的运算符,再循环弹出所有剩余运算符,每次弹出都取两个操作数计算、结果压回栈,直到运算符栈为空,此时操作数栈里剩下的唯一数值就是整个表达式的最终结果。
以你提到的
5+2*3为例,整个流程走下来完全符合优先级要求:
- 解析到数字5压入操作数栈 → 数栈:
[5],符栈:[]- 解析到
+,运算符栈为空直接压入 → 数栈:[5],符栈:[+]- 解析到数字2压入操作数栈 → 数栈:
[5,2],符栈:[+]- 解析到
*,栈顶的+优先级1小于*的优先级2,直接压入*→ 数栈:[5,2],符栈:[+,*]- 解析到数字3压入操作数栈 → 数栈:
[5,2,3],符栈:[+,*]- 字符串遍历完成,开始弹栈计算:先弹出
*,取两个操作数3和2,计算2*3=6压回栈 → 数栈:[5,6],符栈:[+]- 再弹出
+,取两个操作数6和5,计算5+6=11压回栈 → 数栈:[11],符栈为空,最终结果就是11
实现避坑点
- 注意区分作为单目运算符的负号:比如
-3+2、5*-2这类场景里的-不是双目减号,可以给单目负号设更高的优先级,或者遇到表达式开头、运算符、左括号后面跟-的情况,先往操作数栈压一个0,把负号转换成普通的双目减法(比如-3转成0-3),实现逻辑会简单很多 - 栈结构不需要用复杂的链表实现,直接用固定长度的C数组就行,日常输入的表达式长度很少超过100个字符,开256长度的数组完全够用,用一个整型变量记录栈顶下标就能实现所有栈操作
- 基础的错误校验要加上:比如括号不匹配、除以0、运算符连续出现、输入非法字符这类场景,检测到直接返回错误提示即可,避免程序崩溃
如果后续你想拆分逻辑做扩展,也可以用中缀转后缀(逆波兰表达式)的方案,本质计算逻辑和双栈法一致,只是把表达式转换和计算拆成了两个独立步骤,代码结构会更清晰,但入门阶段先把双栈法跑通是效率最高的选择。
内容的提问来源于stack exchange,提问作者wick3dr0se
相关产品推荐
相关产品推荐

