C语言实现四则运算
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项目小结
这次的需求比较多,过程也相对要复杂,要考虑各种可能出现的情况。虽然总体思路比较清晰,但是一开始编码,运行就会出各种问题,所以调试的时间远远大于编码的时间。尽管功能还不够全面,但是实现出来的部分就是收获。因此,要提高设计思想,算法思想,和编程技巧,才能够将项目做得更好。