题目描述
给出一个表达式,其中运算符仅包含+,-,*,/,^(加 减 乘 整除 乘方)要求求出表达式的最终值
数据可能会出现括号情况,还有可能出现多余括号情况
数据保证不会出现≥2……31的答案
数据可能会出现负数情况
题目就是这样简单明了,相信大家都能读懂,我也就不解释了,直接开干。
分析
看题目给的样例,这是一个中缀表达式,也是我们人类最熟悉的表达方式,但电脑它不熟悉呀,怎么办,那当然是把它转化成后缀表达式,那电脑算它不是有手就行。转化成后缀了又怎么办呢,那当然是用栈把它算出来啊。
思路有了,那怎么实现呢,首先我们要知道怎么实现上述转化
中缀表达式转后缀表达式
1.建立一个用于存运算符的栈,逐一扫描该中缀表达式中的元素
(1)如果遇到一个数,输出该数。
(2)如果遇到左括号,把左括号入栈。
(3)如果遇到右括号,不断取出栈顶并输出,直到栈顶为左括号,然后把左括号出栈
(4)如果遇到运算符,只要栈顶符号的优先级不低于新符号,就不断取出栈顶并输出,优先级为乘除>加减>左括号。
2.依次取出并输出栈中所有剩余符号,最后输出的表达式就是一个与原表达式等价的后缀表达式。
后缀表达式求值
1.建立一个用于存数的栈,逐一扫描该后缀表达式的每一个元素
(1)如果遇到一个数,则把该数入栈。
(2)如果遇到运算符,就把栈顶的两个数进行运算,把结果入栈。
2.扫描完成后,栈中恰好只剩一个数,就是该后缀表达式的值。
还有要特别注意的是可能有多余的括号。
理论都有了,直接上代码。
#include<bits/stdc++.h> using namespace std; const int N=110; char s[N];//字符串 char st[N];//存运算符 char ans[N];//存数字 int top,cnt,num; int t[666];//标记运算符等级 int stt[N];//计算结果的栈 int chengfang(int a,int b) { int k=1; while(b--) k*=a; return k; } signed main() { t[int('^')]=4;//规定运算符等级 t[int('*')]=3;// t[int('/')]=3;// t[int('+')]=1;// t[int('-')]=1;// cin>>(s+1);//从第一位开始 int len=strlen(s+1); for(int i=1;i<=len;i++) { if(s[i]>='0'&&s[i]<='9') ans[++cnt]=s[i]; else { if((s[i]=='-'&&i==1/*不要偷工减料*/)||(s[i-1]=='('&&s[i]=='-'))//当扫描的第一个数是负数,或者在字符串中间有负数 { ans[++cnt]='0';//就把负数转化为零减去这个数的绝对值 ans[++cnt]='#'; st[++top]='-';//同时要加一个运算符 continue; } if(s[i-1]>='0'&&s[i-1]<='9')//每读完一个数字就在后面加一个‘# ’隔开方便运算 ans[++cnt]='#'; if(s[i]=='(') st[++top]=s[i]; else if(s[i]==')')//当扫描到的是右括号,只要栈顶不是左括号就一直输出 { while(st[top]!='(') ans[++cnt]=st[top--]; top--;//栈顶指针后移 } else//为运算符 { while(t[s[i]]<=t[st[top]]&&top)//只要栈顶符号的优先级不低于新符号, ans[++cnt]=st[top--]; //就不断取出栈顶并输出 st[++top]=s[i];//最后将新符号入栈 } } } if(s[len]>='0'&&s[len]<='9') ans[++cnt]='#'; while(top)//依次输出栈中所有剩余符号 ans[++cnt]=st[top--]; for(int i=1;i<=cnt;i++) { if(ans[i]>='0'&&ans[i]<='9') { num=num*10+ans[i]-'0';//转化为数字 continue; } if(ans[i]=='#')//扫描到了‘# ’ { stt[++top]=num; num=0;//记得将num初始化,方便记录下一个数 } else//中缀转成后缀后 { top--;//每次遇到运算符就将栈顶的两个数进行运算,结果放回栈中 if(ans[i]=='+') stt[top]=stt[top]+stt[top+1]; else if(ans[i]=='-') stt[top]=stt[top]-stt[top+1]; else if(ans[i]=='*') stt[top]=stt[top]*stt[top+1]; else if(ans[i]=='/') stt[top]=stt[top]/stt[top+1]; else if(ans[i]=='^') stt[top]=chengfang(stt[top],stt[top+1]); else top++;//特殊处理,如果遇到多余的括号,栈顶指针就不动 } } cout<<stt[top]<<endl; return 0; }
这是本蒟蒻第一次写题解,希望能帮到像我一样的蒟蒻。
另外附上一份dalao的直接算中缀表达式的代码。
#include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<iostream> using namespace std; int num[260],topn=0,topo=0,g; char st[260],ops[260]; int you(char ch){ if(ch=='+'||ch=='-') return 2; if(ch=='*'||ch=='/') return 3; if(ch=='^') return 4; return 1; } inline int js(int a){ int sum=0; int f=a; while(st[a]>='0'&&st[a]<='9') a++; g=a; for(int i=f;i<g;i++) sum=sum*10+(st[i]-'0'); return sum; } inline void jia(){ topo--; int sum=num[topn]+num[topn-1]; topn--; num[topn]=sum; } inline void jian(){ topo--; int sum=num[topn-1]-num[topn]; topn--; num[topn]=sum; } inline void cheng(){ topo--; int sum=num[topn-1]*num[topn]; topn--; num[topn]=sum; } inline void chu(){ topo--; int sum=num[topn-1]/num[topn]; topn--; num[topn]=sum; } inline void mul(){ topo--; int x = num[topn - 1], k = num[topn]; int s = 1; for(int i = 1; i <= k; i ++ ) s *= x; topn--; num[topn] = s; } int main(){ gets(st); int len=strlen(st); st[len]=')'; ops[++topo]='('; for(int i=0;i<=len;i++){ if(st[i]>='0'&&st[i]<='9'){ int x=js(i);i=g-1; num[++topn]=x; } else if(st[i]=='(') ops[++topo]='('; else if((st[i]=='-'&&i==0)||(st[i]=='-'&&st[i-1]=='(')){ num[++topn]=0; ops[++topo]='-'; } else if(st[i]=='+'||st[i]=='-'||st[i]=='*'||st[i]=='/'||st[i]=='^'){ while(you(ops[topo]) >= you(st[i])){ if(ops[topo]=='+') jia(); if(ops[topo]=='-') jian(); if(ops[topo]=='*') cheng(); if(ops[topo]=='/') chu(); if(ops[topo]=='^') mul(); } ops[++topo]=st[i]; } else if(st[i]==')'){ while(ops[topo]!='('){ if(ops[topo]=='+') jia(); if(ops[topo]=='-') jian(); if(ops[topo]=='*') cheng(); if(ops[topo]=='/') chu(); if(ops[topo]=='^') mul(); } topo--; } } printf("%d",num[topn]); return 0; }