当前位置: 首页 > news >正文

软工第二次作业——个人项目

软工第二次作业——个人项目

------------恢复内容开始------------

一、作业信息

这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/Class12Grade23ComputerScience
这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/Class12Grade23ComputerScience/homework/13469
这个作业的目标 创建GitHub账号,建立个人博客,进行自我介绍,对软件工程提出问题,初步认识软件工程

GitHub仓库:https://github.com/fengpengGG/3123004349

二、PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 60 100
Estimate 估计这个任务需要多少时间 30 30
Development 开发 200 300
Analysis 需求分析(包括学习新技术) 2000 2000+
Design Spec 生成设计文档 120 150
Design Review 设计重审 45 60
Coding Standard 代码规范 (为目前的开发制定合适的规范) 100 120
Design 具体设计 100 200
Coding 具体编码 3000 3000
Code Review 代码复审 200 400
Test 测试(自我测试,修改代码,提交修改) 200 500
Reporting 报告 100 150
Test Repor 测试报告 100 150
Size Measurement 计算工作量 30 30
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 60 120
合计 6345 7180

总结:由于没怎么接触过类似的项目,所以在学习新技术和方法,比如git,性能测试,单元测试等,具体编码和测试代码阶段花了比预想长很多的时间

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

(一)关系分析

计算模块(Check.h)是文本相似度检测功能的核心,其设计需与数据读取模块(FileHandling.h)、文本预处理模块(TextPreprocess.h)协同工作,整体结构采用 “分层协作” 模式,具体组织如下:

1.核心类与函数的划分

Check 类:封装相似度计算的核心逻辑,对外提供静态接口函数,无需实例化。
核心函数:static double calculate_similarity(const vector& words1, const vector& words2)
功能:接收两个预处理后的分词结果,返回两者的相似度

2. 类之间的依赖关系

计算模块依赖其他模块的输出作为输入,具体关系如下:
FileHandling.h 模块:负责读取原始文本文件(如源文件、抄袭文件),输出原始字符串;
TextPreprocess.h 模块:接收原始字符串,进行预处理全半角转换、去标点、分词等,输出分词结果;
Check.h 模块:接收 TextPreprocess.h 输出的两个分词结果,计算并返回相似度;
最终通过 FileHandling.h 将相似度结果写入输出文件。
整体数据流向:FileHandling.read_file() → TextPreprocess.process_text() → Check.calculate_similarity() → FileHandling.write_result()。

(二)关系函数流程图

屏幕截图 2025-09-23 163856

(三)算法关键

计算模块采用 Jaccard 系数算法 作为核心,其核心思想如下:
Jaccard 系数基础:原始公式为 J(A,B)= ∣A∪B∣/∣A∩B∣
其中 A 和 B 是两个集合。
词频适配:针对文本分词结果(含重复词),将 “集合” 扩展为 “带频率的词集合”:
交集:每个词在两个文本中出现次数的最小值之和(反映共同出现的词的重叠程度);
并集:每个词在两个文本中出现次数的最大值之和(反映两个文本的总信息量);
相似度 = 交集 / 并集

(四)独到之处

边界情况全覆盖:处理 “两个文本均为空”“其中一个为空”“并集为 0” 等极端情况,避免程序崩溃或无效输出;
结果约束:通过 max(0.0, min(1.0, similarity)) 确保输出相似度严格在 0-1 区间内。
接口设计通用:输入为标准容器 vector,与任何文本预处理模块兼容,若更换分词方式,无需修改计算逻辑;
算法易替换:Check 类封装了计算逻辑,若需替换为余弦相似度等其他算法,只需修改 calculate_similarity 函数内部实现,不影响其他模块。

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

性能改进前:
屏幕截图 2025-09-22 234839
修改性能后:
屏幕截图 2025-09-22 235006
修改之后可见核心函数cpu占比降低,内核开销减少,内存使用平稳。
消耗时间:性能改进时间为2小时左右。

(一)改进思路:

从文件读写,文本预处理,相似度计算三个方面进行优化。其中文本预处理的性能需求最高。
文件读取:
模块增大缓冲区,减少调用次数。
文本预处理:
用string_view替代substr,因为substr会频繁创建临时字符串,内存开销大。
预分配vector空间
相似度计算:
用单哈希表统计词频,简化哈希操作,减少遍历开销

代码中消耗最大的函数:Textpreprocess::segment_words
是文本预处理的核心函数,负责将清洗后的原始文本拆分为词语序列。其处理对象是原始文本的每个字符,处理规模与输入文本的总字符数直接相关。

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

