结对项目
四则运算
软工作业 | 结对编程 |
---|---|
作业要求 | 作业 |
Github | Github |
作业题目 | 四则运算 |
姓名 | 学号 |
---|---|
徐潮松 | 3118005387 |
丘美珠 | 3218005399 |
PSP表格
PSP2.1 | Pair-programming Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 60 | 100 |
Estimate | 估计这个任务需要多少时间 | 300 | 500 |
Development | 开发 | 600 | 1200 |
Analysis | 需求分析(包括学习新技术) | 120 | 150 |
Design Spec | 生成设计文档 | 60 | 80 |
Design Review | 设计复审 | 20 | 30 |
Coding Standard | 代码规范(为目前的开发制定合适的规范) | 10 | 20 |
Design | 具体设计 | 50 | 80 |
Coding | 具体编码 | 400 | 600 |
Code Review | 代码复审 | 30 | 60 |
Test | 测试(自我测试,修改代码,提交修改) | 60 | 90 |
Reporting | 报告 | 30 | 50 |
Test Report | 测试报告 | 60 | 120 |
Size Measurement | 计算工作量 | 60 | 50 |
Postmortem&Process Improvement Plan | 事后总结,并提出过程改进计划 | 30 | 40 |
合计 | 1890 | 3170 |
一、效能分析
二、设计实现过程
2.1 数据结构
使用二叉树存放四则运算式,比如1+2×3÷(4-5)+6这个表达式就可以使用以下二叉树表示,中序遍历二叉树时就可以还原四则运算。
作业要求四则运算式中不能出现负数,(4-5)在二叉树中调换位置即可。
2.2 实现步骤
在主函数
main()
中输入-n
,-r
两个参数, 传入并执行generateMap()
函数,在generateMap()
中用for循环new
ArithmeticTree
对象,在ArithmeticTree
的构造器中,计算了四则运算结果,返回一个OperatorNode
结点,在generateMap()
函数调用ArithmeticTree
对象中的值,包括计算出的结果,调用hashMap.put()
保存在HashMap
对象中,再传入writFile()
写出文件。
三、代码说明
类 | 功能 |
---|---|
Main |
主函数,获取输入值,计算结果 |
ArithmeticTree |
构建四则运算的二叉树 |
FractionOperation |
分数的四则运算操作 |
DataNode |
存放数据的结点 |
OperatorNode |
存放操作符的结点 |
FileUtils |
IO流操作,文件输入输出 |
GenerateUtils |
随机生成四则运算 |
/**
* 获取随机范围内的随机整数
* @param range 范围
* @return 随机数
*/
public static int getRandomInRange(int range) {
ThreadLocalRandom random = ThreadLocalRandom.current();
return random.nextInt(range);
}
/**
* 构建生成四则运算表达式的二叉树
* @param number 运算符数量
* @return 二叉树头节点
*/
public DataNode generateNode(int number) {
//如果是0就构造叶子节点
if (number == 0) {
return new DataNode(FractionOperation.generateFraction(), null, null, 1);
}
//其他都是构造符号节点
OperatorNode rootNode = new OperatorNode(null, null, OPERATORS[GenerateUtils.getRandomInRange(4)]);
int leftNum = GenerateUtils.getRandomInRange(number);
//递归下去构造左孩子和右孩子
rootNode.left = generateNode(leftNum);
//总数要减去当前已经构建出来的这一个节点
rootNode.right = generateNode(number - 1 - leftNum);
//计算结果
FractionOperation result = calculate(rootNode.operator, rootNode.left.result, rootNode.right.result);
//如果是负数,交换左右孩子
if (result.isNegative()) {
DataNode tmp = rootNode.left;
rootNode.left = rootNode.right;
rootNode.right = tmp;
}
rootNode.result = result;
rootNode.high = Math.max(rootNode.left.high, rootNode.right.high) + 1;
return rootNode;
}
/**
* 加法
* @param right 右节点分数
* @return 结果
*/
public FractionOperation add(FractionOperation right) {
// a/b+c/d =(ad+bc)/bd
return new FractionOperation(
this.a * right.b + this.b * right.a,
this.b * right.b
);
}
/**
* 减法
* @param right 右节点分数
* @return 结果
*/
public FractionOperation subtract(FractionOperation right) {
// a/b-c/d =(ad-bc)/bd
return new FractionOperation(
this.a * right.b - this.b * right.a,
this.b * right.b
);
}
/**
* 乘法
* @param right 右节点分数
* @return 结果
*/
public FractionOperation multiply(FractionOperation right) {
// a/b * c/d = ac / bd
return new FractionOperation(
this.a * right.a,
this.b * right.b
);
}
/**
* 除法
* @param right 右节点分数
* @return 结果
*/
public FractionOperation divide(FractionOperation right) {
// a/b / c/d = ad / bc
return new FractionOperation(
this.a * right.b,
this.b * right.a
);
}
/**
* 进行两个元素的计算
* @param operator 运算符
* @param leftFraction 左节点分数
* @param rightFraction 右节点分数
* @return 运算结果
*/
private FractionOperation calculate(String operator, FractionOperation leftFraction, FractionOperation rightFraction) {
switch (operator) {
case ADD:
return leftFraction.add(rightFraction);
case SUBTRACT:
return leftFraction.subtract(rightFraction);
case MULTIPLY:
return leftFraction.multiply(rightFraction);
//可能会出现除以0的情况,即rightFraction可能为0
case DIVIDE:
if (rightFraction.getA() == 0) {
this.isDivideForZero = true;
rightFraction.setA(1);
}
return leftFraction.divide(rightFraction);
default:
throw new RuntimeException("该操作符不存在");
}
}
四、测试运行
五、项目小结
-
徐潮松
开始的时候没有头绪,跟队友一起百度浏览,最后找到了用二叉树实现,所以找到方向很关键,方向对了,对实现项目要求有很大的帮助。
-
丘美珠
本来看到这个题目,感觉很难,最后跟队友一起百度搜索,攻克难关,在需要团队合作的项目,沟通是很重要的。