四则运算—基于控制台
程序员文章站
2022-07-07 23:29:20
四则运算题目自动生成——基于控制台(java) "个人作业——四则运算题目生成程序(基于控制台)" 项目已提交到码云: "UMLProject" 需求分析: 关于输入、根据提示依次输入: 数字范围(样例:10) 题目数量(样例:10) 生成的题目: 如果存在形如e1 ÷ e2的子表达式,那么其结果应 ......
四则运算题目自动生成——基于控制台(java)
个人作业——四则运算题目生成程序(基于控制台)
项目已提交到码云:UMLProject
需求分析:
- 关于输入、根据提示依次输入:
- 数字范围(样例:10)
- 题目数量(样例:10)
- 生成的题目:
- 如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数。
- 每道题目中出现的运算符个数不超过3个。
- 整数表示为1,真分数表示为1/2,假分数表示为2’1/2。
- 程序支持:
- 一万道题目生成
- 生成题目的同时计算出答案,分别保存本地txt文件。
- 题目进行查重,去除重复。
- 对个人答案的批改
功能设计:
控制台实现,功能相对简单,实现按要求生成题目,根据用户选择进行是否批改答案。并显示批改结果。
设计实现
1. 生成题目问题:
通过RandomQuestion类最终生成题目,RandomNum类和RandomSign类分别生成操作数和运算符。
RandomSign类:
public RandomSign(){//随机生成符号 int random_sign; random_sign = (int)(Math.random()*4); switch(random_sign){ case 0 : this.setRandom_sign("+");break; case 1 : this.setRandom_sign("-");break; case 2 : this.setRandom_sign("*");break; case 3 : this.setRandom_sign("÷");break; } }
RandomNum类:
public class RandomNum {//随机生成一个数 a'b/c private int random_numerator;//a'b/c 的格式拆分成 a b c 随机生成组合 private int random_denominator; private int random_front; public String toStringSpit(){//进行区分 组成一个整体分数 if(this.getRandom_front()==0){ if(this.getRandom_numerator() == this.getRandom_denominator()){ return "1"; }else return this.getRandom_numerator() + "/" + this.getRandom_denominator();//真分数 } if(this.getRandom_denominator() == this.getRandom_numerator()){ return Integer.toString(this.getRandom_front()+1);//整数 } if(this.getRandom_numerator() == 0) return Integer.toString(this.getRandom_front()); return this.getRandom_front() + "'" + this.getRandom_numerator() + "/" + this.getRandom_denominator();//假分数 } public void SplitANum(String str){//把9‘1/5反向 拆分成类(此处默认所有数为如此格式) String[] parts; int temp; parts = str.split("'"); temp = Integer.parseInt(parts[0]); this.random_front = temp; parts = parts[1].split("/"); temp = Integer.parseInt(parts[0]); this.random_numerator = temp; temp = Integer.parseInt(parts[1]); this.random_denominator = temp; } public String toString(){//默认 return this.getRandom_front() + "'" + this.getRandom_numerator() + "/" + this.getRandom_denominator();//都返回假分数 }
RandomQuestion类:
生成括号参考(就不贴出来了):参考
public RandomQuestion(int qnum_range){//生成题目 用ArrayList存取 int sign_num = (int)(Math.random()*4+1);//骰子判断生成题目长度 //this.randomquestion = null; int flag = 0; RQ(qnum_range,sign_num,flag);//递归实现题目生成 具体就不贴了 }
2. 答案计算:
中缀转换后缀 对后缀表达式进行求答案。
转后缀遵循规则:参考
- 遇到操作数,直接输出;
- 栈为空时,遇到运算符,入栈;
- 遇到左括号,将其入栈;
- 遇到右括号,执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出;
- 遇到其他运算符’+”-”*”/’时,弹出所有优先级大于或等于该运算符的栈顶元素,然后将该运算符入栈;
- 最终将栈中的元素依次出栈,输出。
ChangeToRPN类:
public class ChangeToRPN {//a+b*c+(d*c+f)g -> abc*+de*f+g*+ 中缀转后缀 public ArrayList<Object> changetoRPN(ArrayList<Object> rq){ ArrayList<Object> rpn = new ArrayList<Object>(); Stack sk = new Stack(); String temp_stackpop; for(int i = 0; i <= rq.size()-2; i++){ if(IsSign(rq.get(i).toString())){//判断是不是符号 if(sk.getTop() == -1 || rq.get(i).toString() == "("){//栈空 和( 直接入栈 sk.push(rq.get(i).toString()); }else{ if(rq.get(i).toString() == ")"){ while(sk.getTop() != -1 && sk.top().toString() != "("){ temp_stackpop = sk.pop().toString(); if(temp_stackpop != "(") rpn.add(temp_stackpop); } }else{//遇到别的操作符 判断优先级 while(sk.getTop() != -1 && GetPriority(sk.top().toString(),true) >= GetPriority(rq.get(i).toString(),false)){ temp_stackpop = sk.pop().toString(); if(temp_stackpop != "(") rpn.add(temp_stackpop); } sk.push(rq.get(i)); } } }else rpn.add(rq.get(i)); } while(sk.getTop()!=-1){ temp_stackpop = sk.pop().toString(); if(temp_stackpop != "(") rpn.add(temp_stackpop); } return rpn; } //flag true->栈内 符号优先级 int GetPriority(String operator, boolean flag) { if (operator == "+" || operator == "-") { if (flag) return 3; else return 2; } else if (operator == "*" || operator == "÷") { if (flag) return 5; else return 4; } else if (operator == "(") { if (flag) return 1; else return 6; } else if (operator == ")") { if (flag) return 6; else return 1; } return 0; } }
不得不讲一下,逆波兰式在挺早的时候就学过了,然而还是完全忘了。。最终还是复习了下,才想起来整体流程。
Answer类:
public String GetAnswer(ArrayList<Object> rpn){ Stack sk = new Stack(); String rpn_temp; String num1,num2; String sk_temp; for(int i = 0; i <= rpn.size()-1; i++){ rpn_temp = rpn.get(i).toString(); if(IsSign(rpn_temp)){ num2 = sk.pop().toString();//注意出栈顺序 这边应该是 num2 后 num1 num1 = sk.pop().toString(); sk_temp = TwoNumCount(num1,num2,rpn_temp);//对两个数求值 if(sk_temp != "-1") sk.push(sk_temp); else return "-1";//返回-1表示该式子求值失败 调用处continue }else sk.push(rpn_temp); } String result = sk.pop().toString(); RandomNum rq = new RandomNum(); rq.SplitANum(result); return rq.toStringSpit(); } }
3. 题目查重:
Tree类:
5+6-2 —>56+2- 的转化存储过程:
public class Tree { private double result;//存取当前节点计算的值 private String value;//存取当前节点值 private Tree lchild; private Tree rchild; //生成树中的规则 public boolean Compare(Tree tree1, Tree tree2){//true——>tree1 左边 ChangeToRPN rpn = new ChangeToRPN(); int flag = 0; if(tree1.getResult() > tree2.getResult()) flag = 1; else if(tree1.getResult() < tree2.getResult()) flag = 2; else flag = 3; if(flag == 1) return true; //值大的为左 else if(flag == 2) return false; else if(tree1.getLchild() == null && tree2.getLchild() == null) return true;//2 2相等但是没有孩子 else if(rpn.GetPriority(tree1.getValue().toString(), true) // 值相等 运算符大的 左 > rpn.GetPriority(tree2.getValue().toString(), true)) return true; else if(rpn.GetPriority(tree1.getValue().toString(), true) // 值和运算符都等 则子树的左子树值大的 左 == rpn.GetPriority(tree2.getValue().toString(), true)){ if(tree1.getLchild().getResult() > tree2.getLchild().getResult()) flag = 1; else if(tree1.getLchild().getResult() < tree2.getLchild().getResult()) flag = 2; else flag = 3; if(flag == 1) return true; else if(flag == 2) return false; else return true; } return false;//tree2应为左 } }
4. 运行测试
5. PSP
PSP2.1 | Personal Software Process Stages | Time Senior Student | Time |
---|---|---|---|
Planning | 计划 | 10 | 10 |
· Estimate | 估计这个任务需要多少时间 | 10 | 10 |
Development | 开发 | 600 | 900 |
· Analysis | 需求分析 (包括学习新技术) | 30 | 30 |
· Design Spec | 生成设计文档 | - | - |
· Design Review | 设计复审 | - | - |
· Coding Standard | 代码规范 | - | - |
· Design | 具体设计 | - | - |
· Coding | 具体编码 | 480 | 600 |
· Code Review | 代码复审 | 240 | 120 |
· Test | 测试(自我测试,修改代码,提交修改) | 200 | 120 |
Reporting | 报告 | 240 | 180 |
· | 测试报告 | 50 | 50 |
· | 计算工作量 | 10 | 10 |
· | 并提出过程改进计划 | - | - |
6. 总结
做这个项目还是花了很多时间的,大多是下课后过去图书馆然后做这个了。做的时候碰到挺多问题的吧,最大的是一开始没有构思好具体思路,到了做着的时候发现行不通,后来还是再构想后,决定重新开始做。
具体编码这部分虽然一开始就觉得会花很久,结果真正做的时候发现,出现bug是真的耗费时间。
这个表格的时间我其实我并没有很详细的算了,因为做的时候零零散散的,所以时间也没有很好的统计,只是大概估计了下。
测试这一块我觉得我做的不够好,可以考虑用下单元测试,就像写二叉树查重那块,我是整体写完了,才开始测试,所以出现了有的读空,也有其他的细节小问题,比如出栈数的操作对于减法除法应该反着来的,起初没考虑到,后面发现才改过来。
后来在进一步优化代码以及写写注释什么的,也花了一些时间。
表里面的有的还不太清楚,所以就没写了。
第一次写博客!偷偷标记!