结对项目
这个作业属于哪个课程 | 计科22级12班 |
---|---|
这个作业要求在哪里 | 个人项目 |
这次作业的目标 | 完成一个论文查重的个人项目 |
github仓库地址
团队成员
团队成员 | 学号 |
---|---|
肖睿 | 3122004921 |
麦麦提萨力江·卡西木 | 3122004915 |
1、PSP
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 20 |
Estimate | 估计这个任务需要多少时间 | 210 | 310 |
Development | 开发 | 120 | 240 |
Analysis | 需求分析(包括学习新技术) | 60 | 30 |
Design Spec | 生成设计文档 | 10 | 10 |
Design Review | 设计复审 | 10 | 10 |
Coding Standard | 代码规范(为目前的开发制定合适的规范) | 10 | 10 |
Design | 具体设计 | 10 | 20 |
Coding | 具体编码 | 315 | 630 |
Code Review | 代码复审 | 10 | 10 |
Test | 测试(自我测试,修改代码,提交修改) | 30 | 60 |
Reporting | 报告 | 30 | 60 |
Test Repor | 测试报告 | 30 | 30 |
Size Measurement | 计算工作量 | 10 | 20 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 30 | 60 |
合计 | 915 | 1520 |
2、设计实现过程
设计原理
为实现小学四则运算题目出题程序,我们用随机生成后缀表达式,判断是否重复后,转换为中缀表达式,计算结果,并输出题目和答案至文档,统计用户的作答情况。
实现过程
随机生成后缀表达式
通过入栈出栈操作组成算式,生成过程中确保除数不为0,确保相邻的操作数之间有运算符,确保最后一个元素不为操作符,使生成的表达式合法,并确保式子结果不为负数。
判断后缀表达式是否重复
每生成一个后缀表达式,就将生成的后缀表达式存入列表,下次生成表达式就先判断列表中是否已存在,存在即重复,重新生成后缀表达式。
将后缀表达式转换为中缀表达式
通过栈类型来实现。
输出题目和答案至文档
为实现分数运算,将所有数字转化为fractions.Fraction类型,将假分数转化为带分数,跟运算符结合成中缀表达式,写入题目文档,计算答案,写入答案文档。
读取题目及作答文档并导出作答情况
读取题目文件内容,将数字读入存为fractions.Fraction类型,将带分数转化为整数加分数,跟运算符结合成中缀表达式,计算结果,与作答结果比较,导出作答情况
一个functions类中主要有5个函数
分别为gen_writ(),get_ans(),generate_expression(),to_show_infix(),gen_fraction()
关键函数为to_show_infix(expression)函数
流程图如下
3、效能分析
使用pycharm专业版自带的profile插件进行性能分析
由上图可知程序中消耗资源占比最大的函数为to_show_inix
4、代码说明
下面是三个重要的函数,作用分别是生成随机的后缀表达式,将后缀表达式转换为中缀表达式和计算运算结果。
def generate_expression(self, max_num):
stack = []
# 随机生成表达式的长度
for i in range(random.randint(3, 10)):
if len(stack) >= 2:
# 随机选择两种操作:加入一个操作符或者进行一次运算
if random.randint(0, 1) == 1:
# 随机选择一个运算符
operator = Functions.random_operator(self)
operand2 = stack.pop()
operand1 = stack.pop()
# 确保除数不为0
if operator == '÷' and operand2 == '0':
operand2 = Functions.gen_number(self, max_num)
stack += [operand1, operand2, operator]
else:
# 添加一个操作数
# 确保相邻的操作数之间有运算符
if isinstance(stack[-1], str):
stack.append(Functions.random_operator(self))
stack.append(Functions.gen_number(self, max_num))
else:
# 第一个操作数
stack.append(Functions.gen_number(self, max_num))
# 确保最后一个元素不为操作符
if isinstance(stack[-1], str):
stack.pop()
return stack
def to_show_infix(self, expr):
expression = Functions.get_show_hou(self, expr)
stack = []
for token in expression:
if token in Functions.operators:
if len(stack) >= 2:
operand2 = stack.pop()
operand1 = stack.pop()
# 添加括号,保证运算顺序
stack.append(f"({operand1} {token} {operand2})")
else:
operand = stack.pop()
if len(stack) > 0 and isinstance(stack[-1], list):
# 将操作数添加到前一个表达式中
stack[-1].append(token)
stack[-1].append(operand)
elif len(stack) > 0:
# 两个操作数和一个运算符组成一个表达式
stack.append([stack.pop(), token, operand])
else:
# 第一个操作数
stack.append(operand)
else:
# 操作数入栈
stack.append(token)
if len(stack) == 1 and isinstance(stack[0], list):
# 如果只有一个表达式,则返回这个表达式
stack = stack[0]
return stack
def get_ans(self, expr, note=1):
frac = "Fraction("
if note == 1: # 生成表达式时使用
infix_expression = Functions.to_show_infix(self, expr) # 后缀转中缀
expression = infix_expression[0]
else: # 读取表达式时使用
expression = expr
# print("中缀表达式:", infix_expression)
formul1 = Functions.tranc(self, expression) # x换成*
# print(formul1)
formul1 = Functions.first(self, formul1) # 分数的/换,
formul2 = ''
flag = 0
length = len(formul1)
for i in range(length): # 将带分数的‘换为+
if formul1[i] == "'":
formul2 += '+'
continue
if formul1[i] not in Functions.numb and formul1[i] != "'":
formul2 += formul1[i]
continue
if formul1[i] in Functions.numb and formul1[i - 1] not in Functions.numb: # 读取到的数拼接成分数函数,并看情况加括号
formul2 = formul2 + '(' + frac + formul1[i]
if formul1[i + 1] not in Functions.numb and formul1[i + 1] != "'":
formul2 = formul2 + ')' + ')'
elif formul1[i + 1] not in Functions.numb and formul1[i + 1] == "'":
formul2 += ')'
flag = 1
continue
elif formul1[i] in Functions.numb:
formul2 = formul2 + formul1[i]
if formul1[i + 1] not in Functions.numb and formul1[i + 1] != "'":
if flag == 1:
formul2 = formul2 + ')' + ')' + ')'
flag = 0
else:
formul2 = formul2 + ')' + ')'
elif formul1[i + 1] not in Functions.numb and formul1[i + 1] == "'":
formul2 = formul2 + ')'
flag = 1
continue
formul2 = Functions.tranz(self, formul2) # ÷换成/
# print(formul2)
ans = eval(formul2)
return ans
5、测试运行
参数缺失
参数范围不正确
正确输入参数
6、项目小结
团队成员和工作内容:
团队成员 | 工作内容 |
---|---|
肖睿 | 主函数的实现,性能分析,撰写博客 |
麦麦提萨力江·卡西木 | 功能函数的实现 |
收获内容:
项目管理: 项目的规划和管理对于两位成员都是一次宝贵的经验。他们学会了如何分配任务、制定计划并按时完成工作。
实际应用开发: 这个项目使两位成员有机会将编程和软件开发技能应用到实际项目中,从而更好地理解了如何创建有用的应用程序。
问题解决能力: 在项目中,他们不仅要编写代码,还需要解决各种问题和挑战。这锻炼了他们的问题解决能力。