#include <gtest/gtest.h>
#include <vector>
#include "Check.h"// 测试用例1:两个空文本(边界条件)
TEST(SimilarityTest, BothEmptyTexts) {vector<string> words1;vector<string> words2;double result = Check::calculate_similarity(words1, words2);ASSERT_NEAR(result, 1.0, 0.001); // 空文本视为完全相似
}// 测试用例2:一个空文本,一个非空文本(边界条件)
TEST(SimilarityTest, OneEmptyText) {vector<string> words1 = { "苹果", "香蕉", "橙子" };vector<string> words2;double result = Check::calculate_similarity(words1, words2);ASSERT_NEAR(result, 0.0, 0.001); // 空文本与非空文本相似度为0
}// 测试用例3:完全相同的文本(典型场景)
TEST(SimilarityTest, IdenticalTexts) {vector<string> words1 = { "今天", "天气", "很好", "适合", "散步" };vector<string> words2 = { "今天", "天气", "很好", "适合", "散步" };double result = Check::calculate_similarity(words1, words2);ASSERT_NEAR(result, 1.0, 0.001); // 完全相同相似度为1
}// 测试用例4:完全不同的文本(典型场景)
TEST(SimilarityTest, TotallyDifferentTexts) {vector<string> words1 = { "计算机", "程序", "算法" };vector<string> words2 = { "苹果", "香蕉", "橙子" };double result = Check::calculate_similarity(words1, words2);ASSERT_NEAR(result, 0.0, 0.001); // 无重叠词相似度为0
}// 测试用例5:部分重叠(词频相同)
TEST(SimilarityTest, PartialOverlapSameFrequency) {vector<string> words1 = { "猫", "狗", "鸟", "鱼" };vector<string> words2 = { "猫", "狗", "兔", "熊" };// 交集:"猫"、"狗" → 2;并集:"猫"、"狗"、"鸟"、"鱼"、"兔"、"熊" → 6 → 2/6≈0.333double result = Check::calculate_similarity(words1, words2);ASSERT_NEAR(result, 0.333, 0.001);
}// 测试用例6:部分重叠(词频不同)
TEST(SimilarityTest, PartialOverlapDifferentFrequency) {vector<string> words1 = { "书", "书", "笔", "纸" }; // 书:2, 笔:1, 纸:1vector<string> words2 = { "书", "笔", "笔", "橡皮" }; // 书:1, 笔:2, 橡皮:1// 交集:min(2,1) + min(1,2) = 1+1=2;并集:max(2,1)+max(1,2)+max(1,0)+max(0,1)=2+2+1+1=6 → 2/6≈0.333double result = Check::calculate_similarity(words1, words2);ASSERT_NEAR(result, 0.333, 0.001);
}// 测试用例7:包含重复词的文本
TEST(SimilarityTest, TextsWithDuplicateWords) {vector<string> words1 = { "重复", "重复", "重复" };vector<string> words2 = { "重复", "重复" };// 交集:min(3,2)=2;并集:max(3,2)=3 → 2/3≈0.667double result = Check::calculate_similarity(words1, words2);ASSERT_NEAR(result, 0.667, 0.001);
}// 测试用例8:包含停用词(已过滤后的场景)
TEST(SimilarityTest, TextsWithStopWordsFiltered) {vector<string> words1 = { "的", "是", "重要", "的" }; // 假设停用词"的"未被过滤vector<string> words2 = { "的", "是", "关键", "的" };// 交集:"的":min(2,2)=2,"是":min(1,1)=1 → 3;并集:"的":2,"是":1,"重要":1,"关键":1 → 5 → 3/5=0.6double result = Check::calculate_similarity(words1, words2);ASSERT_NEAR(result, 0.6, 0.001);
}// 测试用例9:中英文混合文本
TEST(SimilarityTest, MixedChineseEnglishTexts) {vector<string> words1 = { "hello", "世界", "python", "编程" };vector<string> words2 = { "hello", "python", "java", "世界" };// 交集:"hello"、"世界"、"python" → 3;并集:4+4-3=5 → 3/5=0.6double result = Check::calculate_similarity(words1, words2);ASSERT_NEAR(result, 0.6, 0.001);
}// 测试用例10:超长文本(性能与正确性验证)
TEST(SimilarityTest, LongTexts) {vector<string> words1, words2;// 构造超长文本(各1000个词,重叠率50%)for (int i = 0; i < 1000; i++) {words1.push_back("词" + to_string(i));if (i % 2 == 0) words2.push_back("词" + to_string(i)); // 偶数索引词重叠}for (int i = 1000; i < 1500; i++) {words2.push_back("词" + to_string(i)); // 新增500个不重叠词}// 交集:500(偶数词);并集:1000 + 1500 - 500 = 2000 → 500/2000=0.25double result = Check::calculate_similarity(words1, words2);ASSERT_NEAR(result, 0.333, 0.001);
}// 自定义main函数(若不使用gtest_main.lib)
int main(int argc, char** argv) {testing::InitGoogleTest(&argc, argv);return RUN_ALL_TESTS();
}

