题解:AcWing 3302 表达式求值
【题目来源】
AcWing:3302 表达式求值 - AcWing题库
【题目描述】
给定一个表达式,其中运算符仅包含 +,-,*,/(加 减 乘 整除),可能包含括号,请你求出表达式的最终值。
【输入】
共一行,为给定表达式。
【输出】
共一行,为表达式的结果。
【输入样例】
(2+2)*(1+1)
【输出样例】
8
【核心思想】
-
问题分析:给定一个包含
+、-、*、/运算符和括号的中缀表达式,需要计算其最终值。这是一个双栈表达式求值问题,关键在于正确处理运算符优先级和括号嵌套。 -
算法选择:
- 双栈法(Two Stacks):使用操作数栈
num存储数字,运算符栈op存储运算符和括号 - 运算符优先级:定义优先级映射表
pr = {'+':1, '-':1, '*':2, '/':2},乘除优先级高于加减 - 栈顶计算(eval):遇到高优先级运算时,立即弹出栈顶两个操作数和运算符进行计算
- 双栈法(Two Stacks):使用操作数栈
-
关键步骤:
- 初始化:创建空的操作数栈
num和运算符栈op,定义运算符优先级表 - 遍历表达式(对于每个字符 \(c\)):
- 数字处理:连续读取数字字符,构建完整数字后压入
num栈 - 左括号
(:直接压入op栈 - 右括号
):循环执行eval()直到遇到左括号,然后弹出左括号 - 运算符(
+、-、*、/):- 当
op栈非空、栈顶不是(、且栈顶优先级 \(\geq\) 当前运算符时,执行eval() - 将当前运算符压入
op栈
- 当
- 数字处理:连续读取数字字符,构建完整数字后压入
- 清空运算符栈:遍历结束后,执行剩余的所有
eval()操作 - 输出结果:
num栈顶即为表达式结果
- 初始化:创建空的操作数栈
-
时间/空间复杂度:
- 时间复杂度:\(O(n)\),每个字符处理一次,每个运算符最多入栈出栈一次
- 空间复杂度:\(O(n)\),两个栈的空间,最坏情况下存储所有字符
-
双栈表达式求值的核心思想:
- 延迟计算:低优先级运算符先入栈等待,遇到高优先级或右括号时再计算
- 优先级控制:通过比较栈顶与当前运算符优先级,确保先计算高优先级运算
- 括号处理:左括号作为屏障,右括号触发括号内所有运算的结算
- 栈顶计算函数:统一封装计算逻辑,保证操作数顺序正确(先弹出的是右操作数)
- 适用于中缀表达式求值、编译器语法分析、计算器实现等场景
【解题思路】

【解题思路2】

【算法标签】
栈
【代码详解】
#include <bits/stdc++.h>
using namespace std;
// 定义两个栈:操作数栈和运算符栈
stack<int> num; // 存储操作数的栈(整数类型)
stack<char> op; // 存储运算符的栈(字符类型)
/**
* 执行栈顶运算:从栈中弹出两个操作数和一个运算符,计算结果后压回栈中
* 注意:先弹出的是第二个操作数,后弹出的是第一个操作数
*/
void eval()
{
// 从操作数栈中弹出第二个操作数(栈顶元素)
auto b = num.top();
num.pop();
// 从操作数栈中弹出第一个操作数
auto a = num.top();
num.pop();
// 从运算符栈中弹出运算符
auto c = op.top();
op.pop();
int x; // 存储运算结果
// 根据运算符执行相应的算术运算
if (c == '+')
{
x = a + b; // 加法运算
}
else if (c == '-')
{
x = a - b; // 减法运算
}
else if (c == '*')
{
x = a * b; // 乘法运算
}
else
{
x = a / b; // 除法运算(整数除法)
}
// 将计算结果压回操作数栈
num.push(x);
}
int main()
{
// 定义运算符优先级映射表
// 优先级数值越大,优先级越高
unordered_map<char, int> pr = {
{'+', 1}, // 加法优先级为1
{'-', 1}, // 减法优先级为1
{'*', 2}, // 乘法优先级为2
{'/', 2} // 除法优先级为2
};
string str; // 存储输入的中缀表达式字符串
cin >> str; // 读取表达式
// 遍历表达式中的每个字符
for (int i = 0; i < str.size(); i++)
{
auto c = str[i]; // 当前字符
// 处理数字字符
if (isdigit(c))
{
int x = 0; // 当前数字的值
int j = i; // 用于扫描连续数字的指针
// 提取连续的数字字符,处理多位数
while (j < str.size() && isdigit(str[j]))
{
// 将字符转换为数字并累加
x = x * 10 + (str[j] - '0');
j++;
}
i = j - 1; // 更新主循环索引,跳过已处理的数字
num.push(x); // 将数字压入操作数栈
}
// 处理左括号:直接压入运算符栈
else if (c == '(')
{
op.push(c);
}
// 处理右括号:计算括号内的所有表达式
else if (c == ')')
{
// 不断计算直到遇到左括号
while (op.top() != '(')
{
eval(); // 执行计算
}
op.pop(); // 弹出左括号
}
// 处理运算符:+ - * /
else
{
// 当栈不为空,且栈顶不是左括号,且栈顶运算符优先级不低于当前运算符时
while (op.size() > 0 && op.top() != '(' && pr[op.top()] >= pr[c])
{
eval(); // 先计算优先级高的运算
}
op.push(c); // 当前运算符压栈
}
}
// 处理运算符栈中剩余的所有运算
while (op.size() > 0)
{
eval();
}
// 输出最终结果(操作数栈中唯一的元素)
cout << num.top() << endl;
return 0;
}
#include <bits/stdc++.h>
using namespace std;
stack<int> num; // 操作数栈,存储数字
stack<char> op; // 操作符栈,存储运算符和括号
string str; // 输入的中缀表达式字符串
// 运算符优先级映射表
map<char, int> pr = {
{'+', 1}, {'-', 1}, // 加减法优先级1
{'*', 2}, {'/', 2}, // 乘除法优先级2
{'^', 3} // 乘方优先级3(最高)
};
int top = 0; // 栈顶指针(实际未使用,因为使用STL stack)
/**
* 执行计算操作:从栈中弹出两个操作数和一个运算符,计算结果压回栈中
*/
void eval()
{
// 弹出第二个操作数(栈顶)
auto b = num.top();
num.pop();
// 弹出第一个操作数
auto a = num.top();
num.pop();
// 弹出运算符
auto c = op.top();
op.pop();
// 根据运算符执行相应的计算
switch (c)
{
case '+':
num.push(a + b); // 加法
break;
case '-':
num.push(a - b); // 减法
break;
case '*':
num.push(a * b); // 乘法
break;
case '/':
num.push(a / b); // 除法
break;
// 注意:代码中定义了^的优先级,但没有实现^的计算
}
}
int main()
{
// 读入中缀表达式
cin >> str;
// 遍历表达式的每个字符
for (int i = 0; i < str.size(); i++)
{
char c = str[i];
if (c >= '0' && c <= '9') // 处理数字
{
int d = 0; // 当前数字的值
int j = i; // 扫描指针
// 提取连续的数字字符,处理多位数
while (j < str.size() && str[j] >= '0' && str[j] <= '9')
{
d = d * 10 + (str[j] - '0'); // 逐位构建数字
j++;
}
// 将数字压入操作数栈
num.push(d);
// 更新索引(跳过已处理的数字字符)
i = j - 1;
}
else if (c == '(') // 左括号:直接入栈
{
op.push(c);
}
else if (c == ')') // 右括号:计算括号内的表达式
{
// 弹出并计算直到遇到左括号
while (op.top() != '(')
{
eval();
}
op.pop(); // 弹出左括号
}
else // 处理运算符:+ - * / ^
{
// 弹出并计算优先级高于或等于当前运算符的运算符
while (op.size() > 0 && op.top() != '(' && pr[op.top()] >= pr[c])
{
eval();
}
op.push(c); // 当前运算符入栈
}
}
// 处理栈中剩余的运算符
while (op.size() > 0)
{
eval();
}
// 输出最终结果(栈中唯一的数字)
cout << num.top() << endl;
return 0;
}
【运行结果】
(2+2)*(1+1)
8
浙公网安备 33010602011771号