表达式求值 解题报告

来源:互联网 发布:gephi数据分析案例 编辑:程序博客网 时间:2024/06/11 13:55

表达式计算

Time Limit:10000MS  Memory Limit:65536K

Description

  输入一个由整数(绝对值小于1000的整数)、括号()、+、-、*、/、^(乘方)运算符构成的表达式,计算出表达式的值。
  (注1:“/”符号用作整除,即7/2=3,而不是3.5)
  (注2:本题中含有二目运算符号,以及一目运算符号,如:负号“-”)

Input

  一个由整数(绝对值小于1000的整数)、括号()、+、-、*、/、^(乘方)运算符构成的表达式,总长度不超过250个字符。输入数据保证运算的中间结果以及最终结果值的绝对值小于2^31。

Output

  表达式的值。

Sample Input

32*(12-13)/(-1)

Sample Output

32


可能有同学会遇到个位数和多位数两种情况,因为多位数表达式求值可以解决个位数的,两者也没什么差别,所以我这里贴的是多位数表达式求值的代码。

抛开个位数多位数不谈,谈谈我的求值思路;网上的说法是用栈+中缀转后缀表达式,然而其实并不一定要这么做。我们可以直接用递归(我当初没学栈时就这么做的),但是那样我写了8K,而改用栈之后我只写了4K,所以主要讲讲栈的处理方式。

我们很容易想到:先算里面的括号,再算外面的;先算左边的括号,再算右边的。所以递归的思路很显然:从左到右找到一个括号,递归找它里面的括号,直到找不到括号就求该括号的值。而用栈,我们可以每找到一个左括号就将其入栈,找到一个右括号就将栈顶的左括号弹出栈,这个弹出去的括号就是当前最里面的括号;这时先不要继续往下枚举,先求该括号内的值使这个括号出栈后变为一个数,然后再继续找括号。为了方便计算(毕竟你计算完之后直接在字符串里修改很不方便),我用了num数组记录当前数,sign数组记录对应num中每个数右边的符号(除括号外),左括号则用last数组(看作栈)记录它的位置。当找到一个右括号,last数组弹出栈顶左括号(假设深m,则m--),然后从左括号位置开始,到右括号位置即当前位置,先算乘方再算乘除最后算加减(具体怎么算看代码,这里有些难讲清)。最后枚举完一遍字符串所有括号就都算完了,但还要再枚举一遍把没括号的部分进行运算。

那么说说存数的方法,个位数的不用说:直接转成数字;多位数的则要判断前面一位是否是符号,如果是,存进num去,否则num=num*10+i;另外要特判第一个数是负数的情况。

代码:

#include#include#includeusing namespace std;string s;int n,m;int num[251];int last[251];char sign[251];int main(){cin>>s;for (int i=0;ilast[m];j--)if (sign[j]=='^'){sign[j]=0;int k=j;while (num[k]==-1) k--;num[k]=int(pow(double(num[k]),num[j+1])); //把值存在符号左边的数,保证所有运算结果向左推进num[j+1]=-1; //已算过,标记为-1p=false;break;}}p=false;while (!p){p=true;for (int j=last[m]+1;j<=n;j++)if (sign[j]=='*'){sign[j]=0;int k=j;while (num[k]==-1) k--;num[k]=num[k]*num[j+1];num[j+1]=-1;p=false;break;}else if (sign[j]=='/'){sign[j]=0;int k=j;while (num[k]==-1) k--;num[k]=num[k]/num[j+1];num[j+1]=-1;p=false;break;}}p=false;while (!p){p=true;for (int j=last[m]+1;j<=n;j++)if (sign[j]=='+'){sign[j]=0;int k=j;while (num[k]==-1) k--;num[k]=num[k]+num[j+1];num[j+1]=-1;p=false;break;}else if (sign[j]=='-'){sign[j]=0;int k=j;while (num[k]==-1) k--;num[k]=num[k]-num[j+1];num[j+1]=-1;p=false;break;}}m--; //左括号出栈}else if (s[i]>='0'&&s[i]<='9') //存数{if (i==0||(s[i-1]<'0'||s[i-1]>'9')) num[++n]=0;num[n]=num[n]*10+int(s[i])-48;}else //存符号{if (i==0) num[++n]=0;sign[n]=s[i];}bool p=false; //最后要记得再算一遍while (!p){p=true;for (int j=n;j>=1;j--)if (sign[j]=='^'){sign[j]=0;int k=j;while (num[k]==-1) k--;num[k]=int(pow(double(num[k]),num[j+1]));num[j+1]=-1;p=false;break;}}p=false;while (!p){p=true;for (int j=1;j<=n;j++)if (sign[j]=='*'){sign[j]=0;int k=j;while (num[k]==-1) k--;num[k]=num[k]*num[j+1];num[j+1]=-1;p=false;break;}else if (sign[j]=='/'){sign[j]=0;int k=j;while (num[k]==-1) k--;num[k]=num[k]/num[j+1];num[j+1]=-1;p=false;break;}}p=false;while (!p){p=true;for (int j=1;j<=n;j++)if (sign[j]=='+'){sign[j]=0;int k=j;while (num[k]==-1) k--;num[k]=num[k]+num[j+1];num[j+1]=-1;p=false;break;}else if (sign[j]=='-'){sign[j]=0;int k=j;while (num[k]==-1) k--;num[k]=num[k]-num[j+1];num[j+1]=-1;p=false;break;}}printf("%d",num[1]); //最后运算值存在num[1]}

原创粉丝点击