本文已参与「新人创作礼」活动,一起开启掘金创作之路。
中缀表达式转后缀表达式
首先,说明为什么会有中缀转后缀的需求,一般是为了计算机更好的求值运算,我们习惯的常规的中缀表达式需要考虑到括号的优先级,所以计算机很难理解,而后缀表达式只需要从前往后扫描运算即可,这无疑方便与计算机的运算。
规则:
- 遇到数值直接输出
- 遇到其他的比较优先级,这里可以简单的把+、-、*、/这些符号当成一种比较矫情的符号,他们忍受不了比他们大(优先级高于或等于)的符号在家中带着享福,认为大的符号就应该外出挣钱,而自己和那些比较小的弟弟妹妹则应该待在家里。括号另说。
- 括号代表则打包带走的含义。需结合例子自行体会。
实例:
把中缀表达式:a+b-a*((c+d)/e-f)+g
转化为后缀表达式:ab+acd+e/f- { ** }-g+#。如果有大括号等自行调整程序。
Tips:请自己跟着步骤来一遍,只看是看不懂的。
步骤:/ 为转义,避免md语法
a 直接输出
/+ Home中没有比+更大的了,+进入home
b 直接输出
/- Home中竟然有比自己大的人(指+),受不了,把+打一顿然后轰出去。/-进入home
a 输出
/* home中只有自己的妹妹/-。所以 / * 进入home
/( 遇见左括号直接进入
/( 遇见左括号直接进入
c 输出
/+ home中没人(Tips:(左括号起到了隔断家的作用)
d 输出
/)home中形成了一对括号,所以资本家把括号内的人都移出了家干活
/ / home中无人,/进入
e输出
/- 把/赶出去,/-进入
f输出
/)资本家打包带走
/+ 把家中的* - 赶出去
g输出
最后的最后,家没了,所以家里面的+只能出来干活了
结果:
#include<iostream>
#include<bits/stdc++.h>
#include<algorithm>
using namespace std;
/*
系统的说明一下:
isp表示in stack priority,即栈内优先级
icp表示in coming priority,即栈外优先级
优先级表格如下:
+------+---------+----------+----------+--------+--------+
操作符 | # | ( | *,/ | +,- | ) |
isp | 0 | 1 | 5 | 3 | 6 |
icp | 0 | 6 | 4 | 2 | 1 |
数组中的‘0’用于填充
*/
char isp[7]= {'#','(','0','+','0','*',')'};
char icp[7]= {'#',')','+','0','*','0','('};
stack<char> home;
//得到某元素的isp
int getisp(char a)
{
if(a=='-')
a='+';
if(a=='/')
a='*';
for(int i=0; i<7; i++)
if(a==isp[i])
{
return i;
}
return -1;
}
//得到某元素的icp
int geticp(char a)
{
if(a=='-')
a='+';
if(a=='/')
a='*';
for(int i=0; i<7; i++)
if(a==icp[i])
{
return i;
}
return -1;
}
string GetHomeitem(stack<char> h)
{
string tmp="";
while(!h.empty())
{
tmp+=h.top();
h.pop();
}
reverse(tmp.begin(),tmp.end());
return tmp;
}
int main()
{
//s就是中缀表达式
string s;
cin>>s;
//res则是后缀表达式
string res="";
int cnt=1;
home.push('#');
for(int i=0; i<s.size(); i++)
{
char item = s[i];
//如果是数,直接输出
if(geticp(item)==-1)
{
res+=item;
cout<<"NO."<<cnt++<<". | Scan item :"<< item<<" | Home(Stack):"<<GetHomeitem(home)<<" | ";
cout<<" Res :"<<res<<endl;
}
//否则比较优先级
else{
char r = home.top();
while(geticp(item)<getisp(r)&&!home.empty())//只要你比我大,你就要出来
{
res+=r;
home.pop();
r=home.top();
cout<<"NO."<<cnt++<<". | Scan item :"<< item<<" | Home(Stack):"<<GetHomeitem(home)<<" | ";
cout<<" Res :"<<res<<endl;
}
if(r=='('&&item==')')
home.pop();
if(item!=')')
{
home.push(item);
cout<<"NO."<<cnt++<<". | Scan item :"<< item<<" | Home(Stack):"<<GetHomeitem(home)<<" | ";
cout<<" Res :"<<res<<endl;
}
}
}
while(!home.empty())
{
res+=home.top();
home.pop();
cout<<"NO."<<cnt++<<". | Scan item : " <<" | Home(Stack):"<<GetHomeitem(home)<<" | ";
cout<<" Res :"<<res<<endl;
}
cout<<res<<endl;
return 0;
}
快速方法
11/12/2021 Update
- 首先按照运算符优先级对所有运算单位加括号
- 把运算符移动到对应的括号后面
- 去括号
举例
a/b+(cd-(ef)/g) 有:
- 加括号 ((a/b)+(((c *d)-(e *f))/g))
- 运算符后移 ((ab)/(((cd)**(ef)*)-g)/)+
- 去括号 ab/cd{ ** } e f { /*}-g/+