📜  波兰 - C++ (1)

📅  最后修改于: 2023-12-03 15:11:04.801000             🧑  作者: Mango

波兰表达式与C++

波兰表达式是一种不常见的表达式书写方式,它把操作符写在操作数之前,比如 (1 + 2) 可以写成 + 1 2,这种方式更方便计算机处理,因为操作符总是在固定位置。

在C++中,比较常见的计算表达式的方式是中缀表达式,即将操作符放在两个操作数中间,比如 (1 + 2),但是我们也可以用栈来实现对波兰表达式的计算。

实现

我们可以用一个栈来保存操作数,遇到操作符则弹出栈顶的两个操作数进行计算,再把结果入栈。

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

using namespace std;

// 判断是否为操作符
bool isOperator(const string& s) {
    return s == "+" || s == "-" || s == "*" || s == "/" || s == "^";
}

// 计算表达式
double cal(const string& op, double a, double b) {
    if (op == "+") return a + b;
    if (op == "-") return a - b;
    if (op == "*") return a * b;
    if (op == "/") return a / b;
    if (op == "^") return pow(a, b);
    return 0;
}

// 求解波兰表达式
double evalRPN(const vector<string>& tokens) {
    stack<double> nums;
    for (const auto& token : tokens) {
        if (isOperator(token)) {
            double b = nums.top(); nums.pop();
            double a = nums.top(); nums.pop();
            double res = cal(token, a, b);
            nums.push(res);
        } else {
            double num = atof(token.c_str());
            nums.push(num);
        }
    }
    return nums.top();
}

// 将中缀表达式转换成波兰表达式
vector<string> infixToRPN(const string& infix) {
    vector<string> res;
    stack<string> ops;
    istringstream iss(infix);
    string token;
    while (iss >> token) {
        if (isOperator(token)) {
            // 优先级高的操作符先处理
            while (!ops.empty() && isOperator(ops.top()) && (opPrecedence(token) <= opPrecedence(ops.top()))) {
                res.push_back(ops.top()); ops.pop();
            }
            ops.push(token);
        } else if (token == "(") {
            ops.push(token);
        } else if (token == ")") {
            while (ops.top() != "(") {
                res.push_back(ops.top()); ops.pop();
            }
            ops.pop(); // 弹出左括号
        } else {
            res.push_back(token);
        }
    }
    while (!ops.empty()) {
        res.push_back(ops.top()); ops.pop();
    }
    return res;
}

// 示例代码
int main() {
    string infix = "3 + 4 * 2 / (1 - 5)^2";
    vector<string> rpn = infixToRPN(infix);
    cout << "RPN: ";
    for (const auto& token : rpn) {
        cout << token << " ";
    }
    cout << endl;
    double res = evalRPN(rpn);
    cout << "Result: " << res << endl;
    return 0;
}
拓展

波兰表达式还有一个对称形式叫做逆波兰表达式,即把操作符放在操作数的后面,比如 (1 + 2) 可以写成 1 2 +,计算方式和波兰表达式一样,只是先弹出的是右操作数。

在实际使用中,波兰表达式比中缀表达式更利于计算机处理,逆波兰表达式也常被用于计算器和编译器中。