这个作业属于哪个课程 软件工程课程
这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/homework/13230
这个作业的目标 实现一个自动生成小学四则运算题目的命令行程序
成员一 32222004725乌克来·布拉什
成员二 3222004728钟慧雯

GitHub地址

https://github.com/wklay-77/Wklay-77

PSP表格:

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 30 30
· Estimate · 估计这个任务需要多少时间 600 750
Development 开发 210 320
· Analysis · 需求分析 (包括学习新技术) 60 60
· Design Spec · 生成设计文档 30 30
· Design Review · 设计复审 (和同事审核设计文档) 10 10
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 10 30
· Design · 具体设计 60 50
· Coding · 具体编码 300 360
· Code Review · 代码复审 60 90
· Test · 测试(自我测试,修改代码,提交修改) 60 80
Reporting 报告 30 30
· Test Report · 测试报告 60 60
· Size Measurement · 计算工作量 20 20
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 30 50
合计 1570 1980

一、项目需求分析

1.题目:

实现一个自动生成小学四则运算题目的命令行程序(也可以用图像界面,具有相似功能)。

2.说明:

  • 自然数:0, 1, 2, …。
  • 真分数:1/2, 1/3, 2/3, 1/4, 1’1/2, …。
  • 运算符:+, −, ×, ÷。
  • 括号:(, )。
  • 等号:=。
  • 分隔符:空格(用于四则运算符和等号前后)。
  • 算术表达式:
    e = n | e1 + e2 | e1 − e2 | e1 × e2 | e1 ÷ e2 | (e),
    其中e, e1和e2为表达式,n为自然数或真分数。
  • 四则运算题目:e = ,其中e为算术表达式。

3.需求:

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

  • 使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围,例如 Myapp.exe -r 10 将生成10以内(不包括10)的四则运算题目。该参数可以设置为1或其他自然
    数。该参数必须给定,否则程序报错并给出帮助信息。

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

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

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

  • 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。例如,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,它们之间不能通过有限次交换变成同一个题目。

  • 生成的题目存入执行程序的当前目录下的Exercises.txt文件,格式如下:
    四则运算题目1
    四则运算题目2
    ……
    其中真分数在输入输出时采用如下格式,真分数五分之三表示为3/5,真分数二又八分之三表示为2’3/8。

  • 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件,格式如下:
    答案1
    答案2
    特别的,真分数的运算如下例所示:1/6 + 1/8 = 7/24。

  • 程序应能支持一万道题目的生成。

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

  • 统计结果输出到文件Grade.txt,格式如下:
    Correct: 5 (1, 3, 5, 7, 9)
    Wrong: 5 (2, 4, 6, 8, 10)
    其中“:”后面的数字5表示对/错的题目的数量,括号内的是对/错题目的编号。为简单起见,假设输入的题目都是按照顺序编号的符合规范的题目。

二、效能分析

1.改进的思路:

  • 输入验证与错误处理:对用户输入进行有效的验证和错误处理,减少无效请求带来的性能消耗。
  • 模块化设计:将功能拆分成独立的模块,每个模块负责一部分,有利于复用和维护。

2.性能分析的图:

3.Memory占用图:

三、设计实现过程

1.类与函数的设计分析:

类 Calculate: 主要用于处理数学表达式的计算。

  • 方法 getResult(String s):
    计算输入字符串 s 的结果。
    先通过 PRNCal 方法计算后缀表达式的结果,然后对结果进行格式化,返回分数的标准形式。

  • 方法 PRNCal(String s):
    计算后缀表达式的结果。
    使用栈结构处理运算符和操作数,支持四种基本运算(加、减、乘、除)。

  • 方法 generate(String s):
    将中缀表达式转换为后缀表达式(逆波兰表示法)。
    使用栈结构处理运算符的优先级和括号。

  • 辅助方法: 包括处理括号、字符串转换、操作符优先级比较、最大公约数和最小公倍数的计算等。

