结对项目:自动生成小学四则运算题目
结对编程
github地址
Github链接:结对项目:四则运算
这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy/Networkengineering1834 |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/gdgy/Networkengineering1834/homework/11148 |
这个作业的目标 | 学习协作编程 |
张浩辉(3118005347),张澍(3118005348)
一、需求分析
需求是需要是需要实现一个自动生成小学四则运算题目的命令行程序
包含加减乘除和括号。这涉及到二叉树的知识。
并且能够控制生成题目的个数和控制题目中的数值范围。
能把题目和答案进行输出,能对用户答案与标准答案作比对。因此涉及到io操作。
二、实现思路
-
表达式构建
在网上参考了很多种方法,主要是两种方法实现,二叉树或者是栈。
这里用的是二叉树方法,在二叉树中,度为0的是运算数,其余的是运算符号。
在每一个节点(包含符号节点)都需要保存当前节点以下的计算结果,符号节点还需要保存当前的符号类型。
-
运算数形式
运算数使用分数进行存储,在构建分数的情况下会对一些异常进行处理比如分母为零的情况,并自动使用辗转相除法对分子分母求最大公约数
-
表达式重复检验
重写hashcode方法可以实现两个二叉树是否为相同的树,即能实现比对两个表达的查重
-
运算结果不能出现负数
通过交换符号节点下的左右子树即可实现
三、具体实现
3.1 文件目录
├── pom.xml
├── src
│ ├── main
│ │ └── java
│ │ └── com
│ │ └── free
│ │ ├── MainStart.java 主启动类
│ │ ├── pojo 实体类
│ │ │ ├── Check.java 检测用户答案
│ │ │ ├── Creator.java 生成表达式
│ │ │ ├── Expression.java 表达式类
│ │ │ ├── MyNumber.java 运算数类
│ │ │ ├── Node.java运算数节点类
│ │ │ └── Onode.java 符号节点类
│ │ └── util
│ │ └── FileUtils.java 文件输入输出类
│ └── test
│ └── java
│ ├── ExpressionTest.java
│ └── FractionTest.java
3.2 类图
3.3核心实现
计算数
package com.free.pojo;
import lombok.Data;
/**
* @ClassName MyNumber
* @Description 计算数
* @Author Free
* @Date2020/10/9 20:22
* @Version V1.0
**/
@Data
public class MyNumber {
/**
* 分子
*/
private int up;
/**
* 分母,不能为0,默认为1
*/
private int down = 1;
//设置分子和分母
public MyNumber(int a, int b) {
setMyNumber(a, b);
}
//看当前分数是否为负数
boolean isNegative() {
//结果默认是正数
boolean isNagitiveAB = false;
if (up * down < 0) {
isNagitiveAB = true;
}
return isNagitiveAB;
}
/**
* 设置分子和分母
* @param up
* @param down
*/
public void setMyNumber(int up,int down){
if (down == 0){
throw new RuntimeException("分母不能为0");
}
//结果默认是正数
int isNagitive = 1;
//调整符号,分母只能为正数
if (up * down < 0) {
isNagitive = -1;
}
up = Math.abs(up);
down = Math.abs(down);
//最大公因数
int greatest_Common_Factor = divisionAlgorithm(up, down);
//化简
this.up = up * isNagitive / greatest_Common_Factor;
this.down = down / greatest_Common_Factor;
}
/**
* 求最大公因数,辗转相除法
* @param a
* @param b
* @return
*/
private int divisionAlgorithm(int a, int b) {
int big = a;
if (big == 0){
return 1;
}
int small = b;
//让a成为最大的
if (a < b) {
big = b;
small = a;
}
int mod = big % small;
return mod == 0 ? small : divisionAlgorithm(small, mod);
}
/**
* 功能描述: 通过表达式得到分子和分母,都未经过简化 "1'21/22"
* @Param: [result]
* @Return:
* @Author: Free
* @Date: 2020/10/9 21:19
*/
public MyNumber(String result) {
result.trim();
int up_index = result.indexOf("/");
int a1_index = result.indexOf("'");
//不是分式的时候
if (up_index == -1) {
up = Integer.valueOf(result);
}
//是分式的时候
else {
//分母
down = Integer.valueOf(result.substring(up_index + 1));
//真分数
if (a1_index == -1) {
up = Integer.valueOf(result.substring(0, up_index));
}
//带分数
else {
int a1 = Integer.valueOf(result.substring(0, a1_index));
int a0 = Integer.valueOf(result.substring(a1_index + 1, up_index));
up = a1 * down + a0;
}
}
setMyNumber(up, down);
}
/**
* 功能描述: 随机生成一个用来运算的分数(多种形式)
*
* @Param: []
* @Return: com.free.pojo.MyNumber
* @Author: Free
* @Date: 2020/10/9 21:16
*/
public static MyNumber generateMyNumber() {
//a.b 都是大于等于0的
int up = Creator.getRandomInRange(Expression.numRange);
int down = Creator.getRandomInRange(Expression.numRange);
//分母为0
while (down == 0) {
down = Creator.getRandomInRange(Expression.numRange);
}
MyNumber result = new MyNumber(up,down);
return result;
}
/**
* 功能描述: <br>加法
* 〈〉
* @Param: [right]
* @Return: com.free.pojo.MyNumber
* @Author: Free
* @Date: 2020/10/9 21:22
*/
public MyNumber add(MyNumber right) {
// a/b+c/d =(ad+bc)/bd
return new MyNumber(
this.up * right.down + this.down * right.up,
this.down * right.down
);
}
/**
* 功能描述: <br>
* 〈〉
* @Param: [right]减法
* @Return: com.free.pojo.MyNumber
* @Author: Free
* @Date: 2020/10/9 21:22
*/
public MyNumber subtract(MyNumber right) {
// a/b-c/d =(ad-bc)/bd
return new MyNumber(
this.up * right.down - this.down * right.up,
this.down * right.down
);
}
/**
* 功能描述: <br>乘法
* 〈〉
* @Param: [right]
* @Return: com.free.pojo.MyNumber
* @Author: Free
* @Date: 2020/10/9 21:22
*/
public MyNumber multiply(MyNumber right) {
// a/b * c/d = ac / bd
return new MyNumber(
this.up * right.up,
this.down * right.down
);
}
/**
* 功能描述: <br>除法
* 〈〉
* @Param: [right]
* @Return: com.free.pojo.MyNumber
* @Author: Free
* @Date: 2020/10/9 21:22
*/
public MyNumber divide(MyNumber right) {
// a/b / c/d = ad / bc
return new MyNumber(
this.up * right.down,
this.down * right.up
);
}
//将a,b转化为表达式
@Override
public String toString() {
//不是分式
if (down == 1)
return String.valueOf(up);
//真分式
else {
int i = up / down;
//余数
int j = up % down;
if (i != 0) {
return String.format("%d'%d/%d", i, j, down);
} else {
return String.format("%d/%d", up, down);
}
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) return false;
MyNumber fraction = (MyNumber) o;
if (up != fraction.up) return false;
return down == fraction.down;
}
//根据分子和分母
@Override
public int hashCode() {
int result = 37853 * up + down;
return result;
}
}
在构建一个运算数的时候,有随机构建功能和手动输入功能,在生成的过程中有自动转化功能,能够保证每一个运算数是正确的,并且都是分数形式存储,用up表示分子部分,down表示分母部分。这样直观,并且在运算的过程中可以通过通分等方式进行计算。
如:
-
1/2 + 3/4 = 1x4+3x2 /2x4
-
1/2 x 3/4 = 1x3 / 2x4
-
1/2 - 3/4 = 1x4 - 3x2 /2x4
-
1/2 ÷ 3/4 = 1x3 + 2x4 /2 x3
四、性能测试
Telemetries
Live Memory
五、运行结果
生成联系文件和答案文件:
校对答案生成成绩文件:
六、 PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 130 | 150 |
· Estimate | · 估计这个任务需要多少时间 | 110 | 150 |
Development | 开发 | 1660 | 2045 |
· Analysis | · 需求分析 (包括学习新技术) | 100 | 160 |
· Design Spec | · 生成设计文档 | 100 | 120 |
· Design Review | · 设计复审 (和同事审核设计文档) | 60 | 80 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 60 | 75 |
· Design | · 具体设计、 | 120 | 130 |
· Coding | · 具体编码 | 1000 | 1200 |
· Code Review | · 代码复审 | 100 | 160 |
· Test | · 测试(自我测试,修改代码,提交修改) | 120 | 120 |
Reporting | 报告 | 120 | 210 |
· Test Report | · 测试报告 | 60 | 150 |
· Size Measurement | · 计算工作量 | 30 | 30 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 30 |
合计 | 1910 | 2570 |