软件工程第一次编程作业

news/2025/9/21 18:06:07/文章来源:https://www.cnblogs.com/ironlifes/p/19103841
这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience
这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience/homework/13477
这个作业的目标 实现一个3000字以上论文查重程序

github地址:https://github.com/ironlifes/3123004784


一、PSP表格如下

Process Stages Process Stages (中文) 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 20 15
· Estimate · 估计这个任务需要多少时间 190 240
Development 开发 200 180
· Analysis · 需求分析 (包括学习新技术) 120 120
· Design Spec · 生成设计文档 15 15
· Design Review · 设计复审 25 25
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 20 10
· Design · 具体设计 40 50
· Coding · 具体编码 50 70
· Code Review · 代码复审 30 55
· Test · 测试(自我测试,修改代码,提交修改) 20 30
Reporting 报告 70 90
· Test Report · 测试报告 40 50
· Size Measurement · 计算工作量 20 20
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 20 10
· 合计 880 980

二、计算模块接口的设计与实现过程

1、程序整体结构

d:\java code\rjgc/
├── src/                 # 源代码目录
│   ├── Main.java        # 主程序入口和测试类
│   ├── PaperChecker.java    # 原始论文查重实现
│   ├── OptimizedPaperChecker.java # 优化版论文查重算法
│   └── PerformanceAnalyzer.java   # 性能分析工具类
├── out/                 # 编译输出目录
│   └── production/rjgc/ # 编译后的class文件
├── orig.txt             # 原始论文文本文件
├── orig_add.txt         # 抄袭版论文文本文件
├── ans.txt              # 查重结果输出文件
└── .idea/               # IntelliJ IDEA配置文件

2、程序流程图

graph TD%% 全局设置classDef user fill:#add8e6,stroke:#000000;classDef entry fill:#90ee90,stroke:#000000;classDef algorithm fill:#ffffcc,stroke:#000000;classDef performance fill:#ffb6c1,stroke:#000000;classDef data fill:#b0e0e6,stroke:#000000;classDef specificAlgorithm fill:#fffacd,stroke:#000000;%% 用户层subgraph "用户层" user[用户]:::userend%% 入口层subgraph "入口层" main["Main.java\n测试入口"]:::entrypaperCheckerMain["PaperChecker.java\n主程序入口"]:::entryend%% 算法层subgraph "算法层" paperChecker["PaperChecker.java\n基础算法实现"]:::algorithmoptimizedPaperChecker["OptimizedPaperChecker.java\n优化算法实现"]:::algorithm%% 具体算法cosineSimilarity["余弦相似度算法"]:::specificAlgorithmsimpleMatch["简单词频匹配算法"]:::specificAlgorithmjaccardSimilarity["Jaccard相似度算法"]:::specificAlgorithmsimHash["SimHash算法"]:::specificAlgorithmend%% 性能分析层subgraph "性能分析层" performanceAnalyzer["PerformanceAnalyzer.java\n性能分析工具"]:::performanceend%% 数据层subgraph "数据层" fileIO["文件读写操作"]:::datatokenization["文本分词处理"]:::datatfCalculation["词频计算"]:::dataend%% 连接关系 - 用户交互user -->|运行主程序| paperCheckerMainuser -->|运行测试| main%% 主程序流程paperCheckerMain -->|读取文件| fileIOpaperCheckerMain -->|调用算法| paperCheckerpaperCheckerMain -->|写入结果| fileIOpaperCheckerMain -->|记录性能| performanceAnalyzer%% 测试流程main -->|测试基础算法| paperCheckermain -->|测试优化算法| optimizedPaperCheckermain -->|记录测试性能| performanceAnalyzer%% 算法调用关系paperChecker -->|默认算法| cosineSimilaritypaperChecker -->|可选算法| simpleMatchpaperChecker -->|可选算法| jaccardSimilaritypaperChecker -->|分词| tokenizationpaperChecker -->|计算词频| tfCalculationoptimizedPaperChecker -->|优化版本| cosineSimilarityoptimizedPaperChecker -->|新增算法| simHashoptimizedPaperChecker -->|优化分词| tokenizationoptimizedPaperChecker -->|优化词频计算| tfCalculation%% 性能分析调用paperChecker -->|性能监控| performanceAnalyzeroptimizedPaperChecker -->|性能监控| performanceAnalyzer%% 辅助流程cosineSimilarity -->|使用词频| tfCalculation%% 图例说明legend["图例说明:"]legend --> legend1["→ 数据流向"]legend --> legend2[":::user 用户层"]legend --> legend3[":::entry 入口层"]legend --> legend4[":::algorithm 算法层"]legend --> legend5[":::performance 性能分析层"]legend --> legend6[":::data 数据层"]

