shunting-yard算法的核心逻辑是将中缀表达式转换为后缀表达式(逆波兰式),再用栈求值;其关键在于维护一个运算符栈,按优先级和括号规则调度运算符入栈与弹出,数字直接输出,左括号入栈、右括号触发弹栈至匹配左括号,运算符依据优先级决定是否先弹出栈顶再入栈。

Shunting-yard算法的核心逻辑是什么
它不是直接求值,而是把中缀表达式转成后缀(逆波兰)形式,再用栈求值。关键在于用两个栈:一个存操作数(或临时结果),一个存运算符——但实际实现时通常只显式维护一个运算符栈,操作数直接输出或暂存于另一结构中。
优先级和括号是核心难点:+ 和 - 优先级最低,* 和 / 居中,^(右结合)最高;左括号入栈,遇到右括号则持续弹出直到左括号;函数调用(如 sin()需额外标记为“函数起始”。
常见错误现象:2 + 3 * 4 解析成 2 3 + 4 *(错),正确应为 2 3 4 * +;根源常是没严格按优先级比较,或弹栈条件写反(比如该弹不弹、不该弹却弹)。
如何用C++实现带括号和二元运算符的版本
用 std::stack<char></char> 存运算符,std::vector<:string></:string> 存输出(每个 token 是数字、运算符或函数名)。逐字符扫描,但注意:数字要连续读取(如 123 不能拆成三个 '1''2''3'),小数点和负号需单独处理(初版建议先忽略负号,只支持非负整数)。
运算符优先级比较推荐封装成函数:int prec(char op),返回数值越大优先级越高;对右结合运算符(如 ^),弹栈条件要改成 prec(op) (严格小于才弹),而非 ≤。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 遇到数字:提取完整 token,push 到 output
- 遇到
'(':直接 push 到 operator stack - 遇到
')':持续 pop 到 output 直到遇到'(',丢弃左括号 - 遇到运算符 op:while 栈非空且栈顶不是
'('且prec(op) ,就 pop 栈顶到 output;然后 push op
为什么 std::string 处理 token 比 char 更可靠
因为 C++ 中单个 char 无法表示 "sin" 或 "12.34" 这类 token。哪怕只支持整数,也要考虑多位数;若后续扩展函数或变量名,std::string 是唯一合理选择。
容易踩的坑:
- 用
std::istringstream或手写 while 循环读数字时,忘记更新扫描位置索引,导致重复处理或跳过字符 - 把
'-'一律当减号,但"-5"开头的负号应作为一元运算符处理(初版可先禁止前导负号,要求输入为"0-5") - 没清空栈尾:表达式结束后,必须把 operator stack 剩余所有运算符 pop 到 output,否则
"1+2"可能只输出"1 2",漏掉'+'
后缀表达式求值时栈里该存什么类型
如果只支持整数运算,用 std::stack<long long></long> 足够;但一旦涉及浮点数(如 3.14 或除法结果),就必须统一用 double。混合类型会引发隐式转换陷阱,比如 5 / 2 在整数栈里得 2,而用户期望 2.5。
实操建议:
- 解析阶段输出 token 全为
std::string,求值阶段再用std::stod()转数字——这样能自然兼容整数和浮点字面量 - 遇到运算符时,pop 两个操作数,注意顺序:
a op b中,先 pop 的是b,后 pop 的是a(因为栈是 LIFO) - 除零检查必须做,否则
1/0会导致程序崩溃或静默产生 inf
最易被忽略的是结合性与栈序的配合:右结合运算符(如幂)在求值时不能简单交换 a/b 顺序,而应在解析阶段就保证其在后缀序列中位置正确——这完全依赖 Shunting-yard 内部的弹栈条件是否区分了结合性。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










