逆波兰式式也称后缀表达式。
一般的表达式求值式子都为中缀表达式,而后缀表达式求值相对更容易,所以可以将中缀表达式转换为后缀表达式。
ps:不了解中缀表达式,后缀表达式的建议先去了解一下。
对于初学者容易弄混这三种,其实前,中,后即节点位置。
前缀表达式树,遍历顺序(节点,左,右)。
中缀表达式树,遍历顺序(左,节点,右)。
后缀表达式树,遍历顺序(左,右,节点)。
步骤:
第一步:将中缀表达式转换为后缀表达式。
1,将+,-,*,/,(等要用到的运算进行优先级处理。
2,需要用到一个符号栈处理:
a,数字字符,小数点直接存入另一个字符串S。
b,’(‘直接入栈,当表达式str字符中‘)’出现,将所有栈顶运算符转移至S直至遇到‘(’,‘(’出栈。
c,当表达式str字符中的运算符优先级大于等于(注意一定要大于等于)栈顶运算符优先级时,将字符依次存入S,直至小于为止。当前运算符入栈。
d,最后当str访问完,将栈中剩余运算符存到S。
第二步:将转换后的后缀表达式进行求值。
1,需要一个浮点型栈(具体根据题目要求)存放数值。
2,遍历S遇见操作数,小数点时处理后入栈,直至遇见运算符,出栈两个操作数,处理后将结果再入栈。
3,栈顶元素即为表达式解。
详情见百度百科
#include<iostream>
#include<string.h>
#include<cstdio>
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std;
string s1,s2;
stack<char>s;
stack<double>c;
void init()//清空
{
while(!s.empty())
s.pop();
while(!c.empty())
c.pop();
}
int yx(char ch)//优先级
{
switch(ch)
{
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
default :
return 0;
}
}
void deal()//把中缀表达式s1换成后缀表达式s2
{
init();
int i=0,len=s1.length();
s.push('#');//#的优先级很小,所有拿它来做比较
while(i<len-1)//i<len-1是因为表达式后有个“=”不用计算
{
if(s1[i]=='(')//左括号全放进去
s.push(s1[i++]);
else if(s1[i]=='+'||s1[i]=='-'||s1[i]=='*'||s1[i]=='/')
{
while(yx(s.top())>=yx(s1[i]))//比较优先级,当前优先级比栈顶的小,就把栈顶的拿出来
{
s2+=s.top();
s2+=' ';//s2中所有的’ ‘都是为了区分数字,比如3.1 2,不加’ ‘就变成了3.12,不能分辨
s.pop();
}
s.push(s1[i++]);//反之入栈
}
else if(s1[i]==')')//遇到右括号就去配对左括号,把中间的东西都转换掉
{
while(s.top()!='(')
{
s2+=s.top();
s.pop();
s2+=' ';
}
i++;
s.pop();
}
else
{
while(s1[i]<='9'&&s1[i]>='0'||s1[i]=='.')//转换数字
s2+=s1[i++];
s2+=' ';
}
}
while(s.top()!='#')//((1+2)*5+1)/4这一步就是为了改"/"
{
s2+=s.top();
s.pop();
s2+=' ';
}
}
double jieguo()//把更改后的s2来通过栈求最后结果,最后栈顶元素就是结果
{
int i=0,len=s2.length();
double x,y;
while(i<len)
{
if(s2[i]==' ')
i++;
else
{
switch(s2[i])//注意减号和除号有点不一样,手推一下
{
case'+':
x=c.top();
c.pop();
x+=c.top();
c.pop();
i++;
break;
case'-':
x=c.top();
c.pop();
x=c.top()-x;
c.pop();
i++;
break;
case'*':
x=c.top();
c.pop();
x*=c.top();
c.pop();
i++;
break;
case'/':
x=c.top();
c.pop();
x=c.top()/x;
c.pop();
i++;
break;
default:
{
x=0.0;
while(s2[i]<='9'&&s2[i]>='0')
{
x=x*10.0+(s2[i++]-'0');
}
if(s2[i]=='.')//小数转换
{
i++;
double k=10.0;
y=0.0;
while(s2[i]<='9'&&s2[i]>='0')
{
y+=(s2[i++]-'0')/k;
k*=10.0;
}
x+=y;
}
}
}
c.push(x);
}
}
return c.top();
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
s1="";//清空
cin>>s1;
s2="";
deal();
printf("%.2lf\n",jieguo());
}
return 0;
}