3、算法关键与独到之处

3.1 余弦相似度算法

  • 核心思想:将文本转换为向量空间中的向量,计算两个向量之间的夹角余弦值
  • 实现步骤:文本分词 → 计算词频 → 构建向量 → 计算余弦值
  • 独到之处:考虑了词频因素,对于较长文本有较好的区分度

3.2 SimHash算法

  • 核心思想:将高维特征向量压缩为低维指纹,通过汉明距离衡量相似度
  • 实现步骤:文本分词 → 计算每个词的哈希值 → 更新向量 → 生成最终哈希值
  • 独到之处:适用于大规模文本比较,计算效率高,空间占用小

三、计算模块接口部分的性能改进

1、性能改进思路

1.1 分词算法优化

  • 将正则表达式分词改为字符遍历分词
  • 对于中文文本,采用更高效的二元语法分词策略
  • 使用StringBuilder代替字符串拼接操作

1.2 词频计算优化

  • 预分配HashMap容量,减少扩容开销
  • 使用compute方法替代getOrDefault+put操作

1.3 余弦相似度计算优化

  • 选择较小的集合进行迭代,减少循环次数
  • 预先计算向量模长,避免重复计算

1.4 新增SimHash算法

  • 针对大文本比较场景,提供更高效的相似度计算方法
  • 使用位运算优化哈希值计算过程

2、性能分析图

image

3、性能对比数据

操作 原始算法耗时(ms) 优化算法耗时(ms) 性能提升
文件读取 0.456 0.280 ~39%
文件写入 0.321 0.215 ~33%
文本分词 2.143 1.331 ~38%
词频计算 1.897 0.942 ~50%
余弦相似度计算 3.568 1.476 ~59%
整体性能 45.32 15.637 ~66%

四、计算模块部分单元测试展示

1、单元测试代码

/*** 测试基本功能*/
private static void testBasicFunctionality() {System.out.println("\n--- 基本功能测试 ---");String original = "今天是星期天,天气晴,今天晚上我要去看电影。";String plagiarized = "今天是周天,天气晴朗,我晚上要去看电影。";String different = "这是一段完全不同的文本内容,与原文没有任何关系。";// 测试相同文本double sameSimilarity = PaperChecker.calculateSimilarity(original, original);System.out.printf("相同文本相似度: %.2f%%\n", sameSimilarity);// 测试相似文本double similarSimilarity = PaperChecker.calculateSimilarity(original, plagiarized);System.out.printf("相似文本相似度: %.2f%%\n", similarSimilarity);// 测试不同文本double differentSimilarity = PaperChecker.calculateSimilarity(original, different);System.out.printf("不同文本相似度: %.2f%%\n", differentSimilarity);
}/*** 测试多种算法*/
private static void testDifferentAlgorithms() {System.out.println("\n--- 多种算法测试 ---");String original = "今天是星期天,天气晴,今天晚上我要去看电影。";String plagiarized = "今天是周天,天气晴朗,我晚上要去看电影。";double cosineSimilarity = PaperChecker.calculateSimilarityWithCosine(original, plagiarized);double simpleMatchSimilarity = PaperChecker.calculateSimilarityWithSimpleMatch(original, plagiarized);double jaccardSimilarity = PaperChecker.calculateSimilarityWithJaccard(original, plagiarized);double simHashSimilarity = OptimizedPaperChecker.calculateSimilarityWithSimHash(original, plagiarized);System.out.printf("余弦相似度: %.2f%%\n", cosineSimilarity);System.out.printf("简单匹配相似度: %.2f%%\n", simpleMatchSimilarity);System.out.printf("Jaccard相似度: %.2f%%\n", jaccardSimilarity);System.out.printf("SimHash相似度: %.2f%%\n", simHashSimilarity);
}/*** 大规模数据测试*/
private static void testLargeScaleData() {System.out.println("\n--- 大规模数据测试 ---");// 创建大规模测试数据StringBuilder originalBuilder = new StringBuilder();StringBuilder plagiarizedBuilder = new StringBuilder();for (int i = 0; i < 10000; i++) {originalBuilder.append("这是一段用于大规模测试的文本内容,包含各种不同的词汇和句子结构。");if (i % 7 != 0) { // 约70%的内容保持一致plagiarizedBuilder.append("这是一段用于大规模测试的文本内容,包含各种不同的词汇和句子结构。");} else {plagiarizedBuilder.append("这是替换后的不同内容,用于测试算法在大规模数据下的表现和准确性。");}}String original = originalBuilder.toString();String plagiarized = plagiarizedBuilder.toString();// 测试优化算法和SimHash算法long startTime = System.currentTimeMillis();double optimizedResult = OptimizedPaperChecker.optimizedCalculateSimilarity(original, plagiarized);long optimizedTime = System.currentTimeMillis() - startTime;startTime = System.currentTimeMillis();double simHashResult = OptimizedPaperChecker.calculateSimilarityWithSimHash(original, plagiarized);long simHashTime = System.currentTimeMillis() - startTime;System.out.println("===== 大规模数据测试结果 ====");System.out.printf("优化余弦相似度算法: %d ms, 结果: %.2f%%\n", optimizedTime, optimizedResult);System.out.printf("SimHash算法: %d ms, 结果: %.2f%%\n", simHashTime, simHashResult);System.out.printf("预期相似度约为70%%,因为约30%%的内容被替换\n");
}

