前缀、中缀、后缀表达式多次成为我们的作业题,值得专门开一个专题讲解一下。
一、后缀表达式
后缀表达式的计算是最经典的使用栈的题目,也是最适合计算机进行运算的表达式。
【题目分析】我们观察一下可以发现,我们每遇到一个运算符,就把存放数字的栈的前两个元素拿出来,用这个运算符运算后结果再放回数字的栈中,最终栈只剩下的一个元素就是答案。
#include <iostream>
#include <stack>
#include <cstring>
using namespace std;
stack<long long> s1;
string s;
int main() {
while (true) {
bool cc = false;
getline(cin, s);
while (!s1.empty()) s1.pop();
for (int i = 0; i < s.size() - 1; i++) {
if (s[i] == ' ') continue;
long long tmp = 0;
bool flag = 0;
while (s[i] >= '0' && s[i] <= '9') {
flag = 1;
tmp = (tmp << 3) + (tmp << 1) + s[i] - '0';
i++;
}
if (flag) s1.push(tmp);
else {
long long a = s1.top(); s1.pop();
long long b = s1.top(); s1.pop();
if (s[i] == '+') s1.push(a + b);
else if (s[i] == '-') s1.push(b - a);
else if (s[i] == '*') s1.push(a * b);
else if (s[i] == '/') {
if (a == 0) {
cout << "NaN" << endl;
cc = true;
break;
}
else s1.push(b / a);
}
}
}
if (cc) continue;
cout << s1.top() << endl;
}
return 0;
}
二、中缀表达式
【2022计算概论A期末T8】四则运算表达式的值
【题目分析】中缀表达式对于计算机是较难处理的,这道题有三个难点:
①判断+和-是运算符还是正数、负数的含义
②运算符优先级的判断
③括号的处理
#include <iostream>
#include <stack>
#include <string>
#include <cctype>
#include <sstream>
using namespace std;
// 计算两个整数的操作
int calculate(int num1, char op, int num2) {
switch (op) {
case '+': return num1 + num2;
case '-': return num1 - num2;
case '*': return num1 * num2;
case '/': return num1 / num2;
}
return 0;
}
// 获取操作符的优先级
int getPriority(char op) {
if (op == '*' || op == '/') return 2;
if (op == '+' || op == '-') return 1;
return 0;
}
// 计算表达式的值
int evaluateExpression(const string& expression) {
stack<int> nums;
stack<char> ops;
for (size_t i = 0; i < expression.length(); ++i) {
char ch = expression[i];
if (ch == '+' && (i == 0 || !isdigit(expression[i - 1])) && (expression[i - 1] != ')')) {
int num = 0;
i++;
while (i < expression.length() && isdigit(expression[i])) {
num = num * 10 + (expression[i++] - '0');
}
if (num) nums.push(num);
--i;
}
else if (isdigit(ch) || (ch == '-' && (i == 0 || !isdigit(expression[i - 1])) && (expression[i - 1] != ')'))) {
// 处理数字(包含负号开头的数字情况)
int num = 0;
bool negative = (ch == '-');
if (negative && expression[i + 1] == '(') {
ops.push('*');
nums.push(-1);
continue;
}
if (negative) ++i;
while (i < expression.length() && isdigit(expression[i])) {
num = num * 10 + (expression[i++] - '0');
}
if (negative) num = -num;
nums.push(num);
--i;
}
else if (ch == '(') {
ops.push(ch);
}
else if (ch == ')') {
while (!ops.empty() && ops.top() != '(') {
int num2 = nums.top(); nums.pop();
int num1 = nums.top(); nums.pop();
char op = ops.top(); ops.pop();
nums.push(calculate(num1, op, num2));
}
if (!ops.empty()) ops.pop(); // 弹出 '('
}
else if (ch == '+' || ch == '-' || ch == '*' || ch == '/') {
while (!ops.empty() && getPriority(ops.top()) >= getPriority(ch)) {
int num2 = nums.top(); nums.pop();
int num1 = nums.top(); nums.pop();
char op = ops.top(); ops.pop();
nums.push(calculate(num1, op, num2));
}
ops.push(ch);
}
}
while (!ops.empty()) {
int num2 = nums.top(); nums.pop();
int num1 = nums.top(); nums.pop();
char op = ops.top(); ops.pop();
nums.push(calculate(num1, op, num2));
}
return nums.top();
}
int main() {
string expression;
while (getline(cin, expression)) {
cout << evaluateExpression(expression) << endl;
}
return 0;
}
三、前缀表达式
题目分析:前缀表达式可以通过函数的递归调用实现。
#include <iostream>
#include <stdlib.h>
#include <cstring>
using namespace std;
string s;
int i = 0;
double calc() {
while (s[i] == ' ') i++;
if (s[i] == '+') {
i++;
double a = calc();
double b = calc();
return a + b;
} else if (s[i] == '-') {
i++;
double a = calc();
double b = calc();
return a - b;
} else if (s[i] == '*') {
i++;
double a = calc();
double b = calc();
return a * b;
} else if (s[i] == '/') {
i++;
double a = calc();
double b = calc();
return a / b;
} else {
int start = i;
while ((s[i] >= '0' && s[i] <= '9') || s[i] == '.') i++;
string str = s.substr(start, i - 1);
char temp[str.size()] = {0};
for (int i = 0; i < str.size(); i++) temp[i] = str[i];
return atof(temp);
}
}
int main() {
getline(cin, s);
printf("%f\n", calc());
return 0;
}