类 Check: 主要用于处理后缀表达式,构建二叉表达式树,并进行遍历。

  • 方法 chaChong(String s):
    接收一个字符串 s 作为输入,生成后缀表达式并调用构建二叉树的函数。
    返回后缀表达式的字符串。

  • 内部类 Node:
    表示二叉树的节点,包含节点值和左右子节点。

  • 方法 suffixExpressionTree(String suffixStr):
    将后缀表达式转换为二叉表达式树。
    使用栈结构来构建树,运算符节点的左右子节点根据优先级和比较规则进行选择。

  • 方法 isOperator(String s):
    判断给定字符串是否为运算符。

  • 方法 PostOrderTravels(Node node):
    进行后序遍历,并调用 visit 方法处理每个节点。

  • 方法 visit(Node node):
    访问节点并将节点值添加到结果字符串 str 中。

  • 方法 compare(String a, String b):
    比较两个分数的大小,使用 Calculate 类中的方法进行转换和比较。

类 CompareAnswer: 主要用于比较两个答案文件的内容,统计正确和错误的行数,并输出结果。

  • 静态变量:
    filePath2: 存储正确答案的文件路径(answer.txt)。
    filePath3: 存储用户答案的文件路径(your-Answer.txt)。

  • 方法 compare():
    该方法负责读取两个文件的内容,逐行进行比较,统计正确和错误的答案,并将结果写入文件。

类 CreateFormula: 用于生成随机的数学算式。

  • 静态变量:
    operate: 存储可用的运算符,包括加法、减法、乘法和除法。

  • 方法 Creating(int range):
    接收一个整数 range 作为参数,用于限制生成的操作数的范围。
    返回一个字符串,表示生成的数学表达式。

  • 方法 getNum(int num):
    随机生成操作数,可以是自然数、真分数或带分数。
    根据随机生成的类型,生成相应格式的字符串表示。

  • 方法 getOperate():
    随机选择一个运算符并返回。

类 fenshu: 用于表示分数,包含分子和分母的属性。

  • fenshu: 整数类型,用于表示分数的值。
  • fenmu: 整数类型,表示分母。
  • fenzi: 整数类型,表示分子。
    Getter 和 Setter 方法:
  • getFenshu(): 返回 fenshu 的值。
  • setFenshu(int fenshu): 设置 fenshu 的值。
  • getFenmu(): 返回 fenmu 的值。
  • setFenmu(int fenshu): 设置 fenmu 的值。
  • getFenzi(): 返回 fenzi 的值。
  • setFenzi(int fenzi): 设置 fenzi 的值。

类 FileWriting: 提供了一系列静态方法,用于文件的操作。

  • 静态属性:
    filePath, filePath2, filePath3, filePath4: 这些字符串常量分别表示不同文件的路径,包含 Exercises.txt、answer.txt、your-answer.txt 和 Grade.txt。

  • 方法 createFile(File fileName):
    创建一个新文件(如果该文件不存在)。

  • 方法 readTxtFile(File file):
    读取指定文件的内容,并将其作为字符串返回。

  • 方法 writeTxtFile(String content, File fileName):
    将指定内容写入文件,覆盖原有内容。

  • 方法 fileChaseFW(String filePath, String content):
    追加内容到指定文件的末尾。

  • 方法 writter, writter1, writter2, writter3:
    这些方法分别用于写入到不同的文件,调用 createFile 和 fileChaseFW。

  • 方法 fileClear():
    清空所有指定文件的内容。

类 HomePage: 该类包含一个 main 方法,负责程序的入口和主要逻辑。

  • 方法 main(String[] args):
    提示用户输入生成的题目数量和数值范围。
    验证用户输入是否为整数。
    调用 question 类的 Exam 方法生成题目。
    提示用户是否需要批改答案。

  • 方法 isInt(String string):
    验证一个字符串是否为整数。

  • 方法 input():
    从控制台读取用户输入。

