【作业3】

news/2025/3/26 7:17:22/文章来源:https://www.cnblogs.com/hhw798/p/18785001
黄鹏翔 3123004229 黄皓维 3123004228
仓库地址 地址
这个作业的要求 结对项目
这个作业的目标 了解双人合作项目的方法,并完成此次项目
PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 30 35
Estimate 这个任务需要的时间 25 30
Development 开发 200 240
Analysis 需求分析 320 340
Design Spec 生成设计文档 15 15
Design Review 设计复审 15 15
Coding Standard 代码规范 20 15
Design 具体设计 20 20
Coding 具体编码 100 110
Code Review 代码复审 20 15
Test 测试 200 230
Reporting 报告 90 100
Test Repor 测试报告 30 30
Size Measurement 计算工作量 30 20
Postmortem & Process Improvement Plan 事后总结,提出过程改进计划 20 20
合计 1135 1235

1.项目结构

src/main/java/com/test/
├── model/ // 基础数据模型
│ └── Fraction.java // 分数类,处理分数运算

├── expression/ // 表达式相关
│ ├── Expression.java // 表达式类
│ │
│ ├── node/ // 表达式节点
│ │ ├── ExpressionNode.java // 节点接口
│ │ ├── NumberNode.java // 数字节点
│ │ ├── OperatorNode/ // 运算符节点
│ │ │ ├── AddNode.java // 加法节点
│ │ │ ├── SubtractNode.java // 减法节点
│ │ │ ├── MultiplyNode.java // 乘法节点
│ │ │ └── DivideNode.java // 除法节点
│ │
│ └── parser/
│ └── ExpressionParser.java // 表达式解析器

├── service/ // 业务逻辑服务
│ ├── Generator.java // 题目生成器
│ └── Checker.java // 答案检查器

└── Main.java // 程序入口类

1.1核心类关系

classDiagram
Main --> Generator: uses
Main --> Checker: uses
Generator --> Expression: creates
Checker --> ExpressionParser: uses
ExpressionParser --> Expression: creates
Expression --> ExpressionNode: contains
NumberNode ..|> ExpressionNode: implements
AddNode ..|> ExpressionNode: implements
SubtractNode ..|> ExpressionNode: implements
MultiplyNode ..|> ExpressionNode: implements
DivideNode ..|> ExpressionNode: implements
ExpressionNode --> Fraction: uses

1.2工作流程

a.生成题目流程

Main -> Generator -> Expression -> ExpressionNode -> Fraction

b.答案检查流程

Main -> Checker -> ExpressionParser -> Expression -> Fraction

1.3流程图

main流程图

generator流程图

ExpressionParser流程图

Checker流程图

2.效能分析

CPU时间

内存分配

该程序中主要消耗占大头的有:

a.题目生成器中的查重=》主要消耗是重复生成和验证是否有重复的过程

b.表达式的解析

改进思路

对算法进行改进,通过优化查重的算法,减少该方法的消耗;改进表达式的解析过程;在内存管理方面,尝试对对象池进行管理,并在完成某些过程后及时释放资源

3.代码说明

3.1表达式解析器

