1,034
社区成员
后缀表达式(也称为逆波兰表达式)是一种数学表达式的表示方式,其中操作符放在其相关操作数的后面。这种表示法消除了括号的需求,并通过操作符的位置直接反映了它们的优先级。
数学表达式中我门常以中缀表达式来表示比如式子:(1+2)*3*(4+5*6)
其对应的后缀表达式为:1 2 + 3 * 4 5 6 * + *
无需括号: 后缀表达式不需要括号来明确运算符的优先级,因为运算符的位置直接反映了它们的优先级。这简化了表达式的书写和理解。
易于计算: 后缀表达式可以直接通过从左到右扫描表达式,并使用栈来存储操作数,从而方便地进行计算。这种计算方式避免了中缀表达式中需要考虑运算符优先级的复杂情况。
减少运算符优先级判断: 在后缀表达式中,运算符的优先级通过其在表达式中的位置隐含地表示,而不需要显式判断。这使得计算和理解表达式更为直观和简单。
减少括号的使用: 由于后缀表达式不需要括号,它在某些情况下可以减少表达式的长度和复杂性。这使得表达式更加紧凑和易读。
没有二义性: 后缀表达式没有二义性,每个运算符都有清晰的操作数,不会存在由于括号导致的歧义。这有助于减少错误的发生。
更适合计算机处理: 后缀表达式对于计算机来说更自然,因为计算机处理的方式更接近于按顺序执行操作。
总体而言,后缀表达式在计算和计算机科学中有一些实际的优点,尤其是在实现计算器、编译器和计算表达式的应用中。然而,在人类编写和理解表达式时,通常更习惯于使用中缀表达式。
首先我们需要一个栈来存储运算符(operatorStack)和一个容器来存储后缀表达式的结果(postfixExpression)
其次遵循以下四条规则:
cin>>origin;//读入表达式
string num="";//储存数字
int flag=0;//统计左括号个数
vector<string>postfixExpression;//后缀表达式
stack<char>operatorStack;//运算符栈
for(auto it:origin){
if(isdigit(it)) num.push_back(it);//如果是数字,则加入数字字符串内
else{//不是数字
if(!num.empty()){//判断数字字符串是否为空
postfixExpression.push_back(num);//数字直接加入后缀表达式
num="";//数字字符串清空
}
if(it=='('){//如果是左括号
flag++;//左括号数量+1
operatorStack.push(it);//左括号直接进栈
}
else if(it==')'){//如果是右括号
if(flag){//先判断是否右左括号(没有左括号的话flag的值为0)
while(!operatorStack.empty()&&operatorStack.top()!='('){//将栈内运算符一直弹出直到栈为空或者遇到左括号
string temp="";
temp.push_back(operatorStack.top());
postfixExpression.push_back(temp);//栈顶运算符加入后缀表达式
operatorStack.pop();//运算符出栈
}
operatorStack.pop();//左括号出栈
flag--;//左括号数量-1
}
else Error();//没有左括号则说明表达式有误
}
else{
if(it=='+'||it=='-'||it=='*'||it=='/'){//如果是运算符
//如果栈为空,或者栈顶是左括号,或者此运算符优先级大于栈顶运算符的优先级直接加入运算符栈
if(operatorStack.empty()||operatorStack.top()=='('||!(Preced(it,operatorStack.top()))) operatorStack.push(it);
else{//否则从栈中弹出并加入后缀表达式所有优先级高于或等于该运算符的运算符直到遇到括号或者栈空,再将本身运算符插入栈
while(!operatorStack.empty()&&Preced(it,operatorStack.top())){
string temp="";
temp.push_back(operatorStack.top());
postfixExpression.push_back(temp);//栈顶运算符加入后缀表达式
operatorStack.pop();//运算符出栈
}
operatorStack.push(it);//本身运算符插入栈
}
}
else Error();//既不是数字也不是运算符和括号,说明表达式有其他字符
}
}
}
//处理完读入的表达式后,左括号的数量应该为0,如果左括号有剩余说明没有相应的右括号即表达式有误
if(flag) Error();
//如果数字字符串不为空则直接进入后缀表达式
if(!num.empty()){
postfixExpression.push_back(num);//数字直接加入后缀表达式
num="";//数字字符串清空
}
//处理运算符栈内剩余的运算符
while(!operatorStack.empty()){
string temp="";
temp.push_back(operatorStack.top());
postfixExpression.push_back(temp);//栈顶运算符加入后缀表达式
operatorStack.pop();//运算符出栈
}
//最后后缀表达式的结果为postfixExpression
for(auto it:postfixExpression) cout<<it<<" ";
cout<<endl;
现在我们得到了一个后缀表达式(postfixExpression),我们该怎么进行计算呢
首先我们需要一个数字栈(number)用于临时储存操作数
其次遵循以下两条规则:
stack<int>number;//数字栈
vector<string>postfixExpression;//后缀表达式
for(auto it:postfixExpression){
if(isNumber(it))//如果是数字则直接加入数字栈内
number.push(stoi(it));//it是字符串需要转化为数字,可以直接使用string头文件内的stoi函数
else{//如果是运算符
if(number.size()<2) Error();//如果数字栈内元素数量少于2,说明没有足够的操作数,则说明表达式有误
int op2=number.top();number.pop();
int op1=number.top();number.pop();
number.push(calculate(op1,op2,it.front()));//将运算结果插入栈内
}
}
int ans=number.top();//最后数字栈内剩余的一个数字就是表达式的结果
number.pop();
if(!number.empty()) Error();//答案出栈后,栈应该为空,所以栈如果不为空说明表达式有误
cout<<ans<<endl;//输出最后的结果
#include<iostream>
#include<map>
#include<string>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
#define endl "\n"
map<char,int>op;
string origin;
void init(){//方便计算运算符的优先级,我就直接以一个映射关系给运算符赋了一个值
op['+']=1,op['-']=1,op['*']=2,op['/']=2,op['(']=3;
}
bool Preced(char a,char b){//比较运算符优先级
return op[a]<=op[b];
}
bool isNumber(string s){//判断这个字符串是不是数字
for(auto it:s){
if(!isdigit(it)){
return false;
}
}
return true;
}
int calculate(int num1,int num2,char ch){//计算表达式
switch(ch){
case '+':{
return num1+num2;
break;
}
case '-':{
return num1-num2;
break;
}
case '*':{
return num1*num2;
break;
}
case '/':{
if(num2==0){
cout<<"被除数不能为0"<<endl;
exit(1);
}
return num1/num2;
break;
}
default:{
cout<<"表达式有误"<<endl;
exit(1);
}
}
}
void Error(){//报错
cout<<origin<<endl;
cout<<"表达式有误"<<endl;
exit(1);
}
int main(){
init();//初始化映射
//中缀表达式转后缀表达式
cin>>origin;//读入表达式
stack<char>operatorStack;//运算符栈
vector<string>postfixExpression;//后缀表达式
string num="";//储存数字
int flag=0;//统计左括号个数
for(auto it:origin){
if(isdigit(it)) num.push_back(it);//如果是数字,则加入数字字符串内
else{//不是数字
if(!num.empty()){//判断数字字符串是否为空
postfixExpression.push_back(num);//数字直接加入后缀表达式
num="";//数字字符串清空
}
if(it=='('){//如果是左括号
flag++;//左括号数量+1
operatorStack.push(it);//左括号直接进栈
}
else if(it==')'){//如果是右括号
if(flag){//先判断是否右左括号(没有左括号的话flag的值为0)
while(!operatorStack.empty()&&operatorStack.top()!='('){//将栈内运算符一直弹出直到栈为空或者遇到左括号
string temp="";
temp.push_back(operatorStack.top());
postfixExpression.push_back(temp);//栈顶运算符加入后缀表达式
operatorStack.pop();//运算符出栈
}
operatorStack.pop();//左括号出栈
flag--;//左括号数量-1
}
else Error();//没有左括号则说明表达式有误
}
else{
if(it=='+'||it=='-'||it=='*'||it=='/'){//如果是运算符
//如果栈为空,或者栈顶是左括号,或者此运算符优先级大于栈顶运算符的优先级直接加入运算符栈
if(operatorStack.empty()||operatorStack.top()=='('||!(Preced(it,operatorStack.top()))) operatorStack.push(it);
else{//否则从栈中弹出并加入后缀表达式所有优先级高于或等于该运算符的运算符直到遇到括号或者栈空,再将本身运算符插入栈
while(!operatorStack.empty()&&Preced(it,operatorStack.top())){
string temp="";
temp.push_back(operatorStack.top());
postfixExpression.push_back(temp);//栈顶运算符加入后缀表达式
operatorStack.pop();//运算符出栈
}
operatorStack.push(it);//本身运算符插入栈
}
}
else Error();//既不是数字也不是运算符和括号,说明表达式有其他字符
}
}
}
//处理完读入的表达式后,左括号的数量应该为0,如果左括号有剩余说明没有相应的右括号即表达式有误
if(flag) Error();
//如果数字字符串不为空则直接进入后缀表达式
if(!num.empty()){
postfixExpression.push_back(num);//数字直接加入后缀表达式
num="";//数字字符串清空
}
//处理运算符栈内剩余的运算符
while(!operatorStack.empty()){
string temp="";
temp.push_back(operatorStack.top());
postfixExpression.push_back(temp);//栈顶运算符加入后缀表达式
operatorStack.pop();//运算符出栈
}
//最后后缀表达式的结果为postfixExpression
for(auto it:postfixExpression) cout<<it<<" ";
cout<<endl;
//计算后缀表达式的结果
stack<int>number;//数字栈
for(auto it:postfixExpression){
if(isNumber(it))//如果是数字则直接加入数字栈内
number.push(stoi(it));//it是字符串需要转化为数字,可以直接使用string头文件内的stoi函数
else{//如果是运算符
if(number.size()<2) Error();//如果数字栈内元素数量少于2,说明没有足够的操作数,则说明表达式有误
int op2=number.top();number.pop();
int op1=number.top();number.pop();
number.push(calculate(op1,op2,it.front()));//将运算结果插入栈内
}
}
int ans=number.top();//最后数字栈内剩余的一个数字就是表达式的结果
number.pop();
if(!number.empty()) Error();//答案出栈后,栈应该为空,所以栈如果不为空说明表达式有误
cout<<ans<<endl;//输出最后的结果
}
特别的,我们也可以在中缀表达式转后缀表达式的时候直接进行运算
完整代码如下:
#include<iostream>
#include<map>
#include<string>
#include<stack>
#include<algorithm>
using namespace std;
#define endl "\n"
map<char,int>op;
string origin;
void init(){
op['+']=1,op['-']=1,op['*']=2,op['/']=2,op['(']=3;
}
bool Preced(char a,char b){
return op[a]<=op[b];
}
int calculate(int num1,int num2,char ch){
switch(ch){
case '+':{
return num1+num2;
break;
}
case '-':{
return num1-num2;
break;
}
case '*':{
return num1*num2;
break;
}
case '/':{
if(num2==0){
cout<<"被除数不能为0"<<endl;
exit(1);
}
return num1/num2;
break;
}
default:{
cout<<"表达式有误"<<endl;
exit(1);
}
}
}
void Error(){
cout<<origin<<endl;
cout<<"表达式有误"<<endl;
exit(1);
}
int main(){
init();
cin>>origin;
string num="";
int flag=0;//统计左括号个数
stack<int>number;
stack<char>operatorStack;
for(auto it:origin){
if(isdigit(it)) num.push_back(it);
else{
if(!num.empty()){
number.push(stoi(num));
num="";
}
if(it=='('){
flag++;
operatorStack.push(it);
}
else if(it==')'){
if(flag){
while(!operatorStack.empty()&&operatorStack.top()!='('){
if(number.size()<2) Error();
else{
int op2=number.top();
number.pop();
int op1=number.top();
number.pop();
number.push(calculate(op1,op2,operatorStack.top()));
}
operatorStack.pop();
}
operatorStack.pop();
flag--;
}
else Error();
}
else{
if(it=='+'||it=='-'||it=='*'||it=='/'){
if(operatorStack.empty()||operatorStack.top()=='('||!(Preced(it,operatorStack.top()))) operatorStack.push(it);
else{
while(!operatorStack.empty()&&Preced(it,operatorStack.top())){
if(number.size()<2) Error();
else{
int op2=number.top();
number.pop();
int op1=number.top();
number.pop();
number.push(calculate(op1,op2,operatorStack.top()));
}
operatorStack.pop();
}
operatorStack.push(it);
}
}
else Error();
}
}
}
if(flag) Error();
if(!num.empty()){
number.push(stoi(num));
num="";
}
while(!operatorStack.empty()){
if(number.size()<2) Error();
else{
int op2=number.top();
number.pop();
int op1=number.top();
number.pop();
number.push(calculate(op1,op2,operatorStack.top()));
}
operatorStack.pop();
}
int res=number.top();
number.pop();
if(!number.empty()) Error();
cout<<res<<endl;
return 0;
}