逆波兰表达式求值应直接用std::stack实现“见数压栈、见符弹两算一”,避免混入AST构建逻辑;token分割须用std::istringstream自动跳过空白并完整保留符号数字;除法需向零截断,负号属数字一部分而非运算符。

逆波兰表达式(RPN)求值本身不需要语法树;强行在 evalRPN 函数里混入节点创建逻辑,只会让栈操作和指针管理互相干扰,引发空指针解引用、内存泄漏或栈大小误判。
std::stack 是 RPN 求值唯一合理的容器
RPN 的语义就是“见数压栈,见符弹两算一”——它天然匹配栈的 LIFO 行为。用 std::stack 不仅简洁,而且 top()/pop() 时间复杂度稳定为 O(1)。试图先建 AST 再遍历求值,是把中缀解析的思路硬套到后缀上,徒增开销与风险。
常见错误包括:
- 用
std::vector模拟栈但忘了同步维护索引,导致back()访问越界 - 在运算符分支里调用
new TreeNode,却没检查栈是否真有 ≥2 个元素,结果pop_back()后访问空容器 - 把
"-123"当作两个 token 处理:先扫到"-"就当运算符,再扫"123"就当正数,彻底破坏原始操作数语义
token 分割必须保留完整数字字符串
所有后续逻辑(无论是求值还是建树)都依赖正确切分。逐字符扫描或简单按空格 split() 都不可靠——" 4\t-13 5 + / " 这类输入会出问题。
立即学习“C++免费学习笔记(深入)”;
推荐做法是用 std::istringstream:
std::istringstream iss(expr);
std::string token;
while (iss >> token) {
if (token == "+" || token == "-" || token == "*" || token == "/") {
// 处理运算符
} else {
long long val = std::stoll(token); // 支持 "-123"、"+42"
// 压栈或建叶节点
}
}
关键点:
-
iss >>自动跳过任意空白符(空格、制表符、换行),无需手动 trim - 只对
"+"、"-"、"*"、"/"四个字面量做运算符判定,其余一律走std::stoll - 用
std::stoll而非std::stoi,避免中间结果溢出(如"1000000000 1000000000 +")
构建语法树必须另起独立函数
如果需求明确要求“返回 RPN 对应的语法树”,那就该拆成两个职责分明的函数:tokenize(const std::string&) 和 buildTreeFromRPN(const std::vector<:string>&)</:string>。不要污染求值函数。
建树逻辑本身很简单,但顺序极易搞反:
- 遇到数字 token:新建
TreeNode叶节点,left/right设为nullptr,压入节点栈 - 遇到运算符 token:弹出栈顶两个节点,**先弹的是右子节点,后弹的是左子节点**(这是 RPN 结构决定的)
- 新建运算符节点,设
left = left_node、right = right_node,再压栈 - 遍历结束时,栈中必须只剩一个节点;否则抛
std::runtime_error("invalid RPN: stack size != 1")
注意:此时节点栈必须用 std::stack<treenode></treenode> 或 std::stack<:shared_ptr>></:shared_ptr>,不能混用原始 int 栈。
除法和负号是两个最常被忽略的坑
RPN 题目(如 LeetCode 150)要求整数除法向零截断,而 C++ 默认是向负无穷截断。直接写 a / b 在 a = -3, b = 2 时得到 -2,但正确答案是 -1。
安全写法是:
long long div(long long a, long long b) {
if (b == 0) throw std::runtime_error("division by zero");
bool neg = (a < 0) ^ (b < 0);
long long res = std::abs(a) / std::abs(b);
return neg ? -res : res;
}
至于负号:RPN 中没有一元负号概念,"-123" 就是一个完整的操作数 token。只有在中缀转后缀阶段才需区分减法与负号——那属于 parser 层,不是 RPN 求值层该管的事。
真正容易被忽略的,是 std::abs(INT_MIN) 溢出问题。所以 div 函数里必须用 long long 接收参数,不能在 int 上做 abs。


