public class ExpressionParser {// 解析表达式字符串为表达式树public static Expression parse(String input) throws ParseException {// 去除空格,简化处理input = input.replaceAll("\\s+", "");  
// 递归构建表达式树
ExpressionNode root = parseNode(input);
return new Expression(root);
}private static ExpressionNode parseNode(String input) throws ParseException {
// 处理括号
if (input.startsWith("(") && input.endsWith(")")) {
input = input.substring(1, input.length() - 1);
}// 查找最后一个运算符(优先级最低)
int opIndex = findLastOperator(input);if (opIndex == -1) {
// 没有运算符,解析数字或分数
return new NumberNode(parseFraction(input));
} else {
// 根据运算符分割并递归处理左右子表达式
String left = input.substring(0, opIndex);
String right = input.substring(opIndex + 1);
char operator = input.charAt(opIndex);// 创建对应的运算符节点
return createOperatorNode(operator, 
parseNode(left), parseNode(right));
}
}// 查找最后一个运算符,考虑括号嵌套
private static int findLastOperator(String input) {
int bracketCount = 0;
int lastAddSub = -1;  // 最后的加减号位置
int lastMulDiv = -1;  // 最后的乘除号位置for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
if (c == '(') bracketCount++;
else if (c == ')') bracketCount--;
else if (bracketCount == 0) {  // 只在没有括号时处理运算符
if (c == '+' || c == '-') lastAddSub = i;
else if (c == '×' || c == '÷') lastMulDiv = i;
}
}// 优先返回加减号位置,体现运算符优先级
return lastAddSub >= 0 ? lastAddSub : lastMulDiv;
}

}

思路说明:

  • 采用递归下降法构建表达式树

  • 通过运算符优先级控制树的结构

  • 使用括号计数处理嵌套表达式

3.2分数运算

public Fraction(int numerator, int denominator) {if (denominator == 0) {throw new IllegalArgumentException("分母不能为0");}// 统一处理负号if (denominator < 0) {numerator = -numerator;denominator = -denominator;}// 化简分数int gcd = gcd(Math.abs(numerator), denominator);this.numerator = numerator / gcd;this.denominator = denominator / gcd;
}// 加法运算
public Fraction add(Fraction other) {// 通分相加int newNumerator = this.numerator * other.denominator + other.numerator * this.denominator;int newDenominator = this.denominator * other.denominator;return new Fraction(newNumerator, newDenominator);
}// 最大公约数(辗转相除法)
private static int gcd(int a, int b) {while (b != 0) {int temp = b;b = a % b;a = temp;}return a;
}// 转换为字符串表示
@Override
public String toString() {if (denominator == 1) {return String.valueOf(numerator);}// 处理带分数形式if (Math.abs(numerator) > denominator) {int whole = numerator / denominator;int remain = Math.abs(numerator % denominator);return remain == 0 ? String.valueOf(whole) : whole + "'" + remain + "/" + denominator;}return numerator + "/" + denominator;
}

}

思路说明:

  • 保持分数始终处于最简形式

  • 统一处理负号位置

  • 支持带分数表示法

  • 使用辗转相除法求最大公约数

3.3题目生成器