屏幕截图 2025-09-23 191903

思路:

1.边界场景覆盖

一个空文本,两个都是空文本

2.核心逻辑验证

完全相同文本和完全不同文本验:证算法基础正确性
部分重叠文本:验证交集和并集的计算逻辑。

3.特殊场景适配

重复词:测试算法对词频权重的处理
停用词和中英混合:验证算法对多类型文本的兼容性。

所有测试用例通过,表明calculate_similarity函数在边界条件、典型场景和特殊场景下均能返回正确结果

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

1.无法打开文件

当指定路径的文件不存在、路径格式错误、文件被占用或无读取权限时,及时抛出异常,避免程序在未正确打开文件的情况下进行后续读写操作,防止不可预期的内存错误或逻辑异常。

读取不存在的片段:

#include <iostream>
#include "FileHandling.h"
using namespace std;int main() {string invalid_path = "C:\\nonexistent_file.txt"; // 不存在的文件路径try {string content = FileHandling::read_file(invalid_path);} catch (const runtime_error& e) {cout << "捕获异常:" << e.what() << endl;}return 0;
}

结果:
image

2.无法打开结果文件

当结果文件路径无效、无写入权限或文件被其他程序锁定时,抛出异常。防止程序在无法写入结果的情况下继续执行,确保相似度计算结果能正确保存到指定路径。

结果文件路径的目录不存:

#include <iostream>
#include "FileHandling.h"
using namespace std;int main() {string invalid_result_path = "C:\\invalid_dir\\result.txt"; // 目录不存在try {FileHandling::write_result(invalid_result_path, 0.85);} catch (const runtime_error& e) {cout << "捕获异常:" << e.what() << endl;}return 0;
}

结果:
image

3.写入结果文件失败

文件成功打开后,若写入过程中出现错误(如磁盘满、文件被突然删除),导致写入状态异常时,抛出异常。确保相似度结果能完整写入文件,避免生成空文件或不完整的结果。

写入时磁盘空间不足(可模拟为向只读文件写入)。
image

#include <iostream>
#include "FileHandling.h"
using namespace std;int main() {string read_only_path = "C:\\read_only_file.txt"; // 手动设置为只读的文件try {FileHandling::write_result(read_only_path, 0.72);} catch (const runtime_error& e) {cout << "捕获异常:" << e.what() << endl;}return 0;
}

结果:
image
------------恢复内容结束------------

http://www.hskmm.com/?act=detail&tid=14998

相关文章:

  • 近十年 CSP-J 复赛知识点分布表
  • AT_arc181_d [ARC181D] Prefix Bubble Sort
  • 【MySQL】使用C/C++链接mysql数据库 - 指南
  • 枚举子集
  • cv-css 快捷方式,将指定节点的计算样式获取下拉 获取tailwind网页样式成原生样式
  • day002
  • PyTorch图神经网络(四)
  • 软件工程:构建数字世界的基石
  • Avalonia 学习笔记07. Control Themes(控件主题)
  • matter 协议的架构;
  • matter 协议解析;
  • 9月23日
  • Nordic 的支持对Matter 协议的支持;
  • nRF54LM20A USB
  • nRF54LM20A GRTC
  • 2025年10款最佳生产力提效chrome插件推荐,亲测有用
  • Avalonia 学习笔记06. Page Layout(页面布局)
  • 发表第一篇文章,谈谈对软件工程的理解
  • nRF54LM20A 芯片分析;
  • 第二天
  • 内部类
  • NRF54L15 两者结合的jlink保护机制(硬件+软件)
  • 软件测试员的核心技能:一文掌握等价类划分与边界值分析
  • 《CBI 技术有聊》对话 OpenCSG:智能体落地困境与企业转型的必然路径
  • 个人对软件工程的理解
  • 9/23
  • NUMERICAL RESULT (2025/09/23)
  • 数组入门:从零基础到排序算法 - 教程
  • 用C/C++重构PowerShell:全面绕过安全机制的技术解析
  • Optuna v4.5新特性深度解析:GPSampler实现约束多目标优化