软工第一次个人编程作业
软工第一次个人编程作业
|
软件工程 |
|
|
作业要求 |
|
|
作业目标 |
按软件设计开发流程设计实现论文查重程序 |
PSP表格
|
PSP2.1 |
Personal Software Process Stages |
预估耗时(分钟) |
实际耗时(分钟) |
|
Planning |
计划 |
25 |
45 |
|
Development |
开发 |
360 |
480 |
|
Analysis |
需求分析 (包括学习新技术) |
160 |
220 |
|
Coding Standard |
代码规范 (为目前的开发制定合适的规范) |
10 |
15 |
|
Design |
具体设计 |
60 |
35 |
|
Coding |
具体编码 |
130 |
120 |
|
Code Review |
代码复审 |
10 |
13 |
|
Test |
测试(自我测试,修改代码,提交修改) |
90 |
37 |
|
Reporting |
报告 |
90 |
90 |
|
Test Report |
测试报告 |
30 |
40 |
|
Postmortem & Process Improvement Plan |
事后总结, 并提出过程改进计划 |
30 |
30 |
|
|
合计 |
995 |
1125 |
需求分析
题目:论文查重
描述如下:
设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率。
- 原文示例:今天是星期天,天气晴,今天晚上我要去看电影。
- 抄袭版示例:今天是周天,天气晴朗,我晚上要去看电影。
要求输入输出采用文件输入输出,规范如下:
- 从命令行参数给出:论文原文的文件的绝对路径。
- 从命令行参数给出:抄袭版论文的文件的绝对路径。
- 从命令行参数给出:输出的答案文件的绝对路径。
我们提供一份样例,课堂上下发,上传到班级群,使用方法是:orig.txt是原文,其他orig_add.txt等均为抄袭版论文。
注意:答案文件中输出的答案为浮点型,精确到小数点后两位
实现思路
程序使用KMP算法在第一个文本中寻找第二个文本的子串,KMP算法通过构建部分匹配表(Partial Match Table)来避免不必要的回溯,提高字符串匹配的效率,然后程序使用动态规划算法计算两个文本之间的编辑距离。动态规划算法通过填充一个二维数组来记录状态值,其中dp[i][j]表示将第一个文本的前i个字符转换为第二个文本的前j个字符所需的最少操作次数。
具体计算步骤如下:
- 初始化数组的第一行和第一列,表示将一个空字符串转换为另一个字符串所需的操作次数。
- 从第二行和第二列开始,遍历数组的每个元素。
- 如果第一个文本的第i个字符等于第二个文本的第j个字符,则dp[i][j]等于dp[i-1][j-1],表示不需要进行任何操作。
- 如果第一个文本的第i个字符不等于第二个文本的第j个字符,则dp[i][j]等于左边、上边和左上角三个元素中的最小值加1,表示需要进行插入、删除或替换操作。
- 最后,dp[len1][len2]即为两个文本之间的编辑距离,其中len1和len2分别表示两个文本的长度。
模块实现
chesischeck类的重要函数:
- 传入命令行参数
ChesisCheck(const std::string& origTxtPath, const std::string& orig_addTxtPath, const std::string& ansTxtPath); - 计算编辑距离
float CalEditDIstance(const wstring& str1,const wstring& str2); - 计算运行时间
void CalRunTime();
性能分析

调用次数最多的是com.hankcs.hanlp包提供的接口, 即分词、取关键词与计算词频花费了最多的时间。整体程序逻辑较为简单,各个函数及方法耗时较短
main函数
int main(int argc,char*argv[]) { ChesisCheck chesischeck(argv[1],argv[2],argv[3]); chesischeck.Init(argc, argv); chesischeck.Start(); return 0; }
测试两个相同的字符之间求的编辑距离是否为0
TEST_METHOD(TestMethod4) { ChesisCheck chesischeck; string str1 = "abc"; string str2 = "abc"; wstring wstr1 = chesischeck.TransUTF8toUnicode(str1); wstring wstr2 = chesischeck.TransUTF8toUnicode(str2); float res = chesischeck.CalEditDIstance(wstr1, wstr2); Assert::AreEqual(res, (float)0, L"testwarning"); }
测试转化“。”时得到的字符串是否为空
TEST_METHOD(TestMethod3) { ChesisCheck chesischeck; string s1 = "。"; wstring w = chesischeck.TransUTF8toUnicode(s1); bool isEmpty = w.empty(); Assert::AreEqual(isEmpty, (bool)false, L"testwarning"); }
测试两个相同的字符之间求的运算时间是否趋近于0
TEST_METHOD(TestMethod5) { clock_t start, end; start = clock(); ChesisCheck chesischeck; string str1 = "abc"; string str2 = "abc"; float ans = 0; wstring wstr1 = chesischeck.TransUTF8toUnicode(str1); wstring wstr2 = chesischeck.TransUTF8toUnicode(str2); end = clock(); ans = 1.0 * (end - start) / CLOCKS_PER_SEC; Assert::AreEqual(ans, (float)0, L"testwarning"); }
单元测试展示


浙公网安备 33010602011771号