要在 C 或 C++ 中实现一个支持加减乘除和指数运算的表达式求值器,可以使用“逆波兰表达式”(也称为后缀表达式)的方法。
具体步骤包括:
- 将中缀表达式转换为后缀表达式:使用“调度场算法”(Shunting Yard Algorithm)处理运算符的优先级和结合性,将中缀表达式转换为后缀表达式。
- 计算后缀表达式的值:使用一个栈来计算后缀表达式的值。
C++ 代码示例:
#include <iostream>
#include <stack>
#include <vector>
#include <cctype>
#include <string>
#include <cmath>
using namespace std;
// 定义运算符的优先级和结合性
int precedence(char op) {
if (op == '^') return 3;
else if (op == '' || op == '/') return 2;
else if (op == '+' || op == '-') return 1;
else return 0;
}
bool isLeftAssociative(char op) {
if (op == '^') return false; // 右结合
else return true; // 左结合
}
// 快速幂函数,计算 a 的 b 次方
long long power(long long a, long long b) {
long long result = 1;
while (b > 0) {
if (b % 2) result = a;
a = a;
b /= 2;
}
return result;
}
int main() {
string input;
getline(cin, input);
vector<string> outputQueue; // 后缀表达式队列
stack<char> operatorStack; // 运算符栈
// 词法分析和中缀转后缀
for (size_t i = 0; i < input.length(); ++i) {
char token = input[i];
// 跳过空格
if (isspace(token)) continue;
if (isdigit(token)) {
// 解析多位整数
string number;
while (i < input.length() && isdigit(input[i])) {
number += input[i];
++i;
}
--i; // 回退一位
outputQueue.push_back(number);
} else if (token == '(') {
operatorStack.push(token);
} else if (token == ')') {
// 将运算符弹出到遇到左括号
while (!operatorStack.empty() && operatorStack.top() != '(') {
outputQueue.push_back(string(1, operatorStack.top()));
operatorStack.pop();
}
if (!operatorStack.empty() && operatorStack.top() == '(') {
operatorStack.pop(); // 弹出左括号
}
} else if (token == '+' || token == '-' || token == '' || token == '/' || token == '^') {
// 处理运算符
while (!operatorStack.empty()) {
char topOp = operatorStack.top();
if ((precedence(topOp) > precedence(token)) ||
(precedence(topOp) == precedence(token) && isLeftAssociative(token))) {
if (topOp == '(') break;
outputQueue.push_back(string(1, topOp));
operatorStack.pop();
} else {
break;
}
}
operatorStack.push(token);
}
}
// 将剩余的运算符弹出
while (!operatorStack.empty()) {
outputQueue.push_back(string(1, operatorStack.top()));
operatorStack.pop();
}
// 计算后缀表达式的值
stack<long long> evalStack;
for (const auto& token : outputQueue) {
if (isdigit(token[0])) {
evalStack.push(stoll(token));
} else {
// 弹出操作数
long long b = evalStack.top(); evalStack.pop();
long long a = evalStack.top(); evalStack.pop();
long long result = 0;
switch (token[0]) {
case '+': result = a + b; break;
case '-': result = a - b; break;
case '': result = a b; break;
case '/': result = a / b; break; // 整数除法
case '^': result = power(a, b); break;
}
evalStack.push(result);
}
}
// 输出结果
cout << evalStack.top() << endl;
return 0;
}
代码说明:
- - 解析输入:使用 `getline` 获取整行输入,处理多位数字和运算符。
- - 中缀转后缀:实现了调度场算法,考虑了运算符的优先级和结合性,以及括号。
- - 计算后缀表达式:使用栈来计算后缀表达式,支持加减乘除和指数运算。
- - 整数除法:在计算除法时,使用整数除法 `a / b`。
- - 指数运算:实现了一个快速幂函数 `power`,用于计算整数的指数。
注意事项:
- 输入长度限制:代码中没有特别处理输入长度,因为题目保证了输入长度不超过 30。
- 数值范围:使用 `long long` 类型来防止溢出,确保支持到 `2^31 - 1`。
测试示例:
输入:
输出:
|