前缀表达式、中缀表达式与后缀表达式的四则运算
表达式的四则运算比较好理解,弄通以后发现栈的运用也顺手了不少。
关于中缀转前缀/后缀,大佬一般用两个栈我看不太懂,于是我决定只用一个栈结合字符串,实现基本转化,要注意的就是多位数字字符串转化成整数。若是用两个栈的话都设定成string类型就能互相存储了。
约定:
可能出现个位及以上数字
数字及运算符之间用空格隔开
表达式中除数不为0(懒得处理了)
1.根据任意表达式画出语法树
在规定了文法和优先级的情况下,语法树是唯一的【加减同级,乘除同级也不可互换顺序,如a-b+cd互换加减顺序会得到a-(b+cd)即a-b-cd】。根据语法树先序遍历即可得到前缀表达式(波兰式),中序遍历得到中缀表达式,后序遍历得到后缀表达式(逆波兰式)。同样我们可由任意式子画出语法树方便人的理解。
画树诀窍:运算优先级越低越靠近根部
中缀表达式一(值为115.649)
1 + 22 * 333 / 4444 - 7 + 6000 / 50的语法树为
先序遍历得到其前缀表达式为+ - + 1 / * 22 333 4444 7 / 6000 50
后序遍历得到其后缀表达式为1 22 333 * 4444 / + 7 - 6000 50 / +
中缀表达式二(值为180)
311 + 7 * ( 11 - 24 ) - 5 * 8的语法树为
先序遍历得到其前缀表达式为- + 311 * 7 - 11 24 * 5 8
后序遍历得到其后缀表达式为311 7 11 24 - * + 5 8 * -
2.将多位字符串型数字转化为整数
由于是逐位扫描字符串,所以需要把形如“1234”的字符串转化为其对应的整数值1234
int StringToInt(string s)
{
int n=0,i=0;
int t=s.length();
for(t=pow(10,t-1);t>0;t/=10)
n+=(s[i++]-'0')*t;
return n;
}
3.后缀表达式求值
开辟一个数值栈in,从左往右逐位扫描后缀表达式。
遇见数字将其压栈(注意处理多位数);
遇见运算符,则出栈两个整数n2和n1,n1对n2使用该运算符进行运算操作,运算结果压栈。(栈的规律:进一出二)
后缀表达式扫描结束时,栈顶元素即为所求值。
float ValueOfSuffix(string s)
{
stack<float> in;
for(int i=0;i<s.length();i++)
{
//扫描到空格,跳过
if(s[i]==' ')
continue;
//扫描到数字,压栈
else if(s[i]>='0' && s[i]<='9')
{
//将多位字符型数字转化为整数
string num;
while(s[i+1]>='0' && s[i+1]<='9')
num+=s[i++];
num+=s[i++];
in.push(StringToInt(num)*1.0);
}
//扫描到运算符,弹出两个整数进行运算并压栈
else
{
float n2=in.top();
in.pop();
float n1=in.top();
in.pop();
switch(s[i])
{
case '+':
in.push(n1+n2);break;
case '-':
in.push(n1-n2);