Github:https://github.com/YgR9710/Calculation
1. PSP2.1表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
Planning | 计划 | 120 | 240 |
· Estimate | · 估计这个任务需要多少时间 | 100 | 200 |
Development | 开发 | 2000 | 3000 |
· Analysis | · 需求分析 (包括学习新技术) | 200 | 300 |
· Design Spec | · 生成设计文档 | 60 | 60 |
· Design Review | · 设计复审 (和同事审核设计文档) | 60 | 60 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 60 | 60 |
· Design | · 具体设计 | 120 | 180 |
· Coding | · 具体编码 | 1800 | 2100 |
· Code Review | · 代码复审 | 10 | 20 |
· Test | · 测试(自我测试,修改代码,提交修改) | 60 | 60 |
Reporting | 报告 | 30 | 30 |
· Test Report | · 测试报告 | 60 | 60 |
· Size Measurement | · 计算工作量 | 30 | 30 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 30 |
合计 |
| 2620 | 3370 |
2需求:
1. 使用 -n 参数控制生成题目的个数。(实现)
2. 使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围。(实现)
3. 生成的题目中计算过程不能产生负数,也就是说算术表达式中如果存在形如e1 − e2的子表达式,那么e1 ≥ e2。(实现)
4. 生成的题目中如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数。(实现)
5. 每道题目中出现的运算符个数不超过3个。(实现
6. 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。(实现)
7.生成的题目存入执行程序的当前目录下的Exercises.txt文件。(实现)
8. 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件。(实现)
9. 程序应能支持一万道题目的生成。(实现)
10. 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计。(未实现)
3效能分析:
在生成表达式的时候用到了下列数据结构:
1.链表
用来存储生成的表达式,逆波兰式
2.栈
用来生成逆波兰式,计算逆波兰式的结果
3.二叉树
用来检查是否有重复表达式(消耗最大,因为需要从头进行比较)
4设计流程
1、先确定输入的参数
2、根据参数生成表达式(不符合要求的,例如重复,计算过程产生负数的均舍弃,重新生成)
3、将生成的普通表达式转换为逆波兰式(用栈实现)
4、生成逆波兰式的同时计算结果(用栈实现)
5、根据逆波兰式生成二叉树,实现查重
6、前面均无问题,则写入文件
5代码说明
1生成表达式
int MakeProgression(int n, int m, int line,LTList <list,int k) //n为取值范围,m为运算符个数
{
LkList list, p;
list = (LkList)malloc(sizeof(LinkList));
list->next = NULL;
p = list;
Elemtype ch, num;
ch.tag = 1;
num.tag = 0;
num.n.numerator = random(n);
num.n.denominator = 1;
num.n.coef = 0;
MakeList(p, num);
int i;
for (i = 1; i <= m; i++)
{
ch.e = op_Symbol[random(4)];
num.tag = 0;
num.n.numerator = random(n);
num.n.denominator = 1;
num.n.coef = 0;
if (Check1(ch.e, num.n.numerator))continue;
MakeList(p, ch);
MakeList(p, num);
}
LkList RePL, Opl;
RePL = (LkList)malloc(sizeof(LinkList));
Opl = (LkList)malloc(sizeof(LinkList));
RePL->next = NULL;
Opl->next = NULL;
if (ReversrPL(list, RePL, Opl) == FALSE)return FALSE;
ltlist[k] = Opl;
int j;
for (j = 1; j < k; j++)
{
if (isRepeat(list, ltlist[j]) == FALSE)return FALSE;
}
Elemtype result;
result.tag = 0;
if (Caculate(RePL, result) == FALSE)return FALSE;
ch.e = '=';
MakeList(p, ch);
MakeList(p, result);
p = list->next;
LkList pp;
while (p != NULL)
{
if (p->elem.tag == 1)printf(" %c ", p->elem.e);
else if (p->elem.tag == 0)
{
printf("%d", p->elem.n.numerator);
}
else if (p->elem.tag == -1)
{
printf("%d%c%d%c%d", p->elem.n.coef, p->elem.quo, p->elem.n.numerator, p->elem.e, p->elem.n.denominator);
}
if (p->next == NULL)pp = p;
p = p->next;
}
char str[100];
strcpy(str, "Exercises.txt");
WriteFILE(list->next, str, line);
strcpy(str, "Answers.txt");
WriteFILE(pp, str, line);
return TRUE;
}
2.建立链表存储
void MakeList(LkList &p, Elemtype E)
{
LkList pt;
pt = (LkList)malloc(sizeof(LinkList));
pt->next = NULL;
pt->elem.tag = E.tag;
if (E.tag == 1)
{
pt->elem.e = E.e;
}
else
{
pt->elem.n.coef = E.n.coef;
pt->elem.n.denominator = E.n.denominator;
pt->elem.n.numerator = E.n.numerator;
}
if (E.tag == -1)
{
pt->elem.e = E.e;
pt->elem.quo = E.quo;
}
pt->elem.tag = E.tag;
p->next = pt;
p = p->next;
return;
}
3.生成逆波兰式
int ReversrPL(LkList list,LkList &Rpl,LkList &Opl) //逆波兰式
{
LkList p;
p = list->next;
Stack s1, s2;
InitStack(s1, 20);
InitStack(s2, 20);
Elemtype E;
E.e = '#';
E.tag = 1;
PushStack(s1, E);
while (p != NULL)
{
if (p->elem.tag != 1)
{
PushStack(s2, p->elem);
}
else if(p->elem.tag==1)
{
if (getPri(p->elem.e) > getPri(s1.elem[s1.top - 1].e))
{
PushStack(s1, p->elem);
}
else
{
while (getPri(p->elem.e) <= getPri(s1.elem[s1.top - 1].e))
{
PopStack(s1, E);
PushStack(s2, E);
}
PushStack(s1, p->elem);
}
}
p = p->next;
}
while (s1.top != 1)
{
PopStack(s1, E);
PushStack(s2, E);
}
LkList pt;
pt = Rpl;
int ns2top = 0;
while (ns2top < s2.top)
{
MakeList(pt, s2.elem[ns2top++]);
}
LkList pn;
pn = Opl;
while (s2.top > 0)
{
PopStack(s2, E);
MakeList(pn, E);
}
s1.elem = NULL;
s2.elem = NULL;
return TRUE;
}
4.计算表达式结果
int Caculate(LkList Rpl, Elemtype &Result)
{
Stack s;
InitStack(s, 20);
LkList p;
p = Rpl->next;
Elemtype t1, t2;
t1.tag = 0;
t2.tag = 0;
while (p != NULL)
{
if (p->elem.tag == 0)
{
PushStack(s, p->elem);
}
else
{
PopStack(s, t1);
PopStack(s, t2);
switch (p->elem.e)
{
case '+':Addition(t2, t1, Result); break;
case '-':Subtraction(t2, t1, Result); break;
case '*':Multiplication(t2, t1, Result); break;
case '/':Division(t2, t1, Result); break;
default:break;
}
if (Result.n.denominator < 0 || Result.n.numerator < 0)return FALSE;
PushStack(s, Result);
}
p = p->next;
}
PopStack(s, Result);
if (Result.n.coef != 0)
{
Result.tag = -1;
Result.quo = '\'';
Result.e = '/';
}
s.elem = NULL;
return TRUE;
}
5.检查是否重复
int isRepeat(LkList ori,LkList cpa) //检查是否重复
{
LkList p ,pn;
p = ori->next;
pn = cpa->next;
pBiTree T1, T2;
T1 = CreateBiTree(p);
T2 = CreateBiTree(pn);
if (isEqual(T1, T2) == FALSE)return FALSE;
return TRUE;
}
6.写入文件
void WriteFILE(LkList List, char*filename ,int i) //写文件
{
FILE *fp;
fp = fopen(filename, "a+");
if (fp == NULL)
{
printf("无法打开此文件\n");
}
LkList p;
p = List;
char str[20];
itoa(i, str, 10);
fputs(str, fp);
fputc('.', fp);
while (p != NULL)
{
if (p->elem.tag == 1)
{
fputc(' ', fp);
fputc(p->elem.e, fp);
fputc(' ', fp);
if (p->elem.e == '=')break;
}
else if (p->elem.tag == 0)
{
itoa(p->elem.n.numerator, str, 10);
fputs(str, fp);
}
else if (p->elem.tag == -1)
{
itoa(p->elem.n.coef, str, 10);
fputs(str, fp);
fputc(p->elem.quo, fp);
itoa(p->elem.n.numerator, str, 10);
fputs(str, fp);
fputc(p->elem.e, fp);
itoa(p->elem.n.denominator, str, 10);
fputs(str, fp);
}
p = p->next;
}
fputs("\n", fp);
fclose(fp);
return;
}
8.主函数
int main(int argc, char*argv[])
{
RandomSeed();
void ClearFILE();
int range, line, cnum;
range = line = cnum = 0;
int i, temp;
for (i = 1; i < argc - 1; i++)
{
if (strcmp(argv[i], "-n") == 0)
{
line = atol(argv[i + 1]);
}
if (strcmp(argv[i], "-r") == 0)
{
range = atol(argv[i + 1]);
}
}
if (line == 0)line = MAXNUM;
if (range == 0)
{
printf("无取值范围,请输入 -r \n");
return 0;
}
LTList ltlist;
ltlist = (LTList)malloc(sizeof(LkList) * line);
if (ltlist == NULL)return -1;
int loop;
for (i = 1; i <= line;i++)
{
loop = MAXLOOP;
cnum = random(3) + 1;
printf("%d. ", i);
temp = MakeProgression(range, cnum, i, ltlist, i-1);
while (temp == FALSE && loop >= 0)
{
temp = MakeProgression(range, cnum, i, ltlist, i - 1);
if (--loop < 0)break;
}
if (loop < 0)
{
printf("ERROR\n");
break;
}
printf("\n");
}
return 0;
}
6测试运行
7项目小结
这次的需求比较多,过程也相对要复杂,要考虑各种可能出现的情况。虽然总体思路比较清晰,但是一开始编码,运行就会出各种问题,所以调试的时间远远大于编码的时间。尽管功能还不够全面,但是实现出来的部分就是收获。因此,要提高设计思想,算法思想,和编程技巧,才能够将项目做得更好。