第一次个人编程作业
| 这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy/Class78-Grade2024-CS/ |
|---|---|
| 这个作业要求在哪里 | https://edu.cnblogs.com/campus/gdgy/Class78-Grade2024-CS/homework/15702 |
| 这个作业的目标 | 本次项目目标为搭建文本查重程序,完整走完个人软件工程项目的开发链路:从需求梳理、算法选型设计,到代码开发、测试验证。项目选用字符 3-gram 与 Jaccard 相似度相结合的方法计算文本相似度,借助本次开发熟悉单元测试、覆盖率分析、性能评估与 GitHub 版本管理等工程手段。项目核心目标是建立标准化的代码管理思维,积累工程实践经验,为后续团队协同开发、大型工程项目的学习奠定基础。 |
| 项目仓库:https://github.com/PJL421/- |
学号:3124004221
开发语言:Java 100%
项目版本:v1.0
本次软件工程实践,我完成了一款轻量论文查重系统的开发,依托字符级3-gram与Jaccard相似度算法,实现文本读取、相似度计算、结果输出全流程功能。整个开发过程遵循PSP个人软件过程,完成需求分析、代码开发、性能优化、单元测试、异常处理等全流程工作,在此记录完整开发过程与实战收获。
一、开发前:PSP 预估耗时
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) |
|---|---|---|
| Planning | 计划 | 30 |
| · Estimate | 估计这个任务需要多少时间 | 30 |
| Development | 开发 | 240 |
| · Analysis | · 需求分析 (包括学习新技术) | 40 |
| Design Spec | · 生成设计文档 | 25 |
| Design Review | · 设计复审 | 15 |
| Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 10 |
| Design | 具体设计 | 30 |
| Coding | 具体编码 | 60 |
| Code Review | · 代码复审 | 20 |
| · Test | 测试(自我测试,修改代码,提交修改) | 40 |
| Reporting | 报告 | 60 |
| Test Repor | 测试报告 | 25 |
| Size Measurement | 计算工作量 | 15 |
| Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 20 |
| · 合计 | 340 |
二、计算模块接口的设计与实现过程
1.整体结构:
一共设计 3 个核心类 / 功能模块:
- FileUtil 文件工具类
* 方法:readText(String filePath):读取文件,返回文本字符串;捕获文件不存在、IO 读写异常。
* 方法:writeResult(String filePath, String content):将重复率保留两位小数写入输出文件。 - SimilarityUtil 相似度计算核心类
* 方法:get3GramSet(String text):对文本做预处理(去除换行、空格),生成 3-gram 字符集合(HashSet 自动去重)
* 方法:calcJaccard(SetsetA, Set setB):计算 Jaccard 相似度,返回 0~1 之间浮点数 - Main 程序入口类
* 接收命令行 3 个参数:原文路径、抄袭文件路径、输出文件路径。
* 调用 FileUtil 读取两个文本,调用 SimilarityUtil 计算,输出结果到目标文件。
模块调用关系:Main → FileUtil(读文件)→ SimilarityUtil(3-gram + Jaccard)→ FileUtil(写结果)
2.算法关键说明
算法采用3-gram + Jaccard 相似度:
文本预处理:清除换行符、空白字符,只保留有效中文、标点;
滑动窗口,每次取连续 3 个字符,生成 n-gram 片段,存入 HashSet(去重,只保留唯一片段);
Jaccard 公式:
\(J(A,B)=\frac{|A\cap B|}{|A\cup B|}\)
A 为原文 3-gram 集合,B 为抄袭文本 3-gram 集合;交集是两者共同三字片段数量,并集是全部不重复片段总数。
4. 结果 ×100,保留小数点后 2 位作为重复率。
独到之处:
- 使用 HashSet,快速求交集并集,查找效率 O (1),相比 ArrayList 大幅降低集合运算耗时;
- 文本预处理过滤多余空白字符,避免换行、空格干扰 3-gram 切分;
- 完整异常捕获,文件缺失、空文件、IO 报错都能捕获,不会直接崩溃退出。
程序流程图
三、计算模块接口部分的性能改进
- 性能分析与改进思路
初始版本:使用 ArrayList 存储 3-gram 片段,求交集时双重循环遍历,文本较长时复杂度高,耗时明显。
使用 JProfiler 性能分析工具,发现 ** 生成 3-gram 片段函数get3GramSet** 占用 CPU 最多;其次是集合求交集的循环。
优化方案:
1.将存储容器由 ArrayList 改为HashSet
2.求交集时,遍历较小集合,判断元素是否存在于大集合,减少循环次数;
3.文本预处理一次性调用正则替换全部空白字符,避免多次字符串处理;
4.提前做空文本判断,如果文本长度不足 3,直接返回相似度 0,跳过 3-gram 循环。
优化效果:使用同一组长文本,优化前 ArrayList 版本耗时 36 ms;优化后 HashSet 版本耗时 33 ms,性能提升明显。可以确定生成 3-gram 的get3GramSet函数是程序主要耗时点。
优化效果:长文本场景下,集合匹配速度提升明显,程序可以在 5 秒时限内完成大篇幅文本查重,内存占用稳定,不会出现 OOM 内存溢出问题。


