软工第二次作业
软工作业2:个人项目-论文查重
GitHub链接: github
课程信息
- 课程: 计科22级2班 - 广东工业大学
- 作业要求: 作业要求
- 目标: 完成个人项目-论文查重;学会写单元测试
一、PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 60 | 30 |
Estimate | 估计这个任务需要多少时间 | 30 | 60 |
Development | 开发 | 300 | 420 |
Analysis | 需求分析 (包括学习新技术) | 60 | 30 |
Design Spec | 生成设计文档 | 60 | 60 |
Design Review | 设计复审 | 15 | 10 |
Coding Standard | 代码规范 | 15 | 10 |
Design | 具体设计 | 30 | 60 |
Coding | 具体编码 | 30 | 60 |
Code Review | 代码复审 | 15 | 10 |
Test | 测试(自我测试,修改代码,提交修改) | 15 | 60 |
Reporting | 报告 | 60 | 120 |
Test Report | 测试报告 | 30 | 60 |
Size Measurement | 计算工作量 | 10 | 10 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 10 | 20 |
合计 | 740 | 1020 |
二、设计与开发
编码规范
- 阿里巴巴开发规范插件
2.1 开发环境
- 操作系统: Windows
- 编程语言: JDK 1.8
2.2 开发工具
- Maven包管理工具
- IDE: IDEA 2022.3.1
- 性能分析工具: JProfiler 11.1.4
2.3 项目依赖
- JUnit测试框架
- Jieba-Java中文分词库
2.4 算法设计说明
longestCommonSubsequence (LCS) 算法
-
动态规划:
- 使用动态规划来计算 LCS。创建一个二维数组
dp
,其中dp[i][j]
表示前i
个字符和前j
个字符的 LCS 长度。 - 遍历两个字符串的每个字符:
- 如果字符相同,则 LCS 长度为
dp[i-1][j-1] + 1
。 - 如果字符不同,则 LCS 长度为
Math.max(dp[i-1][j], dp[i][j-1])
,即取左边或上边的最大值。
- 如果字符相同,则 LCS 长度为
- 使用动态规划来计算 LCS。创建一个二维数组
-
时间复杂度:
- LCS 算法的时间复杂度为 O(m × n),其中 m 和 n 分别是两个字符串的长度。
-
空间复杂度:
- 空间复杂度为 O(m × n),用于存储动态规划表。如果需要优化空间,可以只保留当前行和上一行的数据。
-
优点:
- LCS 算法简单直观,适合用于文本相似度检测。
- 结果能够有效反映文本之间的相似性。
-
缺点:
- 对于较长的文本,计算复杂度较高,可能导致性能问题。
- 仅依赖于字符匹配,无法捕捉文本的语义信息。
2.5 接口设计与实现过程
类设计与实现过程
1. 文件处理类 (FileHandler
)
设计目的
FileHandler
类的主要目的是封装文件操作,以便于读取和写入文本文件。通过将文件操作集中在一个类中,代码变得更加模块化,便于维护和重用。
实现过程
-
读取文件:
- 使用
Files.readAllBytes
方法读取文件内容,并转换为字符串。 - 处理可能的
IOException
,确保文件读取的安全性。
- 使用
-
写入文件:
- 使用
Files.writeString
方法将内容写入文件。添加了StandardOpenOption.APPEND
选项以确保内容被追加,而不是覆盖。 - 添加换行符,确保每次追加内容都在新的一行开始。
- 使用
2. 相似度计算类 (SimilarityCalculator
)
设计目的
SimilarityCalculator
类专注于计算文本之间的相似度,主要采用最长公共子序列(LCS)算法。将相似度计算逻辑与文件处理分开,有助于清晰地划分责任。
实现过程
-
计算相似度:
- 定义
calculateSimilarity
方法,接收两个字符串参数(原始文本和抄袭文本)。 - 调用
longestCommonSubsequence
方法计算 LCS 长度。 - 使用公式计算相似度,并通过
DecimalFormat
确保结果保留两位小数。
- 定义
-
LCS 算法实现:
- 使用两个一维数组
prev
和curr
,将空间复杂度优化为O(n)
。 - 通过动态规划遍历两个字符串,更新数组以计算 LCS 长度。
- 使用两个一维数组
主程序类 (PaperCheck
)
设计目的
PaperCheck
类作为程序的入口,负责协调文件处理和相似度计算的工作。它集成了其他两个类,形成完整的程序。
实现过程
- 主方法:
- 在
main
方法中创建FileHandler
和SimilarityCalculator
的实例。 - 调用
FileHandler
的readFile
方法读取原始文本和抄袭文本。 - 调用
SimilarityCalculator
的calculateSimilarity
方法计算相似度。 - 将相似度结果格式化并写入输出文件,同时打印到控制台。
- 在
三、测试与性能分析
3.1 测试
LCE算法优化:
-之前的实现:使用了一个二维数组 dp,其大小为 m x n,其中 m 和 n 是两个字符串的长度。这在处理较大字符串时,会占用大量内存。
-优化后的实现:只使用两个一维数组prev和curr,分别存储当前行和上一行的状态。这样,空间复杂度从O(m*n)降低到O(n),显着减少了内存使用。
运行时JProfiler分析
覆盖率
部分测试样例:测试LCS算法实现,主要通过正常参数和空参数进行测试
可能的异常
命令行参数不规则
直接判断处理
文本文件为空
直接判断然后结束程序