第一次个人编程作业
| 这个作业属于哪个课程 | 软件工程-计科21级12班-计算机学院-广东工业大学 |
|---|---|
| 这个作业要求在哪里 | 个人项目 |
| 这个作业的目标 | 了解个人项目测试流程;了解使用PSP表格;了解单元测试;学习使用github仓库代码管理 |
一、github链接
二、PSP表格
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 20 | 20 |
| Estimate | 估计这个任务需要多少时间 | 600 | 300 |
| Development | 开发 | 120 | 100 |
| Analysis | 需求分析 (包括学习新技术) | 80 | 100 |
| Design Spec | 生成设计文档 | 30 | 40 |
| Design Review | 设计复审 | 60 | 40 |
| Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 30 | 20 |
| Design | 具体设计 | 60 | 50 |
| Coding | 具体编码 | 120 | 300 |
| Code Review | 代码复审 | 60 | 100 |
| Test | 测试(自我测试,修改代码,提交修改) | 60 | 80 |
| Reporting | 报告 | 120 | 80 |
| Test Report | 测试报告 | 100 | 80 |
| Size Measurement | 计算工作量 | 15 | 20 |
| Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 20 | 25 |
| 合计 | 1495 | 1355 |
三、项目环境
- IDE:Visual Studio Community 2017
- 编程语言:C++
- 运行环境:64-bit Windows 10
四、计算模块接口的设计
- 函数
- readsp函数:接收一个ifstream类对象,读取文本文件并过滤标点符号,返回一个string类型。
- stringcut函数:接收一个string类型,把字符串按每4个字符分词,返回一个map映射类型。
- cossimilarity函数:接收两个vector类型,这两个vector类型存放两个文本的词频向量,由此可以计算出它们的余弦相似度,返回一个float类型。
- testsp函数:接收命令行参数,对文本文件的打开,计算词频向量,输出答案到文本文件和关闭文件的操作都在这里完成。
- main函数:调用testsp函数。
五、性能改进
在最初的版本中,我使用了编辑距离算法来计算文本相似度,关于编辑距离算法:https://www.cnblogs.com/BlackStorm/p/5400809.html
设源文本的数据规模为M,识别文本的数据规模为N,那么编辑距离算法的时间复杂度为O(MN),空间复杂度为O(MN)。
经过一次优化后,可以把编辑距离算法中使用的dp矩阵变化为滚动的,这样空间复杂度可变为O(N)。但是,对于长文本来说,编辑距离算法需要耗时过长,解决论文查重不现实。
因此,我把编辑距离算法改为余弦相似度算法,其中对文本的分词使用n-grams算法。

可以看到,耗时最长的函数是readsp函数与stringcut函数,readsp函数需要不断地输入,时间复杂度为O(n);stringcut函数对字符串进行分词,其时间复杂度为O(n**2)。
六、运行结果
样例文本


结果:

七、异常处理
-
1.对编码方式不同的文本文件的处理
对两个样本进行分析,得到的文本相似度为0,其原因在于两个文本的编码方式不同,导致存储方式也不同,存储有可能为乱码。
![]()
解决方法:在进行测试之前,把两个测试样本的编码方式统一为ANSI编码。 -
2.传入空文件
两个样本为空,这会导致程序崩溃:
![]()
解决方法:只需要对字符串检验一下是否为空即可。
![]()
八、单元测试
单元测试部分代码:
#include "pch.h"
#include "CppUnitTest.h"
#include <cassert>
#include "test_se_homework_1_2.h"
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <iomanip>
#include <map>
#include <set>
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace UnitTest2
{
TEST_CLASS(UnitTest2)
{
public:
/*TEST_METHOD(TestMethod1)
{
}*/
//原样本,相似度准确值为0.8
TEST_METHOD(TestSample1)
{
char argv[4][100] =
{
"D:\\zhuo_mian\\学习\\软件工程\\homework_1_2\\se_homework_1_2\\Debug\\se_homework_1_2.exe",
"D:\\zhuo_mian\\学习\\软件工程\\test_txt\\orig.txt",
"D:\\zhuo_mian\\学习\\软件工程\\test_txt\\orig_0.8_add.txt",
"D:\\zhuo_mian\\学习\\软件工程\\test_txt\\ans.txt"
};
int argc = 4;
auto ans = Test_Sample(argc, argv);
assert(0.7 < ans < 0.9);
}
//完全一致样本,相似度准确值为1
TEST_METHOD(TestSample2)
{
char argv[4][100] =
{
"D:\\zhuo_mian\\学习\\软件工程\\homework_1_2\\se_homework_1_2\\Debug\\se_homework_1_2.exe",
"D:\\zhuo_mian\\学习\\软件工程\\test_txt\\s1.txt",
"D:\\zhuo_mian\\学习\\软件工程\\test_txt\\s1_add.txt",
"D:\\zhuo_mian\\学习\\软件工程\\test_txt\\ans.txt"
};
int argc = 4;
auto ans = Test_Sample(argc, argv);
assert(ans == 1);
}
//两个空文本文件,相似度为0
TEST_METHOD(TestSample3)
{
char argv[4][100] =
{
"D:\\zhuo_mian\\学习\\软件工程\\homework_1_2\\se_homework_1_2\\Debug\\se_homework_1_2.exe",
"D:\\zhuo_mian\\学习\\软件工程\\test_txt\\s2.txt",
"D:\\zhuo_mian\\学习\\软件工程\\test_txt\\s2_add.txt",
"D:\\zhuo_mian\\学习\\软件工程\\test_txt\\ans.txt"
};
int argc = 4;
auto ans = Test_Sample(argc, argv);
assert(ans == 0);
}
//两个不存在的文本文件,默认返回0
TEST_METHOD(TestSample4)
{
char argv[4][100] =
{
"D:\\zhuo_mian\\学习\\软件工程\\homework_1_2\\se_homework_1_2\\Debug\\se_homework_1_2.exe",
"D:\\zhuo_mian\\学习\\软件工程\\test_txt\\s3.txt",
"D:\\zhuo_mian\\学习\\软件工程\\test_txt\\s3_add.txt",
"D:\\zhuo_mian\\学习\\软件工程\\test_txt\\ans.txt"
};
int argc = 4;
auto ans = Test_Sample(argc, argv);
assert(ans == 0);
}
};
}
部分单元测试结果:





浙公网安备 33010602011771号