一、github链接
这个作业属于哪个课程 | 首页 - 计科22级12班 - 广东工业大学 - 班级博客 - 博客园 (cnblogs.com) |
---|---|
这个作业要求在哪里 | 个人项目 - 作业 - 计科22级12班 - 班级博客 - 博客园 (cnblogs.com) |
这个作业的目标 | 规范代码编写;学习模块化管理程序功能;学会写单元测试 |
二、PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 10 | 10 |
· Estimate | · 估计这个任务需要多少时间 | 10 | 10 |
Development | 开发 | 230 | 250 |
· Analysis | · 需求分析 (包括学习新技术) | 20 | 20 |
· Design Spec | · 生成设计文档 | 20 | 20 |
· Design Review | · 设计复审 | 20 | 20 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 20 | 20 |
· Design | · 具体设计 | 30 | 30 |
· Coding | · 具体编码 | 60 | 70 |
· Code Review | · 代码复审 | 30 | 40 |
· Test | · 测试(自我测试,修改代码,提交修改) | 30 | 30 |
Reporting | 报告 | 100 | 120 |
· Test Repor | · 测试报告 | 60 | 70 |
· Size Measurement | · 计算工作量 | 20 | 30 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 20 | 20 |
· 合计 | 340 | 380 |
三、模块接口的设计与实现过程
编码规范
阿里巴巴开发规范手册
3.1 开发环境
操作系统: Windows
编程语言: JDK 20
3.2 开发工具
Maven包管理工具
IDE: IDEA 2023.1.3
性能分析工具: JProfiler 11.1.4
3.3 项目依赖
JUnit测试框架
3.4 算法设计说明
longestCommonSubsequence (LCS) 算法
动态规划:
使用动态规划来计算 LCS。创建一个二维数组 dp,其中 dp[i][j] 表示前 i 个字符和前 j 个字符的 LCS 长度。
遍历两个字符串的每个字符:
1)如果字符相同,则 LCS 长度为 dp[i-1][j-1] + 1。
2)如果字符不同,则 LCS 长度为 Math.max(dp[i-1][j], dp[i][j-1]),即取左边或上边的最大值。
时间复杂度:
LCS 算法的时间复杂度为 O(m × n),其中 m 和 n 分别是两个字符串的长度。
空间复杂度:
空间复杂度为 O(m × n),用于存储动态规划表。如果需要优化空间,可以只保留当前行和上一行的数据。(剪枝)
优点:
1)LCS 算法简单直观,适合用于文本相似度检测。
2)结果能够有效反映文本之间的相似性。
缺点:
1)对于较长的文本,计算复杂度较高,可能导致性能问题。
2)仅依赖于字符匹配,无法捕捉文本的语义信息。
3.5 接口设计与实现过程
类设计与实现过程
1. 文件处理类 (FileHandler)
设计目的
FileHandler 类的主要目的是封装文件操作,以便于读取和写入文本文件。通过将文件操作集中在一个类中,代码变得更加模块化,便于维护和重用。
实现过程
函数1)读取文件:
使用 Files.readAllBytes 方法读取文件内容,并转换为字符串。
处理可能的 IOException,确保文件读取的安全性。
函数2)写入文件:
使用 Files.newBufferedWriter.write 方法将内容写入答案文件,并将输出的答案精确到小数点后两位
2. 相似度计算类 (SimilarityCalculator)
设计目的
SimilarityCalculator 类专注于计算文本之间的相似度,主要采用最长公共子序列(LCS)算法。将相似度计算逻辑与文件处理分开,有助于清晰地划分责任。
实现过程
函数1)计算相似度:
定义 calculateSimilarity 方法,接收两个字符串参数(原始文本和抄袭文本)。
调用 longestCommonSubsequence 方法计算 LCS 长度。
使用公式计算相似度,并通过 DecimalFormat 确保结果保留两位小数。
函数2)LCS 算法实现:
使用两个一维数组 prev 和 curr,将空间复杂度优化为 O(n)。
通过动态规划遍历两个字符串,更新数组以计算 LCS 长度。
3. 主程序类 (PaperPlagiarismChecker)
设计目的
PaperPlagiarismChecker 类作为程序的入口,负责协调文件处理和相似度计算的工作。它集成了其他两个类,形成完整的程序。
实现过程
主方法:
1)在 main 方法中创建 FileHandler 和 SimilarityCalculator 的实例。
2)调用 FileHandler 的 readFile 方法读取原始文本和抄袭文本。
3)调用 SimilarityCalculator 的 calculateSimilarity 方法计算相似度。
4)调用 FileHandler 的 writeFile 方法将相似度结果格式化并写入输出文件,同时打印到控制台。
四、模块接口部分的性能改进
改进计算文本重复率模块性能
LCE算法优化:
-之前的实现:使用了一个二维数组 dp,其大小为 m x n,其中 m 和 n 是两个字符串的长度。这在处理较大字符串时,会占用大量内存。
-优化后的实现:只使用两个一维数组prev和curr,分别存储当前行和上一行的状态。这样,空间复杂度从O(m*n)降低到O(n),显着减少了内存使用。
运行时JProfiler分析
五、模块部分单元测试展示
以下是以测试 SimilarityCalculator 为例
项目部分单元测试代码
@Test
public void testExactMatch() {SimilarityCalculator calc = new SimilarityCalculator();double similarity = calc.calculateSimilarity("hello", "hello");assertEquals(1.0, similarity, 0.001);
}
@Test
public void testSameCharactersDifferentOrder() {SimilarityCalculator calc = new SimilarityCalculator();double similarity = calc.calculateSimilarity("abc", "cba");assertEquals(0.3333, similarity, 0.001);
}
@Test
public void testPartialMatch() {SimilarityCalculator calc = new SimilarityCalculator();double similarity = calc.calculateSimilarity("hello", "helicopter");assertEquals(0.5333, similarity, 0.001);
}`
构造测试数据的思路:
通过输入两个简单字符串,来测试函数的准确性。包括考虑输入的两个字符串的字符不同、顺序不同、长度不同等多种实际情况。
覆盖率
六、模块部分异常处理说明
命令行参数不规则,直接判断处理
单元测试样例,错误对应的场景为传入的参数只传了1个,不够3个