1 条题解
-
0
思路与算法
原题称逆波兰,但示例明确运算符在前,应按前缀表达式求值。流式读入记号,运算符压入一个待计算栈帧;读到数值后,若顶帧尚缺左操作数就保存它,否则按左、右的顺序计算并弹帧,把结果继续交给外层。最终得到根值,以固定6位小数输出。
正确性说明
前缀表达式的一个运算符后面恰有左右两个完整子表达式。栈帧表示当前已读入但尚未完成的运算符,has标记是否已有完整左值。一个数或子表达式结束时,向上一帧交付其值:第一份成为左值,第二份与左值计算后完成此帧。按表达式树结构归纳,每次弹出的值正是对应子树的值,最后空栈时得到整个表达式的值。显式栈同时避免深表达式递归溢出。
复杂度
O(t+字符总数)时间、O(h)额外空间,t为记号数,h为同时未完成的运算符层数;包括动态栈初始化与记号数值解析。没有把原题未给的表达式长度改成固定数组容量。
易错点
减除法左右操作数顺序不能交换;-2.5是一个数值,不是独立减号。按题面printf(%f)示意使用double和6位小数。只对有意义的合法算术表达式求值,不能把它当成运算符在后的后缀式。
参考代码(C++11)
#include <bits/stdc++.h> using namespace std; struct Frame { char op; bool has; double left; }; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); vector<Frame> stack; string token; double answer = 0; while (cin >> token) { if (token == "+" || token == "-" || token == "*" || token == "/") { stack.push_back({token[0], false, 0}); continue; } double value = stod(token); while (!stack.empty()) { auto &f = stack.back(); if (!f.has) { f.has = true; f.left = value; break; } double a = f.left; char op = f.op; stack.pop_back(); if (op == '+') value = a + value; else if (op == '-') value = a - value; else if (op == '*') value = a * value; else value = a / value; } if (stack.empty()) answer = value; } cout << fixed << setprecision(6) << answer << "\n"; }
- 1