2、测试数据构造思路

2.1 基本功能测试

  • 构造相同文本:验证算法是否能正确识别完全相同的文本
  • 构造相似文本:验证算法对近义词、语序变化的敏感度
  • 构造不同文本:验证算法对完全不同内容的区分能力

2.2 多种算法测试

  • 使用相同的测试数据对比四种不同算法的结果差异
  • 分析各算法的优缺点和适用场景

2.3 大规模数据测试

  • 生成包含10000段文本的大规模测试数据
  • 控制相似度比例(约70%内容相同),验证算法在大数据量下的性能和准确性

五、计算模块部分异常处理说明

1、异常设计目标

本系统设计了以下几种异常处理机制,确保系统在各种情况下能够稳定运行:

参数验证异常:确保程序接收到正确的参数格式和数量
文件操作异常:处理文件不存在、权限不足等问题
内存溢出防护:避免处理超大文件时出现内存问题
算法计算异常:确保在边界情况下(如空文本)算法能够正常工作

2、异常处理示例

参数验证异常

public static void main(String[] args) {if (args.length != 3) {System.out.println("Usage: java -jar main.jar [原文文件] [抄袭版论文的文件] [答案文件]");System.exit(1);}// 后续代码...
}

场景说明:当用户未提供正确数量的命令行参数时,系统会显示正确的使用方法并退出,避免后续代码因参数错误而崩溃。

文件操作异常

try {// 开始测量整个程序执行时间PerformanceAnalyzer.start("整个程序执行");String originalText = readFile(originalFilePath);String plagiarizedText = readFile(plagiarizedFilePath);double similarity = calculateSimilarity(originalText, plagiarizedText);writeFile(outputFilePath, similarity);// 结束测量并打印性能统计PerformanceAnalyzer.end("整个程序执行");PerformanceAnalyzer.printStatistics();
} catch (Exception e) {e.printStackTrace();
}

场景说明:当文件不存在、路径错误或权限不足时,系统会捕获异常并打印详细的错误信息,方便用户排查问题。

边界情况处理

// 计算余弦相似度
static double calculateCosineSimilarity(Map<String, Integer> tf1, Map<String, Integer> tf2) {// 计算点积double dotProduct = 0;for (String word : tf1.keySet()) {if (tf2.containsKey(word)) {dotProduct += tf1.get(word) * tf2.get(word);}}// 计算向量长度double magnitude1 = 0;for (int count : tf1.values()) {magnitude1 += count * count;}magnitude1 = Math.sqrt(magnitude1);double magnitude2 = 0;for (int count : tf2.values()) {magnitude2 += count * count;}magnitude2 = Math.sqrt(magnitude2);// 计算余弦相似度if (magnitude1 == 0 || magnitude2 == 0) {return 0;  // 处理空向量情况}return dotProduct / (magnitude1 * magnitude2);
}

场景说明:当输入为空文本或两个文本没有共同词汇时,会出现向量模长为0的情况,此时返回相似度为0,避免除零异常。


六、总结

本论文查重系统通过采用多种相似度计算算法,实现了高效准确的文本相似度检测功能。通过性能分析和优化,我们成功将系统整体性能提升了约66%,特别是在处理大规模文本时表现更为突出。

系统的主要亮点包括:

  • 支持多种相似度计算算法(余弦相似度、简单词频匹配、Jaccard相似度、SimHash)
  • 提供了全面的性能分析工具,方便开发者进行性能优化
  • 针对中文文本特点进行了专门的分词优化
  • 具备良好的异常处理机制,确保系统稳定运行
  • 提供了丰富的测试方法,便于功能验证和性能评估

通过本项目,我不仅学习了各种文本相似度计算算法的原理和实现方法,还深入了解了性能分析和优化的技巧,提高了系统设计和代码实现的能力。

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

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

相关文章

WO Mic - 免费麦克风

WO Mic可以将您的手机变成电脑麦克风。您无需支付一分钱购买任何设备。如果您选择无线传输,它也是便携的。数百万用户已经安装并每天都在使用它进行通话、录音、语音遥控等活动。 三大组件协同工作以实现这一点:WO M…

