其实这种题,中缀转后缀才蛋疼……
先说如何计算后缀表达式:
从前往后扫表达式;
若遇到数字,则扔进数字栈中。
若遇到算符,则弹出栈顶的两个数字进行计算,再扔进去。
最后答案是数字栈里剩下的一个数。
那么如何中缀转后缀呢?
从前往后扫表达式;
若遇到数字,则直接添加进后缀表达式中。
若遇到算符,则与栈顶比较(若栈为空则扔进栈中):
{
若当前算符比栈顶算符优先级高,则直接扔进栈里;
若低,则一直弹出栈顶元素并且添加进后缀表达式中,直到栈为空或者栈顶元素优先级比当前元素低。
若为左括号,则直接扔入栈中。
若为右括号,则一直弹出栈顶元素到后缀表达式中,直到栈顶元素为左括号,弹出左括号。
}
扫完后,把栈中元素弹出进入后缀表达式中。
我觉得这个文章讲的不错,比我说的好多了:戳我
还有就是处理负数,只要在负号前面加一个0即可(并不是平常计算用的减号)
据说有一个表达式树的东西,能把前中后缀表达式转换为表达式树的前中后序遍历,然后递归计算即可……这个大神告诉我的@loi_xczhw Orz
不过我做tyvj1043的时候,不知道是OJ出毛病还是我程序有问题,手测无误交上就WA或者RE,所以代码我就贴1042的吧…少个负数和括号的处理而已QAQ
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<stack>
#include<cmath>
using namespace std;
typedef long long LL;
LL calc(LL a,LL b,char c)
{
if(c=='+') return a+b;
if(c=='-') return a-b;
if(c=='*') return a*b;
if(c=='/') return a/b;
if(c=='^') return (LL)pow(a,b);
}
stack<LL> num;
LL pri[233];
LL solve(string s)
{
for(int i=0;i<s.length();i++)
{
if(s[i]>='0'&&s[i]<='9')
{
int x;
sscanf(s.c_str()+i,"%d",&x);
num.push(x);
for(;i+1<s.length()&&s[i+1]>='0'&&s[i+1]<='9';i++); i++;
}
else
{
int y=num.top(); num.pop();
int x=num.top(); num.pop();
num.push(calc(x,y,s[i]));
}
}
return num.top();
}
string change(string s)
{
string str;
stack<char> oper;
for(int i=0;i<s.length();i++)
{
if(s[i]>='0'&&s[i]<='9')
{
str+=s[i];
for(;i+1<s.length()&&s[i+1]>='0'&&s[i+1]<='9';i++) str+=s[i+1];
str+=" ";
}
else
{
if(oper.empty()) oper.push(s[i]);
else
{
if(pri[s[i]]>pri[oper.top()])
{
oper.push(s[i]);
}
else
{
while(oper.size()&&pri[s[i]]<=pri[oper.top()])
{
char x=oper.top(); oper.pop();
str+=x;
}
oper.push(s[i]);
}
}
}
}
while(oper.size())
{
char x=oper.top();
str+=x;
oper.pop();
}
return str;
}
int main()
{
pri['+']=pri['-']=1;
pri['*']=pri['/']=2;
pri['^']=3;
string s;
cin>>s;
string str=change(s);
cout<<str<<endl;
printf("%d",solve(str));
return 0;
}
/*
2^3+1
9+2*3+10/2
100-1-1-1-1-1-2^4
5-1-1-1-1-1-2^4
*/