作业3:生成四则运算命令行程序-结对项目 - 作业

实现一个自动生成小学四则运算题目的命令行程序

作业所属课程 结对项目 - 作业 - 计科21级12班
作业要求 结对项目 - 作业 - 计科21级12班
作业目标 实现一个自动生成小学四则运算题目的命令行程序

结对项目:林智谦3121004831 叶飞池3121004843

github地址:Flychee/Flychee (github.com)

一、题目要求

  1. 使用 -n 参数控制生成题目的个数,例如Myapp.exe -n 10

  2. 使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围,例如Myapp.exe -r 10

  3. 生成的题目中计算过程不能产生负数,也就是说算术表达式中如果存在形如e1− e2的子表达式,那么e1≥ e2。

  4. 生成的题目中如果存在形如e1÷ e2的子表达式,那么其结果应是真分数。

  5. 每道题目中出现的运算符个数不超过3个。

  6. 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。例如,23 + 45 = 和45 + 23 = 是重复的题目,6 × 8 = 和8 × 6 = 也是重复的题目。3+(2+1)和1+2+3这两个题目是重复的,由于+是左结合的,1+2+3等价于(1+2)+3,也就是3+(1+2),也就是3+(2+1)。但是1+2+3和3+2+1是不重复的两道题,因为1+2+3等价于(1+2)+3,而3+2+1等价于(3+2)+1,它们之间不能通过有限次交换变成同一个题目。

  7. 生成的题目存入执行程序的当前目录下的Exercises.txt文件,格式如下:

  1. 四则运算题目1

  2. 四则运算题目2

    .....

  1. 其中真分数在输入输出时采用如下格式,真分数五分之三表示为3/5,真分数二又八分之三表示为2’3/8

  2. 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件,格式如下:

  1. 答案1
  2. 答案2
  1. 程序应能支持一万道题目的生成。

  2. 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,输入参数Myapp.exe -e <exercisefile>.txt -a <answerfile>.txt

统计结果输出到文件Grade.txt,格式如下:

Correct: 5 (1, 3, 5, 7, 9)

Wrong: 5 (2, 4, 6, 8, 10)

二、效能分析

程序整体算法复杂度是 $O(n^2)$,即生成一次算式遍历已生成的算式,查询是否重复,由于生成查询比较和转化为表达式树的不是完全的 $O(1)$,所以常数比较大。

在最初版本中,没有将表达式树存下来,判重的时候要重复建树导致复杂度飙升,O(n^2(m+m+m+m)),生成、建树、比较、计算答案的复杂度都是O(m),m指的是算式的长度。按这种方式生成1万道题需要26分钟。

接着将树按数组存下来,直接比较两个数组判重,生成1000道需要2.4s,1万需要110s。

fef2d571a4d06027e1a7d7a7dd220f2

694d58e922e32e58f2cd3ca172de416

三、设计实现过程

生成步骤:

  1. 按输入参数首先随机生成算式。
  2. 按规则生成表达式树,(按符号、子树深度、数字大小交换左右子树)
  3. 枚举已经生成的所有表达式树,判重。
  4. 如果无重复且答案非负数,则生成答案。

答案校对步骤:

  1. 输入答案。
  2. 逐个比较。
  3. 输出正确和错误的题号。

四、代码说明

1.命令行参数读取

使用了 Python 内置的 argparse 模块来解析命令行参数。创建一个 ArgumentParser 对象 parser,用来定义命令行参数。然后,我们使用 add_argument() 方法来添加四个命令行参数:

  • -r--radius:用来指定生成数值的范围,默认值为 10。
  • -n--num:用来指定生成题目的数量,默认值为 10。
  • -e--exercise:用来指定生成的题目文件名。
  • -a--answer:用来指定生成的答案文件名。
    parser = argparse.ArgumentParser()
    parser.add_argument('-r', "--radius", type=int, default=10)
    parser.add_argument('-n', "--num", type=int, default=10)
    parser.add_argument('-e', "--exercise", type=str)
    parser.add_argument('-a', "--answer", type=str)
    args = parser.parse_args()

2.题目生成

使用伪代码描述整个生成过程:

function question(num, radius, exercise_file, answer_file):
    # 初始化题目和答案列表
    question_result = []
    answer_result = []

    # 循环生成 num 道题目
    for i in range(num):
        # 生成随机数和运算符序列
        temp = num_random(radius)
        oper = oper_random()

        # 处理运算符序列,生成新的表达式列表
        temp_result = cal_seq(oper, temp)

        # 将表达式列表转换为二叉树,并计算二叉树的值
        tree = buildTree(temp_result)
        value = evaluate(tree)

        # 判断当前表达式是否与之前的表达式重复
        if not is_duplicate(temp_result, question_result):
            # 将表达式和答案添加到题目和答案列表中
            question_result.append(temp_result)
            answer_result.append(value)

    # 将题目和答案写入文件
    write_file(exercise_file, question_result)
    write_file(answer_file, answer_result)

3.判重

需求描述的判重并非单纯的字符串判断,对于计算顺序也不能重复,期初想到的是后缀表达式,判重后使用中缀表达式输出;但是一个后缀表达式不能以一定的规则使其唯一。最后发现表达式树按一定规则生成的话,一个算式对应唯一的表达式树,表达式树不相同,则算式不同。

五、测试运行

1.基本功能

测试1:生成10以内的四则运算。.\Myapp.exe -n 10 -r 10

image-20230928222309249

测试2:生成100以内的四则运算。.\Myapp.exe -n 10 -r 100

image-20230928222351891

测试3:生成5以内的四则运算,判断是否重复。.\Myapp.exe -n 20 -r 5

image-20230928222934929

测试4:生成1000道题。.\Myapp.exe -n 1000 -r 100

image-20230928222840261

测试5:生成10000道题。.\Myapp.exe -n 10000 -r 100

image-20230928223349701

2.校对答案

Exercises.txt存的是题目;Answers,txt存答案;Grade.txt存结果。

.\Myapp.exe -e Exercises.txt -a Answers.txt

测试1:(整数答案)2题的答案是错的,最后的校对成功校对出错误答案。

image-20230928223840166

测试2:(分数答案)

image-20230928224014505

测试3:(带分数答案)

image-20230928224108452

测试4:(多个答案错误)

image-20230928224029583

测试5:(全对)

image-20230928224138446

测试6:(全错)

image-20230928224300471

六、项目小结

人员分工:林智谦主要负责需求分析、算法分析,思考完成方案、测试代码,同时负责撰写博客;叶飞池主要负责代码的编写。本次项目,林智谦同学对c++和算法比较熟悉,叶飞池同学对python比较熟悉,所以由叶飞池同学主要编写代码。

遗憾:对于一棵表达式树,因为是二叉树,所以可以使用一维数组存储,然后计算哈希值,这样判重的时候就只需要$O(1)$。由于后面没时间改了,所以作罢。

七、附录

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划
· Estimate · 估计这个任务需要多少时间 30 30
Development 开发
· Analysis · 需求分析 (包括学习新技术) 300 180
· Design Spec · 生成设计文档 120 30
· Design Review · 设计复审 60 30
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 20 20
· Design · 具体设计 60 60
· Coding · 具体编码 180 180
· Code Review · 代码复审 60 60
· Test · 测试(自我测试,修改代码,提交修改) 180 180
Reporting 报告
· Test Repor · 测试报告 120 60
· Size Measurement · 计算工作量 20 10
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 20 20
· 合计 1230 800
posted @ 2023-09-28 22:46  kai_wei  阅读(34)  评论(0编辑  收藏  举报