【算法分析】
简单而言,将中缀表达式转换为后缀表达式的算法需要注意以下两点。
● 操作数始终入操作数栈。
● 操作符入操作符栈时,比较与操作符栈的栈顶元素的优先级,然后选择入操作符栈还是入操作数栈。直至将操作符栈的所有元素入操作数栈后,终止算法。
若设操作符栈的栈顶元素为top,新来的操作符为new,则此步算法可形式化为:
if(new<=top) {pop top to 操作数栈, push new to 操作符栈}
if(new>top) {push new to 操作符栈}
注意:
上文中的top<=new,表示top的优先级小于等于new的优先级。top>new,以此类推。
当遇到左括号“(”时,直接入操作符栈。随后,在其之后出现的非右括号“)”的操作符的优先级都比它高,即可直接入操作符栈。
当遇到右括号“)”时,操作符栈的栈顶元素入操作数栈,然后左括号“(”出栈。
【实例分析】
例如,将中缀表达式 a+b-a*((c+d)/e-f)+g 转换为后缀表达式的过程如下。
事实上,熟悉算法规则之后,手推就可以很快搞定,不用像本例这样整这么长的解题过程。这在时间有限的考研考场特别重要。
之后,在熟悉各操作符的优先级后,再次提醒要特别注意本算法的核心规则:
(1)操作数始终入操作数栈。
(2)操作符入操作符栈时,比较与操作符栈的栈顶元素的优先级,然后选择入操作符栈还是入操作数栈。直至将操作符栈的所有元素入操作数栈后,终止算法。
【考研真题】
【研究生考试2012年第2题】操作符包括+-*/()。将中缀表达式a+b-a*((c+d)/e-f)+g转换为等价的后缀表达式ab+acd+e/f-*-g+时,用栈来存放暂时还不能确定运算次序的操作符,若栈初始时为空,则转换过程中同时保存在栈中的操作符的最大个数是( A )。
A. 5 B. 7 C. 8 D. 11
【研究生考试2014年第2题】假设栈初始为空,将中缀表达式 a/b+(c*d-e*f)/g 转换成等价的后缀表达式的过程中,当扫描到f时,栈中的元素依次是( B )。
A. +(*- B. +(-* C. /+(*-* D. /+-*
【算法代码】
#include <bits/stdc++.h>
using namespace std;
int prio(char op) {
int grade;
if(op=='*' || op=='/') grade=2;
if(op=='+' || op=='-') grade=1;
if(op=='(') grade=0;
return grade;
}
string convert(string &in){
string post;
stack<char> s;
for(int i=0; i<in.size(); i++){
if(in[i]>='0' && in[i]<='9' || in[i]>='a' && in[i]<='z' || in[i]>='A' && in[i]<='Z'){
post+=in[i];
}
else {
if(s.empty()) s.push(in[i]);
else if(in[i]=='(') s.push(in[i]);
else if(in[i]==')'){
while(s.top()!='('){
post+=s.top();
s.pop();
}
s.pop();
}
else {
while(prio(in[i])<=prio(s.top())){
post+=s.top();
s.pop();
if(s.empty()) break;
}
s.push(in[i]);
}
}
}
while(!s.empty()) {
post+=s.top();
s.pop();
}
return post;
}
int main() {
string infix;
cin>>infix;
cout<<convert(infix)<<endl;
return 0;
}
/*
in: a/b+(c*d-e*f)/g
out: ab/cd*ef*-g/+
*/