软工第二次作业 软工个人项目之词频统计 PSP 表格 需求分析 思路 测试文档 代码规范 实现 性能分析报告  单元测试 异常处理 总结和感想

 

GitHub仓库地址:https://github.com/waaaafool/081600410

PSP 表格

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

需求分析

  • 统计文件的字符数:
    • 只需要统计Ascii码,汉字不需考虑
    • 空格,水平制表符,换行符,均算字符
  • 统计文件的单词总数,单词:至少以4个英文字母开头,跟上字母数字符号,单词以分隔符分割,不区分大小写。
    • 英文字母: A-Z,a-z
    • 字母数字符号:A-Z, a-z,0-9
    • 分割符:空格,非字母数字符号
    • :file123是一个单词, 123file不是一个单词。file,File和FILE是同一个单词
  • 统计文件的有效行数:任何包含非空白字符的行,都需要统计。
  • 统计文件中各单词的出现次数,最终只输出频率最高的10个。频率相同的单词,优先输出字典序靠前的单词。
  • 按照字典序输出到文件result.txt:例如,windows95,windows98和windows2000同时出现时,则先输出windows2000

    • 输出的单词统一为小写格式
  • 输出的格式为

characters: number
words: number
lines: number
<word1>: number
<word2>: number

思路

拿到题目后,进行分析,发现统计行数,输出文件,以及字母数,都只需要从文件流中读出数据,就可以进行统计。而统计单词则需要进行单词的判定,同时统计最高频率的十个单词不仅需要判定单词,还需要对单词出现的次数进行hash处理。所以就想到了,从文档流中读出string类型,然后进行分割出单词,接着则是对单词放入hash_map中,最后用遍历hash_map,放入容量为十的优先队列。最后对这剩下的十个进行按字符串的比较大小排列,输出。

测试文档

input

a
a
a
a
file123

file123
file123
123file
123file
what should i do?i donot like you.
what should i do?i donot like you.
what should i do?i donot like you.

what should i do?i donot like you.

output

characters:190
words: 19
line:13
<donot>:4
<file123>:3
<like>:4
<should>:4
<what>:4

分析:123file不是单词,以及未满四个字符的单词均未被统计入内。空行也没被统计入行数。

代码规范

对于.h和.cpp文件,均使用每个单词的第一个字母大写来命名,而函数和重要变量使用驼峰法命名。

实现

首先确定文件的组织结构

软工第二次作业
软工个人项目之词频统计
PSP 表格
需求分析
思路
测试文档
代码规范
实现
性能分析报告 
单元测试
异常处理
总结和感想

其中Frequency是用来统计单词的数量,而WordCount是用来统计频率最高的十个单词。

主要算法

统计频率最高的十个单词

软工第二次作业
软工个人项目之词频统计
PSP 表格
需求分析
思路
测试文档
代码规范
实现
性能分析报告 
单元测试
异常处理
总结和感想

  •  

算法关键

  引入hash_map,来使查询的时间复杂度变成o(1),以及引入优先队列(堆模型),来使遍历hash_map后,储存以及更新频率最大的单词的时间变为o(lgn);

 

编码 过程

struct node {
	int num;
	string s;
};
node result[10];

bool cmp(node a, node b) {
	return a.s < b.s;
}


using namespace std;
int number = 0;

