逆波兰式 RPN简介
运算符写在操作数的后面的表达式,方便计算机读取。
此处,我们通过栈实现中缀转后缀表达式的代码。
例如:(2*(9+6/3-5)+4) 为一个中缀表达式,它转成后缀表达式应该是2963/+5-*4+
如上我们可以注意到,在转换成后缀表达式后,括号将会消失。其余的操作和运算符的优先级有关系
实现思路
- 创建一个栈用来存放运算符(不包括右括号)
- 如果当前运算符的优先级比栈顶元素优先级高——直接将当前运算符放入栈中
- 如果当前运算符的优先级比栈顶元素优先级低——1.将栈中所有优先级比它高的运算符全部弹出并输出。2.直到当前运算符的优先级高于栈顶元素,将该运算符放入栈中
细节问题
运算符除了加减乘除,还有左括号和右括号,需要注意的是,左括号可以入栈,且作为一个特殊的优先级存在(直接在if中做判断),而右括号不需要入栈,只需要当碰到右括号时,将栈中直到左括号(包括左括号)的所有运算符全部弹出并输出.
运算过程
代码实现
#include<iostream>
#include<stack>
using namespace std;
//判断优先级
int priority(char ch){
//空格不做处理
if(ch=='+'||ch=='-'){
return 1;
}
else if(ch=='*'||ch=='/'){
return 2;
}
}
//比较栈顶运算符和当前运算符优先级,返回值大于0说明当前运算符优先级比栈顶的高,小于0反之
int compare(char cur,char top){
return priority(cur)- priority(top);
}
//判断数字或是字母
int isDigitOrLetter(char ch){
if(ch>='0'&&ch<='9'){
return 1;
}
// if(ch>='a'&&ch<='z'||ch>='A'&&ch<='Z'){
// return 1;
// }
else
return 0;
}
int main()
{
stack<char> stack1;
char res[100];
char str[100];
int index=0;
cout<<"Plz Input a String"<<endl;
gets(str);
for (int i = 0; str[i]!='\0' ; ++i) {
//遍历到的是数字或字母,直接放入结果数组
if(isDigitOrLetter(str[i])){
res[index++]=str[i];
}
else{
//栈为空,不需要判断运算符优先级,直接入栈
if(stack1.empty()){
stack1.push(str[i]);
}
//栈不为空,当前运算符优先级高于栈顶运算符且不为右括号,直接入栈
else if(compare(str[i],stack1.top())>0&&str[i]!=')'){
stack1.push(str[i]);
}
//栈不为空,当前运算符优先级小于或等于栈顶运算符
else if(compare(str[i],stack1.top())<=0){
//把所有栈中优先级大于或等于当前运算符的都出栈并入结果数组
//直到碰到栈为空或者运算符优先级发生改变或者栈顶元素为左括号结束
//注意栈不为空条件要首先判断
while(!stack1.empty()&&compare(str[i],stack1.top())<=0&&stack1.top()!='('){
res[index++]=stack1.top();
stack1.pop();
}
stack1.push(str[i]);//将当前运算符入栈
}
//栈不为空,当前运算符为右括号,将匹配到左括号(包括左括号)在内的所有运算符出栈
else if(str[i]==')'){
while(stack1.top()!='('){
res[index++]=stack1.top();
stack1.pop();
}
stack1.pop();//将左括号出栈
}
}
}
//将栈中剩余元素出栈
while(!stack1.empty()){
res[index++]=stack1.top();
stack1.pop();
}
//输出结果序列
for (int j = 0; j < index; ++j) {
cout<<res[j]<<" ";
}
return 0;
}
运行结果
输入含数字的字符串
输入含字母的字符串
至此,中缀转后缀表达式的代码和逻辑均已实现完毕