给出一个表达式,其中运算符仅包含+,-,*,/,^要求求出表达式的最终值
数据可能会出现括号情况 还有可能出现多余括号情况
数据保证不会出现>maxlongint的数据
数据可能回出现负数情况
仅一行,即为表达式
仅一行,既为表达式算出的结果
(2+2)^(1+1)
16
表达式总长度<=30
题目分析,在计算过程中用codevs3066的方法有点小问题,修改为
将一个中序表达式转化成为后缀表达式方法
首先维护的是两个栈,我们这里暂且称为S1和S2,S1中的结果最后存的就是逆波兰表达式,S2中将用于暂时存放运算符并且在最终形成逆波兰表达式的时候,该栈是会清空的。下面我们看看怎样具体的形成逆波兰表达式。
在此首先定义一下运算符的优先级关系,从小到达排序,相同优先级没有用逗号隔开:(,+-,*\,负号,)。
从左至右遍历一个给定的中序表达式,也就是我们常规的数学计算的表达式。
(1)如果遇到的是数字,我们直接加入到栈S1中;
(2)如果遇到的是左括号,则直接将该左括号加入到栈S2中;
(3)如果遇到的是右括号,那么将栈S2中的运算符一次出栈加入到栈S1中,直到遇到左括号,但是该左括号出栈S2并不加入到栈S1中;
(4)如果遇到的是运算符,包括单目运算符和双目运算符,我们按照下面的规则进行操作:
(4-1)如果此时栈S2为空,则直接将运算符加入到栈S2中;
(4-2)如果此时栈S2不为空,当前遍历的运算符的优先级大于(等于,等于删掉)栈顶运算符的优先级,那么直接入栈S2;
(4-3)如果此时栈S2不为空,当前遍历的运算符的优先级小于(增加等于)栈顶运算符的优先级,则将栈顶运算符一直出栈加入到栈S1中,直到栈为空或者遇到一个运算符的优先级小于等于当前遍历的运算符的优先级,此时将该运算符加入到栈S2中;
(5)直到遍历完整个中序表达式之后,栈S2中仍然存在运算符,那么将这些运算符依次出栈加入到栈S1中,直到栈为空。
按照上面的五条操作反复进行完成,那么栈S1中存放的就是逆波兰表达式。
然后是逆波兰表达式的计算方法.
转自http://www.nowamagic.net/librarys/veda/detail/2306
为了解释后缀表达式的好处,我们先来看看,计算机如何应用后缀表达式计算出最终的结果20的。
后缀表达式:9 3 1-3*+ 10 2/+
下面是详细的步骤:
1. 初始化一个空栈。此桟用来对要运算的数字进出使用。
2. 后缀表达式中前三个都是数字,所以9、3、1进栈。
3. 接下来是减号“-”,所以将栈中的1出栈作为减数,3出栈作为被减数,并运算3-1得到2,再将2进栈。
4. 接着是数字3进栈。
5. 后面是乘法“*”,也就意味着栈中3和2出栈,2与3相乘,得到6,并将6进栈。
6. 下面是加法“+”,所以找中6和9出找,9与6相加,得到15,将15进栈。
7. 接着是10与2两数字进栈。
8. 接下来是符号因此,栈顶的2与10出栈,10与2相除,得到5,将5进栈。
9. 最后一个是符号“+”,所以15与5出找并相加,得到20,将20进栈。
10. 结果是20出栈,栈变为空。
#include<stdio.h> #include<string.h> #include<math.h> #include<stack> #include<cctype> #include<iostream> using namespace std; struct node{ int count; char opr; }; stack<int>s2; node s1[100];//操作符 char a[100]; int len,top=0,oprnum=0; int first[130];//存储++*/的优先级 int com(int x,int y,char opr ){ int tmp; switch(opr){ case '^':{tmp=(int)pow(x,y);break;} case '*':{tmp=x*y;break;} case '/':{tmp=x/y;break;} case '+':{tmp=x+y;break;} case '-':{tmp=x-y;break;} } return tmp; } int comput(){ stack<int>s3; for(int i=1;i<=top;i++){ if(s1[i].opr==0)s3.push(s1[i].count); else{ int x,y; char opr=s1[i].opr; x=s3.top(); s3.pop(); if(s3.empty()) s3.push(com(0,x,opr)); else{ y=s3.top(); s3.pop(); s3.push(com(y,x,opr)); } } } return s3.top(); } int main() { first['+']=first['-']=2; first['*']=first['/']=3; first['^']=4; first['(']=1;// first[')']=1;//其实这两个优先级没使用,括号单独处理的. scanf("%s",a); len=strlen(a); a[len]='.'; int tmp=0; bool f=false; for(int i=0;i<len;i++){ if(a[i]>=48&&a[i]<=57){ //计算数字 f=true; tmp=tmp*10+a[i]-'0'; if(i==len-1) s1[++top].count=tmp; continue; } else{ if(f)s1[++top].count=tmp;; //遇到符号,前一个数字入栈 f=false; tmp=0; if(s2.empty())s2.push(a[i]);//空栈,符号直接入栈 else { if(a[i]=='('){s2.push(a[i]);continue; }//左括号直接入栈 if(first[a[i]]>first[s2.top()])//高优先级直接入栈 s2.push(a[i]); else{ if(a[i]=='+'||a[i]=='-'||a[i]=='*'||a[i]=='/'||a[i]=='^'){//<=的优先级先出栈计算,再入栈 while(!s2.empty()&&first[a[i]]<=first[s2.top()]&&s2.top()!='('){ s1[++top].opr=s2.top(); s2.pop(); ++oprnum; } //=-*/^结束 s2.push(a[i]); } if(a[i]==')'){//右括号,出栈到遇到左括号 while(!s2.empty()&&s2.top()!='('){ s1[++top].opr=s2.top(); s2.pop(); ++oprnum; } //)结束 if(!s2.empty()&&s2.top()=='(')s2.pop(); } }//两种出战结束 } }//符号处理结束 } while(!s2.empty()){//输入完成后剩余两种栈处理 char opr=s2.top(); if(opr=='('||opr==')'){ s2.pop(); continue; } s1[++top].opr=s2.top(); s2.pop(); ++oprnum; } printf("%d\n",comput()); return 0; }