void  wordCount(const char* file){
	ifstream fin;
	ofstream fout;
	fout.open("..//result.txt", ios::out | ios::app);
	fin.open(file);
	if (!fout) {
		cout << "The File cannot open.1111" << endl;
	}
	if (!fin) {
		cout << "The File cannot open." << endl;
	}
	string s;
	hash_map<string, int> wordList;
	while (true) {
		fin >> s;
		string tem="";
		int len = s.length();
		int pre = -1;//记录本单词上一个字母的位置,初始为-1

		//进行文档流读出的string类型的单词切割
		for (int i = 0; i < len; i++) {
			if ('A' <= s[i]&&s[i] <= 'Z') s[i] += 32;
			if (s[i] > 'z' || (s[i]<'a'&&s[i]>'9') || s[i] < '0') {
				if (i - pre > 4&&(s[pre+1]<='z'&&s[pre + 1]>='a')) {
					for (int j = pre + 1; j < i; j++)
						tem += s[j];
					wordList[tem]++;
					tem = "";
				}
				pre = i;
			}
			else if (i == len - 1 && i - pre >=4 && (s[pre + 1] <= 'z'&&s[pre + 1] >= 'a')) {
				for (int j = pre + 1; j <= i; j++)
					tem += s[j];
				wordList[tem]++;
				tem = "";
			}
		}
		if (fin.eof()) {
			break;
		}

	}
	priority_queue<pair<int, string>, vector<pair<int, string>>,greater<pair<int, string>>> maxList;
	
	//遍历hash_map,加入优先队列
	for (hash_map<string, int>::const_iterator i = wordList.begin(); i != wordList.end(); i++) {
		maxList.push(make_pair(i->second, i->first));
		if (maxList.size() > 10) {
			maxList.pop();
		}
	}
	int i = 0;
	//取出队列里面的值,放入result结构数组中
	while (!maxList.empty()) {
		result[i].num = maxList.top().first;
		result[i].s = maxList.top().second;
		maxList.pop();
		i++;
	}

	//排序输出
	sort(result, result + i, cmp);
	for (int j = 0; j < i; j++) {
		cout << "<" << result[j].s << ">" << ":" << result[j].num << endl;
		fout << "<" << result[j].s << ">" << ":" << result[j].num << endl;
	}
	
	fin.close();
	fout.close();

}

  分析:代码使用循环来分割单词,使得性能比较慢,可以改用正则表达式来改进。

性能分析报告 

软工第二次作业
软工个人项目之词频统计
PSP 表格
需求分析
思路
测试文档
代码规范
实现
性能分析报告 
单元测试
异常处理
总结和感想

软工第二次作业
软工个人项目之词频统计
PSP 表格
需求分析
思路
测试文档
代码规范
实现
性能分析报告 
单元测试
异常处理
总结和感想

软工第二次作业
软工个人项目之词频统计
PSP 表格
需求分析
思路
测试文档
代码规范
实现
性能分析报告 
单元测试
异常处理
总结和感想

  分析:对main函数进行大量循环,发现除了那几个自己定义的函数之外,输入输出流占用的cpu比例很大,以前写一些算法题的时候也发现使用C++的输入输出流会超时。所以改用c的输入输出会好很多,因为c++的输入输出流封装了太多c的东西。

单元测试

设计:

1、传入一个空文件;                              

2、传入只有123file等的文件;

3、传入只有空格, , 等字符;

4、传入一个文件,其中包含空行的;

5、传入一个文件,里面有类似adc.fef类似的非空白符为终结符的;

6、传入一个文件,里面不超过十个有效单词的。

7、输入一个文件,里面单词有类似window2002,window1001fa类似的,看输出排列。

通过该变文件类型,证明成功,但由于VS未能找到对应的test,所以没有工程化测试,有点遗憾。

软工第二次作业
软工个人项目之词频统计
PSP 表格
需求分析
思路
测试文档
代码规范
实现
性能分析报告 
单元测试
异常处理
总结和感想

代码覆盖率

下载插件OpenCppCoverage

代码覆盖率的截图如下:

软工第二次作业
软工个人项目之词频统计
PSP 表格
需求分析
思路
测试文档
代码规范
实现
性能分析报告 
单元测试
异常处理
总结和感想

分析:总体而言覆盖率还是很不错的。

异常处理

1、在一开始进行main函数整合的时候,如果文件为空,发现会直接返回错误信息

于是加了一个判断

if (argv == NULL) {
			cout << "请输入文件名" << endl;
			return 0;
		}

  

总结和感想

经过这次软工实践,让我感受到了为什么说退课率这么高了。很多人不一定是因为坚持不下来,而是在衡量坚持下来和换个其他东西坚持,哪个性价比更高。因为软工确实太耗时间了,真的非常耗时间。

通过这次,最直观的就是感受到自己对各种工具的使用能力的匮乏,这次题目,编码不难,难的是在后面插件的下载与使用。