类 question: 包含一个方法 Exam,用于生成题目并处理重复题目。

  • 方法 Exam(int count, int range):
    根据给定的题目数量 count 和数值范围 range 生成题目。
    检查生成的题目是否重复,并将题目和答案写入文件。

  • 方法 deleteKuoHao(String str):
    去掉字符串开头和结尾的括号(如果存在)。

2.关键函数:

  • 方法 main(String[] args):
    提示用户输入生成的题目数量和数值范围。
    验证用户输入是否为整数。
    调用 question 类的 Exam 方法生成题目。
    提示用户是否需要批改答案。

  • 方法 PRNCal(String s):
    计算后缀表达式的结果。
    使用栈结构处理运算符和操作数,支持四种基本运算(加、减、乘、除)。

  • 方法 compare(String a, String b):
    比较两个分数的大小,使用 Calculate 类中的方法进行转换和比较。

  • 方法 Creating(int range):
    接收一个整数 range 作为参数,用于限制生成的操作数的范围。
    返回一个字符串,表示生成的数学表达式。

四、关键代码说明

main函数

代码:

public static void main(String[] args)
        throws Exception
{
    System.out.print("请输入生成的题目数量:");
    String input1 = input();
    while (!isInt(input1)) {
        System.out.println("输入错误,请重新输入!");
        input1 = input();
    }
    System.out.print("请输入题目的数值范围:");
    String input2 = input();
    while (!isInt(input2)) {
        System.out.println("输入错误,请重新输入!");
        input2 = input();
    }
    question exam = new question();
    exam.Exam(Integer.parseInt(input1), Integer.parseInt(input2));
    System.out.println("出题完毕,请到your-answer.txt作答!");
    System.out.println("如需批改请按‘1’,任意键退出");
    String input3 = input();
    if (input3.equals("1")){
        CompareAnswer.compare();
        System.out.println("批改已完成,请到Grade.txt查看");
    }
    else
        System.exit(0);
}

思路说明:

  • 获取题目数量:
    程序首先提示用户输入要生成的题目数量。
    使用 input() 方法读取用户输入的字符串,并将其存储在 input1 中。
    通过 isInt(input1) 方法检查输入是否为整数。如果不是整数,程序会提示用户输入错误,并要求重新输入,直到用户输入有效的整数。

  • 获取数值范围:
    程序接着提示用户输入题目的数值范围,使用相同的方式读取并验证输入。
    将用户输入的数值范围存储在 input2 中,并再次使用 isInt(input2) 方法检查输入的有效性。

  • 创建题目实例并生成题目:
    创建 question 类的实例 exam。
    调用 exam.Exam(Integer.parseInt(input1), Integer.parseInt(input2)) 方法,传入用户输入的题目数量和数值范围,生成数学题目。

  • 输出完成信息:
    程序在控制台输出“出题完毕,请到your-answer.txt作答!”的信息,提醒用户查看生成的题目文件。

  • 选择是否批改答案:
    程序询问用户是否需要批改答案,提示按“1”进行批改,任意键退出。
    读取用户的输入 input3,如果用户输入“1”,则调用 CompareAnswer.compare() 方法进行批改,并在控制台输出批改完成的信息,提示用户查看 Grade.txt 文件。
    如果用户输入其他内容,程序调用 System.exit(0) 退出。

五、测试运行

1.测试覆盖率:

2.运行结果:

六、项目总结

乌克来:这次同钟慧雯同学一起完成的结对项目任务,因为分工明确所以完成的非常顺利。也在这次结对项目中发现她对事反应能力很强,逻辑思维很清晰。
钟慧雯:这次和乌克来合作的结对项目完成得很顺利,我认为她的闪光点是能在发现问题时善于思考,很好地解决问题。很高兴能和她合作。
总结:在借助资料以及文献的帮助下,我们完成了这次项目,通过这次项目,我们对于java语言有了更加深入的了解,也意识到了结队合作的效率之高,相互之间取长补短,共同学习进步,对各自的编程能力与团队协作能力有了很大提升