结队编程——四则运算

Gitcode项目地址

姓名学号gitcode地址
吴凯越3121005011https://gitcode.net/qq_63808826/3121005011
郭远锭3121004995

PSP表格

Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
计划3010
估计这个任务需要多少时间3020
开发6060
需求分析 (包括学习新技术)3030
生成设计文档3010
设计复审3010
代码规范 (为目前的开发制定合适的规范)3030
具体设计3060
具体编码600900
代码复审3020
测试(自我测试,修改代码,提交修改)60100
报告3060
测试报告3060
计算工作量3040
事后总结, 并提出过程改进计划3030
合计10501440

效能分析

自动生成四则运算题目的函数调用情况如下:

在这里插入图片描述

自动查答案的函数调用情况如下:

在这里插入图片描述
可见程序除了用户输入占用了绝大部分的运行时间,其余时间打都花费再重复生成题目以及文件读写上。

设计实现过程

通过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文本内容如下:
在这里插入图片描述
通过不断缩小参数的数值范围,可见生成题目的数值范围随之缩小

项目小结

通过结队编程,对项目有了多角度的了解,虽勉强项目的功能基本实现,但也有一些问题没有能够解决,例如生成题目过多而规定的数值范围太小导致程序随机生成的四则运算题目无法达到规定题目数量的问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值