现在想着,如果最后坚持下来,那一定能学到很多东西的。

GitHub仓库地址:https://github.com/waaaafool/081600410

PSP 表格

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

需求分析

  • 统计文件的字符数:
    • 只需要统计Ascii码,汉字不需考虑
    • 空格,水平制表符,换行符,均算字符
  • 统计文件的单词总数,单词:至少以4个英文字母开头,跟上字母数字符号,单词以分隔符分割,不区分大小写。
    • 英文字母: A-Z,a-z
    • 字母数字符号:A-Z, a-z,0-9
    • 分割符:空格,非字母数字符号
    • :file123是一个单词, 123file不是一个单词。file,File和FILE是同一个单词
  • 统计文件的有效行数:任何包含非空白字符的行,都需要统计。
  • 统计文件中各单词的出现次数,最终只输出频率最高的10个。频率相同的单词,优先输出字典序靠前的单词。
  • 按照字典序输出到文件result.txt:例如,windows95,windows98和windows2000同时出现时,则先输出windows2000

    • 输出的单词统一为小写格式
  • 输出的格式为

characters: number
words: number
lines: number
<word1>: number
<word2>: number

思路

拿到题目后,进行分析,发现统计行数,输出文件,以及字母数,都只需要从文件流中读出数据,就可以进行统计。而统计单词则需要进行单词的判定,同时统计最高频率的十个单词不仅需要判定单词,还需要对单词出现的次数进行hash处理。所以就想到了,从文档流中读出string类型,然后进行分割出单词,接着则是对单词放入hash_map中,最后用遍历hash_map,放入容量为十的优先队列。最后对这剩下的十个进行按字符串的比较大小排列,输出。

测试文档

input

a
a
a
a
file123

file123
file123
123file
123file
what should i do?i donot like you.
what should i do?i donot like you.
what should i do?i donot like you.

what should i do?i donot like you.

output

characters:190
words: 19
line:13
<donot>:4
<file123>:3
<like>:4
<should>:4
<what>:4

分析:123file不是单词,以及未满四个字符的单词均未被统计入内。空行也没被统计入行数。

代码规范

对于.h和.cpp文件,均使用每个单词的第一个字母大写来命名,而函数和重要变量使用驼峰法命名。

实现

首先确定文件的组织结构

软工第二次作业
软工个人项目之词频统计
PSP 表格
需求分析
思路
测试文档
代码规范
实现
性能分析报告 
单元测试
异常处理
总结和感想

其中Frequency是用来统计单词的数量,而WordCount是用来统计频率最高的十个单词。

主要算法

统计频率最高的十个单词

软工第二次作业
软工个人项目之词频统计
PSP 表格
需求分析
思路
测试文档
代码规范
实现
性能分析报告 
单元测试
异常处理
总结和感想

  •  

算法关键

  引入hash_map,来使查询的时间复杂度变成o(1),以及引入优先队列(堆模型),来使遍历hash_map后,储存以及更新频率最大的单词的时间变为o(lgn);

 

编码 过程

struct node {
	int num;
	string s;
};
node result[10];

bool cmp(node a, node b) {
	return a.s < b.s;
}


using namespace std;
int number = 0;

