个人作业1——四则运算题目生成程序(基于控制台)
一、题目描述:
1. 使用 -n 参数控制生成题目的个数,例如
Myapp.exe -n 10 -o Exercise.txt
将生成10个题目。
2. 使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围,例如
Myapp.exe -r 10
将生成10以内(不包括10)的四则运算题目。该参数可以设置为1或其他自然数。该参数必须给定,否则程序报错并给出帮助信息。
3. 生成的题目中如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数。
4. 每道题目中出现的运算符个数不超过3个。
5. 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。例如,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. 四则运算题目1
2. 四则运算题目2
……
其中真分数在输入输出时采用如下格式,真分数五分之三表示为3/5,真分数二又八分之三表示为2’3/8。
6. 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件,格式如下:
1. 答案1
2. 答案2
特别的,真分数的运算如下例所示:1/6 + 1/8 = 7/24。
7. 程序应能支持一万道题目的生成。
8. 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,并会输出所有题目中重复的题目,输入参数如下:
Myapp.exe -e <exercisefile>.txt -a <answerfile>.txt -o Grade.txt
统计结果输出到文件Grade.txt,格式如下:
Correct: 5 (1, 3, 5, 7, 9)
Wrong: 5 (2, 4, 6, 8, 10)
Repeat:2
RepeatDetail:
(1) 2,45+32 Repeat 3,32+45
(2) 5,3+(2+1) Repeat 7,1+2+3
解释:
Correct: 5 ----5道题目正确,正确的题号 1,3,5,7,9
Wrong:5 -----5道题目错误,错误的题号 2,4,6,8,10
Repeat:2 2---组题目重复
(1) 第一组 题号2,题目 45+32 与题号3的题目重复,题号3为 32+45
(2)第二组 题号5,题目 3+(2+1) 与题号7的题目重复,题号7为 1+2+3
其中“:”后面的数字5表示对/错的题目的数量,括号内的是对/错题目的编号。为简单起见,假设输入的题目都是按照顺序编号的符合规范的题目。
二、需求分析
系统能自动生成带有‘+’、‘-’、‘*’、‘÷’并且表达式带有分数的四则运算式,分数以真分数和带分数的形式出现。例如(1/2和1‘2/3),并能根据所给的题目文件和答案文件进行批改。程序支持1W道题目的生成,生成题目后将题目和题目的运算结果保存至文件保存,并且支持对所给题目的查重。用户通过控制台形式进行生成题目数量和文件的修改。
三、功能设计:
基本功能:
表达式的生成、运算、查重
扩展功能:
添加出题人与答题人角色,出题人可为教师,教师通过创立小组,小组有唯一编号(可用二维码形式),答题人通过扫描二维码加入小组答题。提交后教师可以查看已提交的用户试题,并且可以对所有答题结果进行数据分析。
四、设计实现:
1.程序入口类(Main.java)
主要实现主程序的命令输入和命令提示和文件的存储与读取。
2.运算类(Calcuate.java)
包含两个函数1:将中缀表达式转换为后缀表达式。2:将后缀表达式进行运算算出结果。
3.二叉树类(Node.java)
包含了一个二叉树结构和两个函数1:将中缀表达式转换为二叉树村粗胡。2:二叉树的判重。
4.操作数类(Num.java)
包含了整数、分子和分母来组成操作数,其中包含了操作数的加减乘除、判重、以及生成一个随机数。
5.题目类(Request.java)
包含了题目的中缀表达式、答案、后缀表达式、二叉树结构以及题目的生成和判重。
五、代码实现:
中缀转后缀函数
1 public String toSuffix(String infix){ 2 List<String> queue = new ArrayList<String>(); 3 List<Character> stack = new ArrayList<Character>(); 4 5 char[] charArr = infix.trim().toCharArray(); 6 String standard = "*÷+-()"; 7 char ch = '&'; 8 int len = 0; 9 for (int i = 0; i < charArr.length; i++) { 10 11 ch = charArr[i]; 12 if(Character.isDigit(ch)) { 13 len++; 14 }else if(ch=='/') { 15 len++; 16 }else if(ch == '.'){ 17 len++; 18 }else if(Character.isSpaceChar(ch)) { 19 if(len > 0) { 20 queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len, i))); 21 len = 0; 22 } 23 continue; 24 }else if(standard.indexOf(ch) != -1) { 25 if(len > 0) { 26 queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len, i))); 27 len = 0; 28 } 29 if(ch == '(') { 30 stack.add(ch); 31 continue; 32 } 33 if (!stack.isEmpty()) { 34 int size = stack.size() - 1; 35 boolean flag = false; 36 while (size >= 0 && ch == ')' && stack.get(size) != '(') { 37 queue.add(String.valueOf(stack.remove(size))); 38 size--; 39 flag = true; 40 } 41 while (size >= 0 && !flag && basic.get(stack.get(size)) >= basic.get(ch)) { 42 queue.add(String.valueOf(stack.remove(size))); 43 size--; 44 } 45 } 46 if(ch != ')') { 47 stack.add(ch); 48 } else { 49 stack.remove(stack.size() - 1); 50 } 51 } 52 if(i == charArr.length - 1) { 53 if(len > 0) { 54 queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len+1, i+1))); 55 } 56 int size = stack.size() - 1; 57 while (size >= 0) { 58 queue.add(String.valueOf(stack.remove(size))); 59 size--; 60 } 61 } 62 63 } 64 return queue.stream().collect(Collectors.joining(",")); 65 }
后缀运算出结果
1 public String dealEquation(String equation){ 2 String [] arr = equation.split(","); //根据, 拆分字符串 3 List<String> list = new ArrayList<String>(); //用于计算时 存储运算过程的集合【例如list中当前放置 100 20 5 / 则取出20/5 最终将结果4存入list 此时list中结果为 100 4 】 4 5 6 for (int i = 0; i < arr.length; i++) { //此处就是上面说的运算过程, 因为list.remove的缘故,所以取出最后一个数个最后两个数 都是size-2 7 int size = list.size(); 8 switch (arr[i]) { 9 case "+": Num a = new Num(list.remove(size-2)).add(new Num(list.remove(size-2))); list.add(a.toString()); break; 10 case "-": Num b = new Num(list.remove(size-2)).sub(new Num(list.remove(size-2))); list.add(b.toString()); break; 11 case "*": Num c = new Num(list.remove(size-2)).muti(new Num(list.remove(size-2))); list.add(c.toString()); break; 12 case "÷": Num d = new Num(list.remove(size-2)).division(new Num(list.remove(size-2))); list.add(d.toString()); break; 13 default: list.add(arr[i]); break; //如果是数字 直接放进list中 14 } 15 } 16 17 return list.size() == 1 ? list.get(0) : "运算失败" ; //最终list中仅有一个结果,否则就是算错了 18 }
使用递归来对二叉树进行判重(注意加法和乘法可以左右交换)
1 public boolean equals(Node node){ 2 if(!this.getData().equals(node.getData())){ 3 return false; 4 } 5 if(this.getLeft()==null&&this.getRight()==null&&node.getLeft()==null&&node.getRight()==null){ 6 if(this.getData().equals(node.getData())) 7 { 8 return true; 9 } 10 else 11 return false; 12 13 } 14 if(this.getData().equals("*")||this.getData().equals("+")) 15 if(this.getLeft()!=null&&this.getRight()!=null&&node.getLeft()!=null&&node.getRight()!=null){ 16 if(this.getLeft().equals(node.getLeft())&&this.getRight().equals(node.getRight())) 17 return true; 18 if(this.getLeft().equals(node.getRight())&&this.getRight().equals(node.getLeft())) 19 return true; 20 21 } 22 return false; 23 }
六、测试运行:
生成题目
题目
答案
进行评测(当未输入题目名和答案名时默认为Answers.txt和Exercise.txt)
七、PSD统计:
PSP2.1 |
Personal Software Process Stages |
Time Senior Student |
Time |
|
Planning |
计划 |
30 |
20 |
|
· Estimate |
估计这个任务需要多少时间 |
800 |
700 |
|
Development |
开发 |
600 |
500 |
|
· Analysis |
需求分析 (包括学习新技术) |
10 |
5 |
|
· Design Spec |
生成设计文档 |
30 |
40 |
|
· Design Review |
设计复审 |
10 |
10 |
|
· Coding Standard |
代码规范 |
10 |
10 |
|
· Design |
具体设计 |
20 |
15 |
|
· Coding |
具体编码 |
600 |
500 |
|
· Code Review |
代码复审 |
10 |
10 |
|
· Test |
测试(自我测试,修改代码,提交修改) |
20 |
30 |
|
Reporting |
报告 |
30 |
60 |
|
· |
测试报告 |
10 |
10 |
|
· |
计算工作量 |
10 |
10 |
|
· |
并提出过程改进计划 |
5 |
5 |
|
|
|
|
|
|
八:源代码
https://gitee.com/lwddddd/four_operations
九:总结
程序的效率并不高,有很多地方待优化比如操作数的约分,arraylist的遍历等等。