AudioRelay —— 让电脑使用手机的麦克风和扬声器

写在前面 总所周知,电脑的麦克风和扬声器一直是很垃圾的水平,和手机相比差了很多,那能不能使用手机的硬件设备来给电脑使用呢,也能省个音箱的钱呢?答案是可以的。那就是使用AudioRelay。前段时间介绍了WO Mic,他…

【小白学算法】矩阵快速幂超详细解析+例题[HDU - 2802]

用于高效解决线性递推问题 前言 在算法竞赛和实际编程中,我们经常遇到需要计算矩阵的高次幂的问题。如果直接用朴素的矩阵乘法来计算,时间复杂度会达到O(n k),其中n是矩阵的维度,k是幂次。当k非常大时(比如\(10^…

lyms 的神秘歌单

关于这个闲话。还有 50 min 就要回 whk 了,我们可以干点什么呢?wy_x and lyms : 写闲话!所以就写。 说实在的根本不知道能写什么。 要不然给自己喜欢的曲子列个列表。 就当是什么神秘歌单了。 update on 9.21 推什么…

大学园区二手书交易强大的平台(代码+数据库+LW)

大学园区二手书交易强大的平台(代码+数据库+LW)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas",…

深入解析:SpringMVC的请求接收与结果响应

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

Element UI框架中自定义input组件的placeholder样式

Element UI是基于Vue.js的组件库,提供了一系列的组件,方便在Vue应用程序中快速使用。对于自定义input组件的placeholder样式,可以通过CSS覆盖默认样式来实现。以下是对Element UI中input组件的placeholder样式自定义…

go语言数组的方法

go语言数组的方法 漫思

【C++】类与结构体的区别

区别 技术上 实际上类与结构体在技术层面除了可见性并没有区别,唯一值得一提的区别就是: class类默认情况下其中的变量、函数都为private私有的。 struct结构体默认情况下则都是public公共的。 用法上 何时使用class…

Linux云端服务器上部署Spring Boot应用

在Linux云服务器上部署Spring Boot应用环境准备:确保Java JDK已安装。Spring Boot通常需要Java 8或更高版本。使用 java -version来确认Java版本。 安装Maven(如果是Maven项目)或Gradle(如果是Gradle项目),这取决…

HTML表单验证:确认input元素输入为具有特定整数和小数位数的数值

为了确保HTML表单中的 input元素接收具有特定整数位和小数位数的数值,您需要利用HTML和JavaScript进行前端验证。在HTML5中,可以使用内建的表单验证功能,比如 pattern属性,然而 pattern属性主要用于字符串的正则表…

课前问题思考3

1.什么样的方法应该用static修饰?不用static修饰的方法往往具有什么特性?Student的getName应该用static修饰吗?什么样的方法应该用static修饰?方法不依赖于类的实例状态。 方法提供的功能与类的实例无关。 工具类方…

实用指南:Docker部署Drawnix开源白板工具

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

go静态方法

go静态方法 漫思

在CentOS上配置SVN至Web目录的自动同步

配置SVN(Subversion)到Web目录的自动同步在CentOS系统中是一种有效的代码部署方法,它可以让团队成员更便捷地管理和发布Web项目。以下是如何在CentOS上实现SVN仓库到Web目录的自动同步的详细步骤。= 1. 安装并配置S…

AIGC在游戏开发中的革命性影响:从生产效率到体验创新 - 详解

AIGC在游戏开发中的革命性影响:从生产效率到体验创新 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Cons…

使用Docker配置并连接HBase的Java API

配置并使用Docker容器化HBase,并通过Java API进行连接,首先涉及到Docker配置HBase环境以及编写Java代码以编程方式连接HBase。以下是这一流程的具体步骤。 使用Docker部署HBase获取HBase镜像:使用Docker Hub提供的官…

在Linux环境下安装和卸载DMETL5数据迁移工具

在Linux环境下,安装和卸载特定的数据迁移工具,如DMETL5,通常涉及到一系列具体步骤。由于DMETL5不是一个广泛认知的公共软件,我们可以遵循一般的Linux软件安装和卸载流程来讨论这个问题。 安装DMETL5数据迁移工具 通…

赛前训练3 欧拉路

以下,斜体表示注意点,粗体表示技巧点。 无向图欧拉路径的判定:除去孤点之外图联通。度数为奇数的点只有 \(0\) 或 \(2\) 个。有向图欧拉路径的判定:除去孤点之外图联通。出度比入度大一或入度比出度大一的有 \(0\)…

HDFS 纠删码技术(Erasure Coding, EC)详解 - 指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …