完成人员 | 学号 |
---|---|
李锋泉 | 3121005173 |
牛奕飞 | 3121005180 |
1.作业的基本信息
作业所属课程 | 软件工程 |
---|---|
作业要求 | 结对编程:小学四则运算 |
作业目标 | 实现一个自动生成小学四则运算题目的命令行程序(也可以用图像界面,具有相似功能) |
2.作业地址
https://gitcode.net/qq_62309055/four-rule-operation
3.PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 15 | 20 |
Estimate | 估计这个任务需要多少时间 | 1000 | 750 |
Development | 开发 | 200 | 160 |
Analysis | · 需求分析 (包括学习新技术) | 120 | 180 |
Design Spec | · 生成设计文档 | 30 | 25 |
Design Review · | 设计复审 | 30 | 40 |
Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 10 | 10 |
Design · | 具体设计 | 90 | 100 |
Coding · | 具体编码 | 400 | 450 |
Code Review | · 代码复审 | 40 | 40 |
Test | · 测试(自我测试,修改代码,提交修改) | 180 | 185 |
Reporting | 报告 | 150 | 165 |
Test Report | 测试报告 | 60 | 65 |
Size Measurement | · 计算工作量 | 10 | 10 |
Postmortem & Process Improvement Plan · | 事后总结, 并提出过程改进计划 | 20 | 25 |
合计 | 1200 | 1150 |
4.效能分析
5.设计实现过程
本次设计程序我们采取了面向对象的方法进行编程,对于整个程序进行分析,我们以生成题目、计算答案、校对答案三个功能把它分为了三个模块构造了四个类,其中BinaryTree类主要服务于Product类实现生成题目的功能
第一个类: BinaryTree类
该类有两个功能:生成二叉树和检查两颗二叉树是否相同
生成二叉树: 是将传入的后缀表达式列表用二叉树进行存储
检查两颗二叉树是否相同:实现的方法是基于递归的方法进行遍历结点
本类是为了Product类的def isRepeat(self, express_set, expression)函数服务的,在Product类为了避免生成重复的表达式,采用了基于二叉树的形式进行查重!
第二个类: SuffixExpression类
该类的功能如下:
1、将中缀表达式转化为后缀表达式(def toSuffix(self))
2、 计算后缀表达式的值( def suffixToValue(self): )
第三个类:Product类
功能是生成要求的四则运算式子。
对于实现生成式子功能,我们把式子的各个要素分别构建方法进行生成,式子可能包含的要素分别为:整数、分数、括号、运算符。
其中分数的生成是较为复杂的,因为题目要求生成的都是真分数,所以在生成分数后我们有构建了一个方法把假分数转换为带分数
第四个类:Answer类
功能是:
调用SuffixExpression类进行计算得出答案文档
校对提交的答案
6.代码说明
1.生成题目
实现思路:
随机生成参数列表和运算符列表
判断算式是否存在括号
if 存在不括号:
返回获取到的无括号算式
else:
返回获取到的括号算式
算式存在括号
括号数为1时
利用 **random.randint(0, len(op_list) - 1)**来决定左括号的位置
利用 **random.randint(left_bracket_index + 1, len(parameter_list) - 1)**来决定右括号的位置
括号数为2时
随机获取括号类型
if 括号类型为并列:
循环获取参数列表和运算符列表获取到算式时,在相应的的位置插入括号,即:( A +B ) + ( C + D )
else 括号类型为嵌套:
先确定外层括号的位置,再利用递归,传递外层括号里的子字符串,从而确定内从括号,最终得到嵌套括号的算式
流程图
代码截图:
2. 计算
实现思路
先处理算式,得到参数和操作符组成的列表,例如:' 1 + 2' 处理成 ['1', '2', '3']
创建数字栈和操作符栈
进行循环获取算式列表
如果是数字则压入数字栈
如果是操作符
while True 的循环
如果操作符栈为空,或者运算符为 '(' 时
入栈,break
如果当前操作符的优先级比栈顶操作符的优先级高
入栈,break
如果当前操作符为 ')',且栈顶操作符为 '('
'(' 出栈,丢掉 ')',break
如果当前操作符的优先级比栈顶操作符的优先级低
获得数字栈最后两个元素、操作符栈最后一个元素,进行计算
如果除数为零、被除数大于除数、结果为负数
return Error
得到结果入栈
if 循环之后如果数字栈和操作符栈还有内容
while 直到操作符栈不为空:
计算
如果除数为零、被除数大于除数、结果为负数,return Error
得到的结果入栈
数字栈的元素就是计算得出的结果
流程图
代码截图
7.测试运行
8.项目小结
1.对于结对项目的实操是给我们团队编程的一次训练,团队合作可能成员实力有强有弱,这时候能力较强的可能要付出多一点教导能力较弱的成员,两人一个学习一个复习,共同进步。
2.合作方面:开发前二人进行较多的讨论,通过事先调研、二人讨论确定本次开发所需要的技术,并 确定各自任务和合作内容。两人合作可以发现各自无法发现的bug,并互相促进更进进度。结对编程重要的还是交流与互助!
3.遇到的困难主要是数组越界,通过严谨的检查以及步步验证的方式找出了错误并解决了。另一个须待解决的问题是生成题目的速度有些缓慢,因此完善了多次的算法来提高代码的执行效率。
4.总的来说,在结对编程中我们有各自的想法,通过代码的形式来进行人与人之间的交流不失为一种好的方法,在这个过程中我们培养了团队协作的能力和与他人交际的能力,同时也促使自身的编程能力不断提高,这使我们都受益匪浅。