结对项目
这个作业属于哪个课程 | 软件工程 |
---|---|
这个作业要求在哪里 | 结对项目 |
这个作业的目标 | 实现一个自动生成小学四则运算题目的命令行程序 |
Github 链接 | https://github.com/eee-qxxtg/3219005450_3219005452 |
成员 | 学号 |
---|---|
周心怡 | 3219005452 |
邱秀文 | 3219005450 |
1. 接口的设计与实现过程
-
核心算法
-
题目限制了生成的提名的数字最多为3个,运算符便设计为1-3个。
-
通过randint随机生成指定的数,并判断生成什么符号,然后插入数字生成表达式。
-
确定计算的优先级,并通过括号将其标记出来,视为中缀表达式,然后再将其转为前缀表达式。
-
将前缀表达式转化为二叉树,并对二叉树重新排序,规则:左节点的计算值小于右节点的计算值。
-
输出唯一表达式。
-
判断最终二叉树结果是否为False,若是,则抛弃此表达式,否则判断此表达式是否重复,不重复则加入题目数组中。
-
-
关键函数
- main.py中定义的类:
类名 功能 TreeNode类 树的节点类 Expression类 生成表达式 - main.py中定义的函数:
函数名 功能 main() 主函数 calculate_gcd(a, b) 辗转相除法求最大公因数 reduce_fraction(factor) 对分数进行约分 true_fraction(numerator, denominator) 将分子大于分母的分数化为真分数 infix_prefix(str_list) 中缀表达式转化为前缀表达式 judge_priority(op) 判断运算符的优先级 normalize_num(num) 对分数进行约分并将数字规范化 operate(a, operator, b) 两数运算结果为负数、除数或者分母为0时,返回 False num_test(num) 测试题目中计算过程是否产生负数及形如a÷ b的表达式的计算结果是否为真分数 tree_prefix(tree) 将树化为前缀表达式 prefix_tree(expression) 将前缀表达式转化为二叉树 sort_tree(tree) 对树每一个节点进行计算并将树按照一定规则进行重排序 fraction_maker() 生成分数 num_maker() 生成符合要求的数 operator_maker() 生成运算符 operand_num() 确定操作符数量 add_brackets(expression) 加括号 prefix_expression() 生成前缀表达式 -
运行结果
此处采用最大值为10,题目数为20为例:
- 题目文件
- 答案文件
结果:没有假分数,没有负数,没有重复,生成了答案和问题文件,且答案正确。
2. 性能分析
- 使用pycharm自带的profile方法进行性能分析
- 代码覆盖率:
代码未覆盖部分主要出现在if语句和异常处理语句,条件不满足时,代码未全覆盖。例如true_fraction(numerator, denominator)函数,它的功能是将假分数化成真分数,然而随机生成的数不一定为假分数,所以该方法后面的代码便没有执行;通过infix_prefix()函数有些表达式被抛弃了,所以部分代码也不执行;其它部分基本接近100%。
3. 单元测试
-
新建单元测试文件test.py
import unittest import four_arithmetic # 部分函数测试 class MyTestCase(unittest.TestCase): def setUp(self): self.calculate_gcd = four_arithmetic.calculate_gcd self.reduce_fraction = four_arithmetic.reduce_fraction self.true_fraction = four_arithmetic.true_fraction self.operate1 = four_arithmetic.operate self.operate2 = four_arithmetic.operate self.num_test2 = four_arithmetic.num_test self.num_test3 = four_arithmetic.num_test self.normalize_num = four_arithmetic.normalize_num def tearDown(self): self.calculate_gcd = None self.reduce_fraction = None self.true_fraction = None self.operate = None self.num_test = None self.normalize_num = None def test(self): self.assertEqual(self.calculate_gcd(100, 125), 25) self.assertEqual(self.reduce_fraction("24/44"), "6/11") self.assertEqual(self.true_fraction("18", "16"), "1’1/8") self.assertEqual(self.operate1("-4", '+', "3"), False) self.assertEqual(self.operate2("10", '/', "0",), False) self.assertEqual(self.num_test2("22/2"), False) self.assertEqual(self.num_test3("6/7"), True) self.assertEqual(self.normalize_num("1’2/5"), "7/5") def suite(): s = unittest.TestCase() s.addTest(MyTestCase('test')) return s if __name__ == '__main__': unittest.main()
-
测试结果
4. 问题与不足
-
在判断表达式是否重复的地方遇到了问题,最后决定采取前缀表达式转为特定二叉树来生成唯一表达式来判断表达式是否重复;其中一个难点是二叉树的重新排序,我们通过增添了result成员来放置该点位的结果,如果是符号,则计算其下面子树的结果,如果是数值则放置数值本身,通过这个方法来比较左右的大小。另外,在实行中缀表达式转为前缀表达式时,刚开始因为左右括号的问题纠结了一下,最后还是解决了,具体是,如果遇到),则直接入栈,如果遇到(,则将前面一个)和之间的都输出。
-
不能使用input函数,所以在测试时,手动改成了value_max=10,exercises_num=20,修改后程序正常运行。
-
因时间关系,部分需求未实现。
5. PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 15 | 10 |
Estimate | 估计这个任务需要多少时间 | 1565 | 1335 |
Development | 开发 | 1550 | 1325 |
Analysis | 需求分析 (包括学习新技术) | 200 | 120 |
Design Spec | 生成设计文档 | 60 | 30 |
Design Review | 设计复审 | 20 | 25 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 20 | 30 |
Design | 具体设计 | 60 | 75 |
Coding | 具体编码 | 800 | 740 |
Code Review | 代码复审 | 60 | 70 |
Test | 测试(自我测试,修改代码,提交修改) | 120 | 90 |
Reporting | 报告 | 90 | 60 |
Test Repor | 测试报告 | 45 | 30 |
Size Measurement | 计算工作量 | 15 | 10 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 60 | 45 |
合计 | 1565 | 1335 |
6. 项目小结
- 周心怡个人小结
不足:
- 对python不太熟悉,很多地方其实有更快捷的方法,但是因为之前不了解所以写的比较效率低且慢
- 对数据结构学习不到位
- 测试部分做的不太顺畅
收获:
- 与搭档的团队合作能力有了很大的提升,更加知道了一个项目里应该如何与他人合作,收获了一份更加坚固的友谊
- 技术上的进步,对python和数据结构的了解更加深入且熟练
- 实践巩固,将之前学习到的内容运用到了这个项目里面
总之,这次结对项目虽然时间有点赶,内容有点重,但是在我们努力肝完项目之后,感觉还是收获满满的,不仅仅是技术的熟练,我觉得在团队合作中写代码的细节和与人相处的情商更加重要。
- 邱秀文个人小结
本次结对编程用到了二叉树、列表、二叉树判定重复、表达式的转换等等,让我复习旧知识的同时学习到了不少新知识。这次的合作编程令我受益匪浅,让我知道了合作时沟通的重要性,在项目开发前需要和搭档进行较多的讨论,事先确定各自的任务和合作的内容,商量要编写的模块,以免最后无法整合。在开发过程中,要注意代码规范,要编写注释,这样才能方便搭档了解代码的功能和用途。总而言之,结对编程需要交流互助,通过搭档,可以轻易发现各自程序中的bug,双方相互督促、相互提醒,使项目更加顺利地完成。