软工第二次作业

Github地址

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

解题思路

统计行数和计算字符数量很简单,用C++的getline每次读取文件的一行存入字符串中,计算size,行数可以直接计算出来,字符数量则需要统计的字符数量加上行数;词频统计相对麻烦一点,先用输入流读取一个字符串,再去判断是否符合单词的要求。

查找资料

将代码按功能划分,主要分成三个函数,一个函数计算行数以及字符数,一个函数统计词频,一个函数对词频进行排序

主要函数的流程图

image

countLine函数主要计算行数以及字符数量;countWord函数利用文件输入流将单词与分割符分离,将单词和数量益键值对的形式存入undered_map中;WordSort主要将单词的键值对进行排序输入到文件当中。

单元测试弄了好久,无论是未封装的版本,还是已经封装了的版本去编写单元测试,总是出现无法解析的外部符号这个错误,在网上找了好多解决方法,比如将两个obj文件加入外部依赖项等等都没有解决,只好先放着,后面再去查找资料。单元测试没有做成,只好手动测试了,从网上copy了10篇的英文作文,在词云统计上进行统计与我的程序的统计进行对比,两者的对比结果相差无几。

在改进程序性能上至少花了四个小时,刚开始使用的map来记录键值对,但是map的性能不好,测试一篇大约70万词的圣经要用26秒的时间,在性能图上看,在map的查找与插入上花费了一半以上的时间。image
后来使用set,用set来记录某个单词是否出现过,若出现过,则在map中加一,若没有则创建一个新的键值对,但是并没有提高多少效率
image
后来跟乐忠豪同学交流了一下,改用了undered_map来进行键值对的记录,效率直接提高了一半!
image

image
image
直接从之前的26秒到后面的13秒,简直是质的提升。
后面占用最多的是文件的读取占用了一半的时间,去网上查资料也不知道如何改进文件的读取速度,希望有会的大佬指点一下。

首先是记录单词的函数

void countWord(unordered_map<string, int>& words, string filename, ifstream& infile)//统计词频,传入的参数是unordered_map的引用以及文件流的引用
{
	unordered_map<string, int>::iterator iter;
	infile.open(filename);
	string word;
	while (infile >> word)//利用文件输入流将字符串与分隔符分离,将字符串输入到word里面,再来判断是否属于单词与统计
	{
		if (word.size() < 4)
			continue;
		if ((word[0] >= 'a'&&word[0] <= 'z' || word[0] >= 'A'&&word[0] <= 'Z') && \
			(word[1] >= 'a'&&word[1] <= 'z' || word[1] >= 'A'&&word[1] <= 'Z') && \
			(word[2] >= 'a'&&word[2] <= 'z' || word[2] >= 'A'&&word[0] <= 'Z') && \
			(word[3] >= 'a'&&word[3] <= 'z' || word[3] >= 'A'&&word[3] <= 'Z'))
		{
			wordNum++;
			for (unsigned int i = 0; i < word.size(); i++)
				if (word[i] >= 'A'&&word[i] <= 'Z')
					word[i] += 32;
			words[word]++;
		}
	}
}

然后就是对键值对的排序,这里使用sort来进行排序,因为map是不能用于排序的,所以将键值对拷贝到vector中再进行排序

这里说一下noexcept,这是在进行代码分析的时候发现的

在C++11中,声明一个函数不可以抛出任何异常使用关键字noexcept.

cmp函数的作用只是来对排序进行规划,而不是实际的调用,所以不会返回任何的异常处理。简而言之,如果你知道你的函数绝对不会抛出任何异常,应该使用noexcept, 而不是throw().

int cmp(const pair<string, int>& a, const pair<string, int>& b) noexcept
{
	return a.second > b.second;
}
void wordSort(unordered_map<string, int>& words, ofstream& outfile)
{
	unordered_map<string, int>::iterator iter;
	vector<pair<string, int>> tmp;
	for (iter = words.begin(); iter != words.end(); iter++)
		tmp.push_back(pair<string, int>(iter->first, iter->second));
	sort(tmp.begin(), tmp.end(), cmp);
	for (unsigned int i = 0; i < (tmp.size() < 10 ? tmp.size() : 10); i++)
		outfile << "<" << tmp[i].first << ">:" << " " << tmp[i].second << endl;
}

最后是行数和字符数的统计,这个就简单多了,使用getline来获取文件中的每一行,将每一行输入到字符串中,每一行都有一个换行符也算字符,所以总的字符数量应该是characters+lines。

void countLine(ifstream& infile)//统计行数以及字符数
{
	string s;
	while (getline(infile, s))
	{
		if (s.size() == 0)
		{
			characters++;
			continue;
		}
		characters += s.size();
		lines++;
	}
}

前面的是未封装的函数,后来将函数给封装成dll文件。
新建一个动态链接库(DLL)项目,将所要封装的函数的具体表示形式放进Dll.cpp当中
image
然后在Dll.h文件当中输入如下

#pragma once
__declspec(dllexport) pair<int, unordered_map<string, int>> countWord(string filename);
__declspec(dllexport) int number_of_word(string filename);
__declspec(dllexport) int cmp(const pair<string, int>& a, const pair<string, int>& b);
__declspec(dllexport) void wordSort(unordered_map<string, int>& words);
__declspec(dllexport) void top_10_words(string filename);
__declspec(dllexport) pair<int, int> countLine(string filename);
__declspec(dllexport) int line(string filename);
__declspec(dllexport) int character(string filename);

点击生成解决方案,就会在原文件夹当中生成dll,lib,.h文件,将他们拷贝到词频统计的项目当中,在资源文件和头文件当中添加现有项.ib和.h文件就能使用封装的函数啦。

总结:

这次的作业真的学到了非常多,代码分析,性能分析器,预编译文件stdafx的使用等等之前没有使用过的,dll的封装以及旧知识的复习,感觉自己还是有很多的不足。还有交流很重要,遇到不懂的要多去问问,集思广益,比自己埋头苦干要有效的多。

posted on 2018-09-10 22:17  蔡子阳  阅读(291)  评论(6编辑  收藏  举报