前言: 中缀表达式转后缀表达式也是近年来找工作笔试、面试、考研机试,算法竞赛中的考点,所以学会它也是很有必要的,因为这种问题的代码比较模板化,建议读者直接背诵模板,但是不能死记硬背,而是在理解算法思路的基础上背诵此代码。
读者可以先阅读这篇博客 —> 博客传送门
因为表达式求值中的代码中隐含了一步,即将中缀表达式转换成后缀表达式,因此只需要将表达式求值的代码稍作修改即可得到中缀表达式转后缀表达式的代码。
题目
给定一个中缀表达式,其中运算符仅包含 + , − , ∗ , / +,-,*,/ +,−,∗,/(加 减 乘 整除),可能包含括号,请你将中缀表达式转换成后缀表达式。
输入
( 2 ∗ 1 + 6 ) ∗ ( 5 − 3 ) / 4 (2*1+6)*(5-3)/4 (2∗1+6)∗(5−3)/4
输出
2 2 2 1 1 1 ∗ * ∗ 6 6 6 + + + 5 5 5 3 3 3 − - − ∗ * ∗ 4 4 4 / / /
实现思路
- 若碰到操作数,直接输出在后缀表达式中;
- 若碰到左括号,直接将左括号压入操作符栈中;
- 若碰到右括号,弹出操作符栈中的操作符直到碰到左括号为止,弹出操作符将操作符输出在后缀表达式中;
- 若碰到操作符,弹出操作符栈中优先级 大于或者等于 大于或者等于 大于或者等于该操作符的元素(若碰到到左括号或者栈为空应该停止),弹出操作符将操作符输出在后缀表达式中;
- 若扫描完字符串后,运算符栈不为空,弹出操作符输出在后缀表达式中直到栈为空,算法结束;
手动模拟
步骤1
步骤2
步骤3
步骤4
步骤5
步骤6
步骤7
步骤8
步骤9
步骤10
步骤11
步骤12
步骤13
步骤14
步骤15
步骤16
代码(附详细注释)
#include<iostream>
#include<string>
#include<map>
#include<stack>
using namespace std;
//定义操作符栈和操作数栈
stack<char> op;
//弹出操作符,输出操作符
void eval(){
char c = op.top();
op.pop();
cout << c << " ";
}
int main(){
//读入表达式字符串
string s;
cin >> s;
//定义四个操作符的优先级; 加减的优先级比乘除低,这里定义加减是1,乘除是2
map<char, int> mp = {{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};
//从左到右扫描一遍字符串
for(int i = 0; i < s.size(); i++){
//四种情况分别对应该字符是数字,左括号,右括号,操作符
if(isdigit(s[i])){
//operand存储操作数,因为操作数在字符串里面可能有连续几位
int j = i, operand = 0;
//这段代码不要害怕,实际上是将字符串"1234"转换成数字1234的代码
while(j < s.size() && isdigit(s[j])){
operand = operand * 10 + s[j] - '0';
j++;
}
cout << operand << " "; //遇到操作数直接输出在表达式
i = j - 1; //for循环里面会执行i++,所以这里j需要减去1
}else if(s[i] == '('){
op.push(s[i]); //左括号则压栈
}else if(s[i] == ')'){
//右括号则一直匹配,直到碰到左括号位置
while(op.top() != '(') eval();
op.pop();
}else{
//若栈不为空且没有碰到左括号且栈顶元素的优先级大于等于该操作符的优先级
while(op.size() && op.top() != '(' && mp[op.top()] >= mp[s[i]])
eval();
op.push(s[i]); //将操作符压入栈中
}
}
//操作到运算符栈空为止
while(op.size()) eval();
return 0;
}
注意
- 实现中缀表达式转后缀表达式,只需要将表达式求值的代码中有关操作数栈的代码删除,改成遇见操作数直接输出操作数,操作运算符直接输出即可;
- 只要理解了表达式求值的代码,中缀表达式转后缀表达式代码稍作修改,直接背诵
- 其他的注意点请见这篇博客 —>博客传送门