public List<String> generateExercises(int count) {List<String> exercises = new ArrayList<>();Set<String> uniqueExpressions = new HashSet<>();while (exercises.size() < count) {Expression expr = generateExpression();String exprStr = expr.toString();// 检查是否重复且结果合法if (!uniqueExpressions.contains(exprStr) && isValidResult(expr.evaluate())) {exercises.add(exprStr);uniqueExpressions.add(exprStr);}}return exercises;
}private Expression generateExpression() {// 生成运算符数量(1-3个)int operatorCount = random.nextInt(3) + 1;// 构建表达式树ExpressionNode root = generateNode(operatorCount);return new Expression(root);
}private ExpressionNode generateNode(int depth) {if (depth == 0) {// 生成叶子节点(数字)return generateNumberNode();}// 生成运算符节点char[] operators = {'+', '-', '×', '÷'};char operator = operators[random.nextInt(operators.length)];return createOperatorNode(operator,generateNode(depth - 1),generateNumberNode());
}// 检查结果是否合法(正数且不超过限制)
private boolean isValidResult(Fraction result) {return result.getNumerator() > 0 && result.getNumerator() <= MAX_NUMBER &&result.getDenominator() <= MAX_NUMBER;
}

}

思路说明:

  • 随机生成表达式树

  • 控制运算符数量和数值范围

  • 确保结果为正数且在合理范围内

  • 避免重复题目

4.测试代码

答案解析\检查器

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import java.io.IOException;
import java.util.List;public class CheckerTest {@Testpublic void testCheck() throws IOException {// 定义测试文件路径String exerciseFile = "exercisefile.txt";String answerFile = "answerfile.txt";// 调用 check 方法Checker.check(exerciseFile, answerFile);// 读取生成的 Grade.txt 文件并验证内容List<String> lines = java.nio.file.Files.readAllLines(java.nio.file.Paths.get("Grade.txt"));assertFalse(lines.isEmpty(), "Grade.txt 文件不应为空");// 验证 Correct 和 Wrong 的数量是否正确String correctLine = lines.get(0);String wrongLine = lines.get(1);assertTrue(correctLine.startsWith("Correct: "), "第一行应包含 Correct 信息");assertTrue(wrongLine.startsWith("Wrong: "), "第二行应包含 Wrong 信息");// 打印结果以供检查System.out.println("Correct Line: " + correctLine);System.out.println("Wrong Line: " + wrongLine);}
}

表达式解析器测试

import org.junit.Test;
import static org.junit.Assert.*;
import java.text.ParseException;//测试 ExpressionParser(表达式解析器)是否能够正确解析数学表达式
public class ExpressionParserTest {//测试整数解析@Testpublic void testParseInteger() throws ParseException {Expression expr = ExpressionParser.parse("5");assertEquals("5", expr.evaluate().toString());}//测试分数解析@Testpublic void testParseFraction() throws ParseException {Expression expr = ExpressionParser.parse("3/4");assertEquals("3/4", expr.evaluate().toString());}//测试带分数解析@Testpublic void testParseMixedFraction() throws ParseException {Expression expr = ExpressionParser.parse("1'1/2");assertEquals("1'1/2", expr.evaluate().toString());}
}

表达式计算测试

import org.junit.Test;
import static org.junit.Assert.*;//测试 Expression(表达式)计算是否正确
public class ExpressionTest {//测试简单的加法计算@Testpublic void testSimpleAddition() {Expression expr = new Expression(new AddNode(new NumberNode(new Fraction(1, 2)), new NumberNode(new Fraction(1, 3))));assertEquals("5/6", expr.evaluate().toString());}//测试简单的减法计算@Testpublic void testSimpleSubtraction() {Expression expr = new Expression(new SubtractNode(new NumberNode(new Fraction(3, 4)), new NumberNode(new Fraction(1, 4))));assertEquals("1/2", expr.evaluate().toString());}//测试乘法计算@Testpublic void testMultiplication() {Expression expr = new Expression(new MultiplyNode(new NumberNode(new Fraction(2, 3)), new NumberNode(new Fraction(3, 4))));assertEquals("1/2", expr.evaluate().toString());}//测试除法计算@Testpublic void testDivision() {Expression expr = new Expression(new DivideNode(new NumberNode(new Fraction(3, 4)), new NumberNode(new Fraction(2, 5))));assertEquals("1'7/8", expr.evaluate().toString());}//测试将加法节点转换为字符串@Testpublic void testToString1() {Expression expr = new Expression(new AddNode(new NumberNode(new Fraction(1, 2)), new NumberNode(new Fraction(1, 3))));assertEquals("1/2 + 1/3", expr.toString());}//测试将减法节点转换为字符串@Testpublic void testToString2() {Expression expr = new Expression(new SubtractNode(new NumberNode(new Fraction(1, 2)), new NumberNode(new Fraction(1, 3))));assertEquals("1/2 - 1/3", expr.toString());}//测试将乘法节点转换为字符串@Testpublic void testToString3() {Expression expr = new Expression(new MultiplyNode(new NumberNode(new Fraction(1, 2)), new NumberNode(new Fraction(1, 3))));assertEquals("1/2 × 1/3", expr.toString());}//测试将除法节点转换为字符串@Testpublic void testToString4() {Expression expr = new Expression(new DivideNode(new NumberNode(new Fraction(1, 2)), new NumberNode(new Fraction(1, 3))));assertEquals("1/2 ÷ 1/3", expr.toString());}
}

分数类测试

import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;//测试 Fraction(分数)类的功能,包括四则运算、约分、负数处理等。
public class FractionTest {private Fraction f1, f2, f3, f4;//初始化测试数据@Beforepublic void setUp() {f1 = new Fraction(1, 2);  // 1/2f2 = new Fraction(1, 3);  // 1/3f3 = new Fraction(-2, 4); // -1/2 (约分)f4 = new Fraction(4, 8);  // 1/2 (约分)}//测试分数是否能够正确约分@Testpublic void testFractionReduction() {assertEquals("1/2", f4.toString()); // 4/8 应该被约分成 1/2}//测试负数分数的正确性@Testpublic void testNegativeFraction() {assertEquals("-1/2", f3.toString()); // -2/4 应该变成 -1/2}// 测试分数加法@Testpublic void testAddition() {assertEquals("5/6", f1.add(f2).toString()); // 1/2 + 1/3 = 5/6}//测试分数减法@Testpublic void testSubtraction() {assertEquals("1/6", f1.subtract(f2).toString()); // 1/2 - 1/3 = 1/6}//测试分数乘法@Testpublic void testMultiplication() {assertEquals("1/6", f1.multiply(f2).toString()); // 1/2 * 1/3 = 1/6}//测试分数除法@Testpublic void testDivision() {assertEquals("1'1/2", f1.divide(f2).toString()); // 1/2 ÷ 1/3 = 3/2}// 测试两个相等的分数是否被认为相等@Testpublic void testEquality() {assertEquals(new Fraction(1, 2), f4); // 1/2 应该等于 4/8}
}

表达式生成测试

import org.junit.Test;
import static org.junit.Assert.*;public class GeneratorTest {// 测试生成的表达式不超过最大值@Testpublic void testGeneratedExpressionWithinRange() {int maxValue = 10;Generator generator = new Generator(maxValue);Expression expr = generator.generate();Fraction result = expr.evaluate();String str = result.toString();// 解析带分数、假分数和整数三种情况int numerator;int denominator;if (str.contains("'")) { // 带分数格式,如 "2'1/2"String[] parts = str.split("'");int whole = Integer.parseInt(parts[0]);String[] fractionParts = parts[1].split("/");int remNumerator = Integer.parseInt(fractionParts[0]);denominator = Integer.parseInt(fractionParts[1]);numerator = whole * denominator + remNumerator;} else if (str.contains("/")) { // 假分数格式,如 "3/2"String[] fractionParts = str.split("/");numerator = Integer.parseInt(fractionParts[0]);denominator = Integer.parseInt(fractionParts[1]);} else { // 整数格式,如 "5"numerator = Integer.parseInt(str);denominator = 1;}int maxAllowed = maxValue * denominator;assertTrue("分子超过最大值" + maxAllowed + ",当前值为:" + numerator,numerator <= maxAllowed);}// 测试生成的表达式不为空@Testpublic void testGeneratedExpressionNotNull() {Generator generator = new Generator(10);Expression expr = generator.generate();assertNotNull(expr);}
}

以上测试代码在功能测试中是已经测试了基本运算的正确性,表达式的处理,分数的化简;边界测试中的最大最小值,特殊的分数格式;异常测试中的非法输入,文件操作异常。因此可以确定该程序能够正确运行

5.项目小结

本次项目的完成,我们是采用结对编程的方式进行开发。在合作中我们学到如何高效合作,高效沟通,快速分工,提高效率。通过先搭建起项目框架的,然后层层优化性能,最终得到此程序

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/902433.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ASE11N45-ASEMI智能家居专用ASE11N45

ASE11N45-ASEMI智能家居专用ASE11N45编辑:ll ASE11N45-ASEMI智能家居专用ASE11N45 型号:ASE11N45 品牌:ASEMI 封装:TO-252 批号:最新 最大漏源电流:11A 漏源击穿电压:450V RDS(ON)Max:0.39Ω 引脚数量:3 沟道类型:N沟道MOS管、中低压MOS管 漏电流:ua 特性:N沟道M…

sql 保留两位小数并强制向前进位的方法

使用CEILING函数 CEILING函数会返回大于或等于指定数值的最小整数值 例如,保留两位小数:select CEILING(0.0132*100)/100输出结果 这里,我们将数字乘以100(因为我们想保留两位小数),使用CEILING函数确保向上进位,然后再除以100以恢复原来的数值范围。

可行性分析[3]

第1章 系统分析 1.1 可行性分析 1.1.1 技术可行性分析 1.1.2 经济可行性分析 1.1.3 社会可行性分析 1.1.4 法律可行性分析 1.2 系统流程分析 1.2.1 系统开发总流程 1.2.2 登录流程 1.2.3 系统操作流程 1.2.4 系统性能分析 第1章 可行性分析 1.1可行性分析 随着生活水平的提高,…

PLM项目管理软件的未来:自动化与智能化的发展方向

PLM(产品生命周期管理)项目管理软件在现代企业的产品研发、生产与运营过程中扮演着至关重要的角色。它整合了从产品概念设计到退役处理的全流程信息,助力企业提升效率、降低成本并提高产品质量。随着科技的飞速发展,自动化与智能化成为 PLM 项目管理软件未来的核心发展方向…

研发效率提升30%的秘诀:PLM系统需求管理的6步工作法

在企业的研发过程中,提升效率是一个永恒的追求。研发效率的高低,直接影响着产品推向市场的速度,进而决定企业在竞争中的地位。而在众多影响研发效率的因素中,需求管理无疑是关键一环。PLM(产品生命周期管理)系统作为整合产品全生命周期信息的重要工具,其需求管理功能若能…

数字化转型,目的是为了转型还是数字化?

谢邀,这个问题问得很到位啊! 很多老板和员工都搞不明白,数字化转型到底是在搞什么?是单纯把业务搬到线上?还是整个公司要脱胎换骨? 今天咱们就掰开揉碎了聊,结合我这些年踩过的坑和看到的案例,给大家尽可能讲明白数字化转型到底是什么—— 先说结论:数字化转型的本质是…

Qt 有时嵌入的控件和窗体背景颜色不一样可设置 autoFillBackGround 这个属性

控件本身和作用它的布局都设置下这个属性,应该就可以解决控件颜色不一致的问题了吧。

发现《双影奇境》隐藏关卡!通关就获得独家情报?!

《双影奇境》真是太太太火了! 小编身边十个人里八个人都在玩!而且每个人都赞不绝口,狂夸里面的画面和关卡设计精美又好看。 最近甚至有人发现了地狱级的隐藏关卡!不仅挑战性拉满,通关奖励居然还包含了制作人亲笔签名的瑞典工作室邀请函! 今天小编就来为你解开这一神秘关卡…

远程控制中的云电脑是什么意思?1分钟学会用

很多常用我们ToDesk远程控制的朋友们或许会注意到无论是在PC端还是移动端中都出现有【云电脑】【来云电脑爽玩-新用户免费1小时】这些词句等信息。那么这究竟是代表什么意思呐?云电脑是什么又怎么用呐?为什么要增加云电脑?以下小T就为大家科普下!什么是云电脑?为什么要设云…

WPF 你真的会写 XAML 吗?浅谈 ControlTemplate 、DataTemplate 和其它 Template

本文介绍了 WPF 中关于各种 Template 的用法。WPF 你真的会写 XAML 吗?浅谈 ControlTemplate 、DataTemplate 和其它 Template本文希望从写死的代码慢慢引入 WPF 的一些机制。一、Button 难题 我们想要修改 Button 的背景色但是效果非常不理想,默认的 Button 样式是完全无法给…