高级软件工程第二次作业--四则运算生成器
1 项目 GitHub 地址
https://github.com/shuangshuanggit
2 预估耗时与实际耗时
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 60 |
· Estimate | · 估计这个任务需要多少时间 | 120 | 240 |
Development | 开发 | 300 | 780 |
· Analysis | · 需求分析 (包括学习新技术) | 30 | 40 |
· Design Spec | · 生成设计文档 | 0 | 0 |
· Design Review | · 设计复审 (和同事审核设计文档) | 0 | 30 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 0 | 0 |
· Design | · 具体设计 | 30 | 60 |
· Coding | · 具体编码 | 120 | 500 |
· Code Review | · 代码复审 | 60 | 30 |
· Test | · 测试(自我测试,修改代码,提交修改) | 60 | 120 |
Reporting | 报告 | 180 | 150 |
· Test Report | · 测试报告 | 150 | 120 |
· Size Measurement | · 计算工作量 | 10 | 10 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 20 | 20 |
合计 | 510 | 990 |
3 解题思路
为了稍微好上手,还是选择了最熟悉的C语言。
1.根据要求,随机生成四则运算的长度(操作符个数小于10),n=rand()%10+1,生成操作数个数;
2.操作数随机生成,保存在整形数组a[n]中,其中a[2i]时保存的1~100的数字,rand()%100+1,所以后面不会再考虑除数是否为0;
3.把分数也看成除法,所以整个式子就是整数的加减乘除,在这里,把a[2i+1]里面的数看成操作符,rand()%4-4,随机生成的-4、-3、-2、-1分别代表“+”、“-”、“*”、“/”;
4.能够保存用户的输入,并判断对错,我的想法是把最后结果转化为字符串,用户的输入也用字符串保存(如果输入为整数则只与最后结果‘/’之前的字符串进行比较),进行字符串匹配,判断是否正确;
5.计算正确率,只需要用一个count来记录即可,最后count*100/n,然后用%.2f表示即可;
6.其中关键就是如何计算这个四则运算式,在我考虑了乱七八糟的很长时间后,室友提醒我用逆波兰式,然后就百度,看了一位博主的分析,原理分析很细致,然后就顺着这个思路来往下继续写。主要是将结果保存在另外一个整型数组中,得到最终结果后,转化为字符串。
总结一下,大致为: 随机运算符个数、随机操作数、随机运算符保存在数组中-->然后转化为后缀表达式-->计算后缀表达式-->与输入的结果进行匹配
4设计实现和代码说明
有4个被调函数,生成表达数create()函数,转换后缀表达式trans()函数、后缀表达数计算calculate()函数、最大公约数gcd()函数(用于分数化简)。
4.1 随机运算符个数、操作符、运算符的生成
C语言中有生成随机数的函数,因为对每句代码如何写还是不知道,所以每写一句就会百度一下,过程中才知道应该使用srand()函数,然后写在主函数中:
void int main() { int n,i,c; printf("请输入需要生成的四则运算式的个数:"); scanf("%d",&c); for(i=0;i<n;i++) { srand( (unsigned int)time( NULL ) ); //初始化随机数 n=rand()%10+1;//随机生成表达式长度,有1~10个操作符 //生成运算表达式等等操作 } //其他操作 }
4.2生成运算表达式
随机生成四则运算表达式create()函数:
int create(int n,int a[]) { //首先随机生成一个运算表达式 int m,i,j,t,top=0; m=2*(n-1);//表达式有多少个操作数,就要用相应长度的数组来保存 //随机生成表达式 for(i=0;i<=m;i++) { if(i%2==0) { a[i]=rand()%100+1;//1~100之间的数,所以后面也无需判断除数是否为零。 } else { j=rand()%4-4;//因为用整型保存,所以使用-4,-3,-2,-1分别表示+,-,*,/ a[i]=j; } if(a[i]==-4) printf("%c",'+'); else if(a[i]==-3) printf("%c",'-'); else if(a[i]==-2) printf("%c",'*'); else if(a[i]==-1) printf("%c",'/'); else printf("%d",a[i]);//输出表达式 } printf("=\n"); }
4.3转化为后缀表达式
转化为后缀表达式trans()函数:
int trans(int n,int *a) { int i=0,j=0,top=0; int t=a[i++]; //保存当前a[i]的值 int b[2*(n-1)];//保存后缀表达式 int stack[2*(n-1)];//作为栈使用 while(i<=2*(n-1)) { switch(t) { case -4:/*判定为加减号*/ case -3: while(top!=0) { b[j]=stack[top]; top--;j++; } top++; stack[top]=t; break; case -2: case -1: while(stack[top]==-2||stack[top]==-1) { b[j]=stack[top]; top--;j++; } stack[++top]=t; break; default://默认为数字 while(t>=0&&t<=100) { b[j]=t;j++; t=a[i];i++; } } } while(top!=0) { b[j]=stack[top]; j++;top--; } }
4.4计算后缀表达式
计算后缀表达式calculate()函数,将第一个数保存在r[3]中。r[1]固定为-1,代表除号,用户每次计算都是取一个操作数与r[0](分子)或者r[2](分母)进行运算;
//计算后缀表达式,并将结果转化为字符串 void calculate(int n,int b[],char rs1[]) { int i=0,t,top=0; int stack[2*(n-1)]={0}; int r[3]={0,-1,1};//保存最后结果,初始情况下,分子为0,分母为,1 //rs1保存最后正确结果的分子 char rs2[2*(n-1)]={' '};//最后结果的分母用字符串表示 t=b[i];i++; while(i<=2*(n-1)) { switch(t) { case -4:r[0]=r[0]+stack[top]*r[2];top--;break;//+ case -3:r[0]=stack[top]*r[2]-r[0];top--;break;//- case -2:r[0]=r[0]*stack[top];top--;break;//* case -1:r[2]=r[2]*stack[top];top--;break; default: top++;stack[top]=t; } t=b[i++]; } //化简最终结果 r[0]=r[0]/gcd(r[0],r[2]); r[2]=r[2]/gcd(r[0],r[2]); //将整形转化成字符串 itoa(r[0],rs1,10); itoa(r[2],rs2,10); strcat(rs1,"/");//字符串拼接 strcat(rs1,rs2); }
4.5求最大公约数
为了化简最后的分数,所以写了一个求最大公约数的函数。
5.运行结果
运行结果如图:因为之前没有报错,然后就一直在写,只是写的被调函数trans()的测试程序发现闪退,找不到原因,然后想起来用VS测试,但是发现现在来不及了。所以整个代码现在是,没有错,但是跑不出结果的状态,等后面再补充!!!
6.项目小结
虽然是个很小的项目,再看了其他同学的博客后,很多都说很简单,最开始没有形成具体的思路,所以一下子上手总是卡壳。最开始想的是生成的运算符就用字符串保存,后面自己进行不下去了。后面想着看一下其他同学的代码,从他们规范的定义到用重载,这些或许在老师看来很简单的东西,我一下子都有点懵,现在想想,一个星期这么长时间,自己静下心来,足以把这个东西搞明白,但是我没有想其他同学那样,遇到问题,能静下心来一点一点分析,最后自己把知识点琢磨透彻。于是就按照自己特别low的想法来一步一步写,最后的最后还是出现很多问题,这个程序思路很简单,代码量也很小,但是就是出现没有错误,运行不出来的情况,然后我才想起来没有做测试,于是就单独对每个被调函数测试,发现是转化为后缀表达式trans()函数有问题。后面计算函数依然是这样。慢慢体会到测试的重要性,并且也明白,在编程阶段,不能确保当前代码正确的实现功能的时候,千万不能继续往下赶。还有就是同样时间,自己却没有做出来,学习方法和学习策略确实有问题,下来会和同学多交流,也会继续把这个代码结果跑出来。