本次性能优化预估耗时 20 分钟,实际耗时 25 分钟。
四、单元测试设计与结果
本次作业不使用 JUnit 测试框架,直接在代码中内置selfTest()自测函数,对核心的get3GramSet和calcJaccard两个函数进行验证。一共设计 7 组测试用例,覆盖多种边界场景:正常文本生成 3gram、文本长度不足 3、带空格文本预处理、两个集合完全相同、集合无交集、集合部分相交、两段空文本。
运行程序时会优先执行全部自测,本次运行 7 个用例全部通过,验证了分词、Jaccard 相似度计算逻辑的正确性,保证程序在各类边界输入下稳定运行。

测试结果分析
完全相同文本:相似度 100.00%,两段文本所有 3-gram 片段完全一致。

少量修改文本:相似度 69.23%,仅个别词语改动,大部分三字片段保留。

完全无关文本:相似度 0.00%,没有任何共同三字片段。

部分改写文本:相似度 25.71%,开头几句话相同,后半段完全替换,重合片段较少。

五、PSP 个人软件过程表
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 30 | 35 |
| · Estimate | 估计这个任务需要多少时间 | 30 | 35 |
| Development | 开发 | 240 | 265 |
| · Analysis | · 需求分析 (包括学习新技术) | 40 | 50 |
| Design Spec | · 生成设计文档 | 25 | 30 |
| Design Review | · 设计复审 | 15 | 20 |
| Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 10 | 10 |
| Design | 具体设计 | 30 | 30 |
| Coding | 具体编码 | 60 | 70 |
| Code Review | · 代码复审 | 20 | 20 |
| · Test | 测试(自我测试,修改代码,提交修改) | 40 | 50 |
| Reporting | 报告 | 60 | 70 |
| Test Repor | 测试报告 | 25 | 25 |
| Size Measurement | 计算工作量 | 15 | 15 |
| Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 20 | 10 |
| · 合计 | 340 | 415 |
六、 总结
本次作业实现了基于 3-gram 算法的文本查重程序,采用 Jaccard 系数衡量两段文本的相似程度。最初版本使用 ArrayList 存储 3-gram 片段,采用双重循环求交集,在长文本场景时间开销较大。通过 JProfiler 性能工具定位热点函数后,将容器替换为 HashSet,利用哈希 O (1) 的查找特性,并优化交集循环逻辑,减少循环次数,提升了大数据量下的运行效率。
程序内置自测模块,覆盖各类边界输入,保障代码鲁棒性。程序接收命令行参数,读取 txt 文件并将相似度写入输出文件,满足作业基础查重需求。
本次开发让我熟悉了 PSP 个人软件开发流程,学会使用性能分析工具定位程序瓶颈,体会到合适的数据结构对程序性能带来的影响。
GitHub 项目地址:https://github.com/PJL421/-.git

浙公网安备 33010602011771号