void  wordCount(const char* file){
	ifstream fin;
	ofstream fout;
	fout.open("..//result.txt", ios::out | ios::app);
	fin.open(file);
	if (!fout) {
		cout << "The File cannot open.1111" << endl;
	}
	if (!fin) {
		cout << "The File cannot open." << endl;
	}
	string s;
	hash_map<string, int> wordList;
	while (true) {
		fin >> s;
		string tem="";
		int len = s.length();
		int pre = -1;//记录本单词上一个字母的位置,初始为-1

		//进行文档流读出的string类型的单词切割
		for (int i = 0; i < len; i++) {
			if ('A' <= s[i]&&s[i] <= 'Z') s[i] += 32;
			if (s[i] > 'z' || (s[i]<'a'&&s[i]>'9') || s[i] < '0') {
				if (i - pre > 4&&(s[pre+1]<='z'&&s[pre + 1]>='a')) {
					for (int j = pre + 1; j < i; j++)
						tem += s[j];
					wordList[tem]++;
					tem = "";
				}
				pre = i;
			}
			else if (i == len - 1 && i - pre >=4 && (s[pre + 1] <= 'z'&&s[pre + 1] >= 'a')) {
				for (int j = pre + 1; j <= i; j++)
					tem += s[j];
				wordList[tem]++;
				tem = "";
			}
		}
		if (fin.eof()) {
			break;
		}

	}
	priority_queue<pair<int, string>, vector<pair<int, string>>,greater<pair<int, string>>> maxList;
	
	//遍历hash_map,加入优先队列
	for (hash_map<string, int>::const_iterator i = wordList.begin(); i != wordList.end(); i++) {
		maxList.push(make_pair(i->second, i->first));
		if (maxList.size() > 10) {
			maxList.pop();
		}
	}
	int i = 0;
	//取出队列里面的值,放入result结构数组中
	while (!maxList.empty()) {
		result[i].num = maxList.top().first;
		result[i].s = maxList.top().second;
		maxList.pop();
		i++;
	}

	//排序输出
	sort(result, result + i, cmp);
	for (int j = 0; j < i; j++) {
		cout << "<" << result[j].s << ">" << ":" << result[j].num << endl;
		fout << "<" << result[j].s << ">" << ":" << result[j].num << endl;
	}
	
	fin.close();
	fout.close();

}

  分析:代码使用循环来分割单词,使得性能比较慢,可以改用正则表达式来改进。

性能分析报告 

软工第二次作业
软工个人项目之词频统计
PSP 表格
需求分析
思路
测试文档
代码规范
实现
性能分析报告 
单元测试
异常处理
总结和感想

软工第二次作业
软工个人项目之词频统计
PSP 表格
需求分析
思路
测试文档
代码规范
实现
性能分析报告 
单元测试
异常处理
总结和感想

软工第二次作业
软工个人项目之词频统计
PSP 表格
需求分析
思路
测试文档
代码规范
实现
性能分析报告 
单元测试
异常处理
总结和感想

  分析:对main函数进行大量循环,发现除了那几个自己定义的函数之外,输入输出流占用的cpu比例很大,以前写一些算法题的时候也发现使用C++的输入输出流会超时。所以改用c的输入输出会好很多,因为c++的输入输出流封装了太多c的东西。

单元测试

设计:

1、传入一个空文件;                              

2、传入只有123file等的文件;

3、传入只有空格, , 等字符;

4、传入一个文件,其中包含空行的;

5、传入一个文件,里面有类似adc.fef类似的非空白符为终结符的;

6、传入一个文件,里面不超过十个有效单词的。

7、输入一个文件,里面单词有类似window2002,window1001fa类似的,看输出排列。

通过该变文件类型,证明成功,但由于VS未能找到对应的test,所以没有工程化测试,有点遗憾。

软工第二次作业
软工个人项目之词频统计
PSP 表格
需求分析
思路
测试文档
代码规范
实现
性能分析报告 
单元测试
异常处理
总结和感想

代码覆盖率

下载插件OpenCppCoverage

代码覆盖率的截图如下:

软工第二次作业
软工个人项目之词频统计
PSP 表格
需求分析
思路
测试文档
代码规范
实现
性能分析报告 
单元测试
异常处理
总结和感想

分析:总体而言覆盖率还是很不错的。

异常处理

1、在一开始进行main函数整合的时候,如果文件为空,发现会直接返回错误信息

于是加了一个判断

if (argv == NULL) {
			cout << "请输入文件名" << endl;
			return 0;
		}

  

总结和感想

经过这次软工实践,让我感受到了为什么说退课率这么高了。很多人不一定是因为坚持不下来,而是在衡量坚持下来和换个其他东西坚持,哪个性价比更高。因为软工确实太耗时间了,真的非常耗时间。

通过这次,最直观的就是感受到自己对各种工具的使用能力的匮乏,这次题目,编码不难,难的是在后面插件的下载与使用。

现在想着,如果最后坚持下来,那一定能学到很多东西的。