目录
Gitcode项目地址
姓名 | 学号 | gitcode地址 |
---|---|---|
吴凯越 | 3121005011 | https://gitcode.net/qq_63808826/3121005011 |
郭远锭 | 3121004995 |
PSP表格
Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|
计划 | 30 | 10 |
估计这个任务需要多少时间 | 30 | 20 |
开发 | 60 | 60 |
需求分析 (包括学习新技术) | 30 | 30 |
生成设计文档 | 30 | 10 |
设计复审 | 30 | 10 |
代码规范 (为目前的开发制定合适的规范) | 30 | 30 |
具体设计 | 30 | 60 |
具体编码 | 600 | 900 |
代码复审 | 30 | 20 |
测试(自我测试,修改代码,提交修改) | 60 | 100 |
报告 | 30 | 60 |
测试报告 | 30 | 60 |
计算工作量 | 30 | 40 |
事后总结, 并提出过程改进计划 | 30 | 30 |
合计 | 1050 | 1440 |
效能分析
自动生成四则运算题目的函数调用情况如下:
自动查答案的函数调用情况如下:
可见程序除了用户输入占用了绝大部分的运行时间,其余时间打都花费再重复生成题目以及文件读写上。
设计实现过程
通过random模块及fractions模块来产生随机数,随机的运算符,以及随机的分数,再通过二叉树这种数据结构来形成随机的四则运算式子,再通过判断是否同构来避免题目重复。
程序代码包括有两个类:
class Number: # 数字结构体
class BinaryTree: # 二叉树结构体
数字结构体定义了生成随机数的方法,二叉树结构体中定义了中序遍历并输出的结点内容到一个列表中的方法
程序主要的函数有:
# 判断树是否同构
def isOmorphic(t1,t2):
# 随机生成题目
def generate_topic(min,max):
# 将topic列表转换为字符串
def str_topic(t):
# 重复生成题目
def repeat(n,min,max): # n为生成题目的数量
其中重复生成题目的repeat函数同调用随机生成题目的 generate_topic函数以及判断是否同构的isOmorphic函数来完成
代码说明
class Number: # 数字结构体
def __init__(self):
self.number_sign = 0 # 数的类型
self.numerator = 0 # 分子
self.denominator = 1 # 分母
def generate_number_sign(self): # 随机生成数的类型,类型值为1时分母默认为1
self.number_sign = random.randint(1,2)
def generate_numerator(self,min,max): # 随机生成分子的大小
self.numerator = random.randint(min,max)
def generate_denominator(self,min,max): # 随机生成分母的大小
self.denominator = random.randint(min,max)
通过此结构体产生随机的计算数
class BinaryTree: # 二叉树结构体
def __init__(self, rootObj):
self.key = rootObj
self.leftChild = None
self.rightChild = None
def insert_left(self,newRoot): # 插入左子树
if(self.leftChild == None):
self.leftChild = BinaryTree(newRoot)
else:
t = BinaryTree(newRoot)
t.leftChild = self.leftChild
self.leftChild = t
def insert_right(self,newRoot): # 插入右子树
if(self.rightChild == None):
self.rightChild = BinaryTree(newRoot)
else:
t = BinaryTree(newRoot)
t.rightChild = self.rightChild
self.rightChild = t
def get_leftChild(self): # 返回左孩子
return self.leftChild
def get_rightChild(self): # 返回右孩子
return self.rightChild
def set_root(self,Obj): # 修改当前结点的内容
self.key = Obj
def get_Root(self): # 返回当前结点的内容
return self.key
def inorder(self): # 中序遍历
if self.leftChild:
self.leftChild.inorder()
if self.key:
# print(self.key, end=' ')
topic.append(self.key)
if self.rightChild:
self.rightChild.inorder()
# 判断树是否同构
def isOmorphic(t1,t2):
if t1==None and t2==None: return True
if (t1!=None and t2==None) | (t1==None and t2!=None):
return False
if t1.key != t2.key:
return False
if t1.leftChild==None and t2.leftChild==None:
return isOmorphic(t1.rightChild,t2.rightChild)
if t1.leftChild!=None and t2.leftChild!=None and t1.leftChild.key==t2.leftChild.key:
return isOmorphic(t1.leftChild,t2.leftChild) and isOmorphic(t1.rightChild,t2.rightChild)
else:
return isOmorphic(t1.leftChild,t2.rightChild) and isOmorphic(t1.rightChild,t2.leftChild)
通过二叉树这种结构体来存储随机产生的四则运算式子的各个部分,并通过中序遍历来得到四则运算四则,再通过判断是否同构来辨别题目是否会通过通过有限次交换变成同一个题目。
# 随机生成题目
def generate_topic(min,max):
size = topic_size()
# size = 1
if size == 2:
operator = generate_operator()
t = BinaryTree(operator)
a = Number()
b = Number()
a.generate_number_sign()
if a.number_sign == 1:
a.generate_numerator(min,max)
else:
a.generate_numerator(min,max)
a.generate_denominator(min,max)
b.generate_number_sign()
if b.number_sign == 1:
b.generate_numerator(min,max)
else:
b.generate_numerator(min,max)
b.generate_denominator(min,max)
t.insert_left(Fraction(a.numerator,a.denominator))
t.insert_right(Fraction(b.numerator,b.denominator))
else:
operator = generate_operator()
t = BinaryTree(operator)
if size == 1:
operator = generate_operator()
t.insert_left(operator)
a = Number()
b = Number()
c = Number()
c.generate_number_sign()
if c.number_sign == 1:
c.generate_numerator(min, max)
else:
c.generate_numerator(min, max)
c.generate_denominator(min, max)
t.insert_right(Fraction(c.numerator, c.denominator))
t1 = t.leftChild
a.generate_number_sign()
if a.number_sign == 1:
a.generate_numerator(min, max)
else:
a.generate_numerator(min, max)
a.generate_denominator(min, max)
t1.insert_left(Fraction(a.numerator, a.denominator))
b.generate_number_sign()
if b.number_sign == 1:
b.generate_numerator(min, max)
else:
b.generate_numerator(min, max)
b.generate_denominator(min, max)
t1.insert_right(Fraction(b.numerator, b.denominator))
else:
operator = generate_operator()
t.insert_right(operator)
a = Number()
b = Number()
c = Number()
a.generate_number_sign()
if a.number_sign == 1:
a.generate_numerator(min, max)
else:
a.generate_numerator(min, max)
a.generate_denominator(min, max)
t.insert_left(Fraction(a.numerator, a.denominator))
t2 = t.rightChild
b.generate_number_sign()
if b.number_sign == 1:
b.generate_numerator(min, max)
else:
b.generate_numerator(min, max)
b.generate_denominator(min, max)
t2.insert_left(Fraction(b.numerator, b.denominator))
c.generate_number_sign()
if c.number_sign == 1:
c.generate_numerator(min, max)
else:
c.generate_numerator(min, max)
c.generate_denominator(min, max)
t2.insert_right(Fraction(c.numerator, c.denominator))
return t
函数通过给随机生成一层或两层的二叉树,并通过给规定的结点随机赋予规定的初值并返回该二叉树
topic = [] # 用于储存生成题目的字符及计算数字
def str_topic(t): # 将topic列表转换为字符串
length = len(topic)
# print(length)
if len(topic) == 5:
a = topic.index(t.key)
if a == 3 and (topic[3] == '*' or topic[3] == '/') and (topic[1] == '+' or topic[1] == '-'):
topic.insert(0,'(')
topic.insert(4,')')
elif topic[1] != topic[3]:
topic.insert(2,'(')
topic.insert(6,')')
if len(topic) == 3:
str = '{} {} {}'.format(topic[0],topic[1],topic[2])
elif len(topic) == 5:
str = '{} {} {} {} {}'.format(topic[0],topic[1],topic[2],topic[3],topic[4])
else:
str = '{} {} {} {} {} {} {}'.format(topic[0],topic[1],topic[2],topic[3],topic[4],topic[5],topic[6])
return str
被赋初值的二叉树通过中序遍历将四则运算式子输出到topic列表中,该函数可以将topic列表中的各个元素整合成格式合适的字符串以便于对四则运算式子进行运算及输出
测试运行
生成题目功能的代码覆盖率如下:
题目检错功能的代码覆盖率如下:
由两部分功能的代码覆盖率及程序程序题目生成功能与答案检错功能的相对独立可得程序整体代码覆盖率相对较高
测试用例1
结果如下:
Exercises文本如下:
Answers文本如下:
测试用例2
然后对生成的题目进行答案检错:
测试用例如下:
结果如下:
Grade文本如下:
测试用例3
将生成的题目答案进行修改来证明答案检错功能能够正常运行
测试用例如下:
对Answers文本的第250行的答案进行修改:
修改后如下:
结果如下:
Grade文本如下:
测试结果分析:
由第3个测试用例可证明程序题目检错功能能够正常运行,而测试用例2又进一步证明程序生成题目功能能够正常运行
其他测试用例
重复运行同一个测试用例,进而得出程序具有随机生成四则运算题目的功能
测试用例如下:
多次运行后Exercises文本内容如下:
由结果可见题目能随机生成四则运算题目
通过调整参数来测试程序产生规定数值范围的四则运算题目的功能
测试用例如下:
结果如下:
Exercises文本内容如下:
测试用例如下:
结果如下:
Exercises文本内容如下:
测试用例如下:
结果如下:
Exercises文本内容如下:
测试用例如下:
结果如下:
Exercises文本内容如下:
测试用例如下:
结果如下:
Exercises文本内容如下:
通过不断缩小参数的数值范围,可见生成题目的数值范围随之缩小
项目小结
通过结队编程,对项目有了多角度的了解,虽勉强项目的功能基本实现,但也有一些问题没有能够解决,例如生成题目过多而规定的数值范围太小导致程序随机生成的四则运算题目无法达到规定题目数量的问题。