题目

编写程序,利用 std::stack<long long> 对给定的逆波兰表达式(Reverse Polish Notation 后缀表达式,如 ["2", "1", "+", "3", "*"] 等价于 (2 + 1) * 3)进行解析与求值。支持 +, -, *, / 运算,且严格遵循减法与除法的操作数弹出先后顺序(先弹出者为右操作数,后弹出者为左操作数),并防御除零异常。

输入格式:无需外部输入(内置后缀表达式测试串)。

输出格式:输出逆波兰表达式计算出的数值结果。

数据范围与约定:运算过程符合 64 位整型范围,除数不为 0。

思路与算法

1. 逆波兰表达式的免括号特性
后缀表达式将运算符置于操作数之后,无需任何括号即可唯一确定运算先后级,是编译原理语法树计算的标准中间表示。

2. 操作数弹出顺序陷阱
对于非对称运算(减法与除法),从栈中弹出的第一个数是右操作数 b = st.top(),第二个数是左操作数 a = st.top(),计算公式必须为 a - b 与 a / b,切勿写反!

3. 流提取与数字判定
负数可能以 - 开头,因此判定是运算符还是负数时,需检测 token.size() > 1 || std::isdigit(token[0])。

完整程序

#include <iostream>
#include <stack>
#include <vector>
#include <string>
#include <sstream>
#include <stdexcept>

long long evalRPN(const std::vector<std::string>& tokens) {
    std::stack<long long> st;

    for (const std::string& token : tokens) {
        if (token == "+" || token == "-" || token == "*" || token == "/") {
            // 弹出两个操作数
            long long right = st.top(); st.pop();
            long long left = st.top(); st.pop();

            if (token == "+") st.push(left + right);
            else if (token == "-") st.push(left - right);
            else if (token == "*") st.push(left * right);
            else if (token == "/") {
                if (right == 0) throw std::runtime_error("除数为 0 错误");
                st.push(left / right);
            }
        } else {
            // 操作数直接压栈
            st.push(std::stoll(token));
        }
    }

    return st.top();
}

int main() {
    std::string line = "10 6 9 3 + -11 * / * 17 + 5 +";
    std::stringstream ss(line);
    std::vector<std::string> tokens;
    std::string token;
    while (ss >> token) {
        tokens.push_back(token);
    }

    std::cout << "后缀表达式: " << line << "\n";
    long long result = evalRPN(tokens);
    std::cout << "求值结果: " << result << "\n";

    return 0;
}

运行示例

输出:

后缀表达式: 10 6 9 3 + -11 * / * 17 + 5 +
求值结果: 22