利用栈进行表达式求解
以前A掉的表达式求解统统是递归= =,栈一直不知道怎么搞,今天稍微看了看,写了一个较简单的。
对于一个合法的表达式,只要知道运算符的优先级即可利用栈求解,貌似是将中缀表达式转化为了后缀表达式,这些个名词咳咳= =
顾名思义后缀表达式就是运算符写在后面嘛,对于a+b就是ab+ ,我们就知道要计算ab的和,对于一些更复杂状态的式子,显然需要一些技巧。
先来看一道简单的题目 http://acm.nyist.net/JudgeOnline/problem.php?pid=1272
注意到这个题目中只有Smax一个函数所以可以用逗号来替代这个函数更加简便,我们用两个栈保存中间变量,一个储存符号的栈sc,一个储存中间值的栈si,还要有一个优先级表。
当前字符如果是一个数字那就计算出连续的这个数字并加入到si中,如果是个字符的话,与sc栈顶字符比较优先级,如果等于栈顶那就出栈(对于'(',')'这些特殊的匹配符号),如果大于栈顶那么说明应该先执行这个运算符,
入栈即可,如果小于栈顶,说明我们要用掉栈顶的运算符,取出si中的两个数后根据栈顶符号计算后再将结果加入到si中,注意到可能有多个需要计算的运算符所以这里用一个循环表达。为了方便引入'#'这个匹配字符,这样不用判断栈空的情况,显然最后sc中只有一个数字,就是答案了。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<queue> 6 #include<map> 7 #include<stack> 8 #include<ctype.h> 9 using namespace std; 10 #define inf 0x3f3f3f3f 11 char opt[]={'=',',','*','(',')','#'}; 12 int g[10][10]={ 13 {1,1,-1,-1,1,1}, 14 {-1,1,-1,-1,1,1}, 15 {1,1,1,-1,1,1}, 16 {-1,-1,-1,-1,0,1}, 17 {1,1,1,0,1,1}, 18 {-1,-1,-1,-1,-1,0} 19 }; 20 map<char,int>M; 21 char s[330]; 22 stack<char>sc; 23 stack<int>si; 24 int num(int N) 25 { 26 int r=0; while(N){r+=N%10;N/=10;} 27 return r; 28 } 29 int cal(int a,int b,char ch) 30 { 31 switch(ch){ 32 case '+':return a+b;break; 33 case '*':return a*b;break; 34 case ',':return max(num(a),num(b));break; 35 } 36 } 37 int main() 38 { 39 int T,N,i,j,k; 40 for(i=0;i<6;++i) 41 M[opt[i]]=i; 42 cin>>T; 43 while(T--){ 44 scanf("%s",s); 45 N=strlen(s); 46 s[N]='#'; 47 while(!sc.empty())sc.pop(); 48 while(!si.empty())si.pop(); 49 sc.push('#'); 50 for(i=0;i<=N;++i) 51 { 52 int t=-1; 53 if(isdigit(s[i])){ 54 t=s[i]-'0'; 55 while(isdigit(s[i+1])){ 56 t=t*10+s[++i]-'0'; 57 } 58 si.push(t); 59 } 60 else{bool ok=1; 61 while(ok){ 62 if(s[i]=='S')i+=4; 63 int x=g[M[sc.top()]][M[s[i]]]; 64 if(x==0) ok=0,sc.pop(); 65 else if(x==-1) ok=0,sc.push(s[i]); 66 else{ 67 int a1=si.top();si.pop(); 68 int a2=si.top();si.pop(); 69 si.push(cal(a2,a1,sc.top())); 70 sc.pop(); 71 } 72 } 73 } 74 } 75 cout<<si.top()<<endl; 76 } 77 return 0; 78 }
http://acm.hdu.edu.cn/showproblem.php?pid=1237
有了四种运算+-*/ , 其实和上面的类似改下代码就能AC,当然可以写的更简单,不过为了练习栈就这样写了。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<queue> 6 #include<map> 7 #include<stack> 8 #include<ctype.h> 9 using namespace std; 10 #define inf 0x3f3f3f3f 11 char opt[]={'+','-','*','/','(',')','#'}; 12 int g[10][10]={ 13 {1,1,-1,-1,-1,1,1}, 14 {1,1,-1,-1,-1,1,1}, 15 {1,1,1,1,-1,1,1}, 16 {1,1,1,1,-1,1,1}, 17 {-1,-1,-1,-1,-1,0,1}, 18 {1,1,1,1,0,1,1}, 19 {-1,-1,-1,-1,-1,-1,0} 20 }; 21 map<char,int>M; 22 char s[1005]; 23 stack<char>sc; 24 stack<double>si; 25 double cal(double a,double b,char ch) 26 { 27 switch(ch){ 28 case '+':return a+b;break; 29 case '*':return a*b;break; 30 case '-':return a-b;break; 31 case '/':return a/b;break; 32 } 33 } 34 int main() 35 { 36 int T,N,i,j,k; 37 for(i=0;i<7;++i) 38 M[opt[i]]=i; 39 while(gets(s)){ 40 N=strlen(s); 41 if(N==1&&s[0]=='0') break; 42 s[N]='#'; 43 while(!sc.empty())sc.pop(); 44 while(!si.empty())si.pop(); 45 sc.push('#'); 46 for(i=0;i<=N;++i) 47 { 48 if(s[i]==' ') continue; 49 double t=-1; 50 if(isdigit(s[i])){ 51 t=s[i]-'0'; 52 while(isdigit(s[i+1])){ 53 t=t*10+s[++i]-'0'; 54 } 55 si.push(t); 56 } 57 else{bool ok=1; 58 while(ok){ 59 int x=g[M[sc.top()]][M[s[i]]]; 60 if(x==0) ok=0,sc.pop(); 61 else if(x==-1) ok=0,sc.push(s[i]); 62 else{ 63 double a1=si.top();si.pop(); 64 double a2=si.top();si.pop(); 65 si.push(cal(a2,a1,sc.top())); 66 sc.pop(); 67 } 68 } 69 } 70 } 71 printf("%.2f\n",si.top()); 72 } 73 return 0; 74 }