板子:中缀转后缀与后缀求值
★ 级:会手算最重要,代码认得就行。中缀转后缀用的是运算符栈,后缀求值用的是操作数栈。
手算规则(中缀 → 后缀)
从左往右扫描中缀表达式:
| 遇到 | 做法 |
|---|---|
| 操作数 | 直接输出 |
( | 直接入栈 |
) | 依次弹出栈顶并输出,直到弹出 ( 为止(括号本身不输出) |
| 运算符 | 先把栈顶优先级 ( 就停),再把它入栈 |
| 扫描结束 | 栈里剩下的运算符全部弹出输出 |
例:a+b*(c-d)-e/f → abcd-*+ef/-。
另一种手算法(加括号法):先按运算顺序给每一步加上括号,再把每个运算符移到自己那对括号的右括号后面,最后去掉所有括号。适合只要结果、不问栈状态的选择题。
代码
int prio(char op) { // 优先级:* / 为 2,+ - 为 1,'(' 为 0
if (op == '*' || op == '/') return 2;
if (op == '+' || op == '-') return 1;
return 0; // '(' 最低:别的运算符来了都不会把它弹出
}
void toPostfix(char in[], char out[]) { // 中缀转后缀;操作数都是单个字符
char st[MaxSize]; // 运算符栈
int top = -1, k = 0; // k:out 的下一个写入位置
for (int i = 0; in[i] != '\0'; i++) {
char c = in[i];
if (c == '(') st[++top] = c; // 左括号:直接入栈
else if (c == ')') { // 右括号:一直弹到左括号
while (st[top] != '(') out[k++] = st[top--];
top--; // 左括号出栈,但不输出
} else if (c == '+' || c == '-' || c == '*' || c == '/') {
while (top != -1 && prio(st[top]) >= prio(c)) // 用 >=:同级的也要先弹,保证从左往右算
out[k++] = st[top--];
st[++top] = c; // 比它高的弹完了,自己再入栈
} else out[k++] = c; // 操作数:直接输出
}
while (top != -1) out[k++] = st[top--]; // 扫完后,栈里剩下的全部输出
out[k] = '\0';
}
int evalPostfix(char s[]) { // 后缀表达式求值;操作数都是一位数字
int st[MaxSize], top = -1; // 操作数栈
for (int i = 0; s[i] != '\0'; i++) {
char c = s[i];
if (c >= '0' && c <= '9') { // 数字:入栈
st[++top] = c - '0';
continue;
}
int b = st[top--]; // 运算符:先弹出的是右操作数
int a = st[top--]; // 后弹出的是左操作数
if (c == '+') st[++top] = a + b;
else if (c == '-') st[++top] = a - b;
else if (c == '*') st[++top] = a * b;
else st[++top] = a / b;
}
return st[top]; // 最后栈里只剩一个数,就是结果
}复杂度:两个函数都是时间
关键边界
| 位置 | 为什么 |
|---|---|
prio(st[top]) >= prio(c) 用 >= | 同级运算要从左往右算。写成 > 的话,a-b-c 会转成 abc--,意思就变成了 |
'(' 的优先级是 0 | 左括号在栈里时,任何运算符都不会把它弹出,只有右括号能弹出它 |
| 先弹出的是右操作数 | a-b 的后缀是 ab-:b 后入栈、先出栈。写反了减法和除法会算错 |
易错点
- 两个栈别弄混:中缀转后缀,栈里放运算符;后缀求值,栈里放操作数。
- 选择题常问「转换过程中栈里最多同时有几个运算符」,按手算规则一步步模拟,每一步都记下栈的内容。
- 前缀表达式(波兰式)求值是从右往左扫描,先弹出的是左操作数,和后缀正好相反。
链接
- 📕 返回:数据结构代码板子
- ⬅️ 上一篇:括号匹配
- ➡️ 下一篇:KMP 的 next 与 nextval
- 🔗 从表达式树输出中缀:表达式树转中缀表达式