软工实践第二次作业

WordCount

Github项目地址:https://github.com/czx731039257

PSP表格

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

解题思路描述

首先拿到题目,我就先上网查了关于C++怎么实现文件的输入和输出,还有关于怎么进行接口封装的知识。再初步掌握了这些操作后,我就开始设计每个模块要猜用的结构和数据结构。首先是第一部分统计字符,我直接从get()函数每次从文本中读出一个字符。
第二部分的统计单词数,显然需要用到多个循环结构,由于这部分单词是有要求,所以这部分的是整个代码的关键之处,直接影响到后面功能,在这部分需要仔细的考虑好每个限制条件,反复的进行测试,方可开展下一个模块的工作。
最后的统计词频模块,我想的是利用哈希表来完成。再考虑好每个模块的需求后,我需要查找好自己需要的相关资料,然后再去动手打代码,这样会比较方便。

设计实现过程

这里由于需要用到哈希表,所以我先创建好链表指针。首先,我用ifstream创建文件流对象,然后用 文件流对象.open 的格式打开文件进行读取,读取时用get()函数每次读取一个字符到程序中。
在读完并统计好字符数后,我利用了多个循环结构来实现单词的判断和提取,并将每个单词散列到哈希表中为最后的统计词频做准备。
其次统计行数,我先按顺序遍历文本,当遇到有若可使干个字符(换行符和制表符)和一个换行符就把行数加一。
最后的统计词频,我利用了单词的前3个字母进行散列(字母1x26+字母2x26x26+字母3x26x26x26)这样把全部单词散列到结构体指针数组去。然后开始输出最多的10个单词,在这里我首相想到的是利用排序来解决。

改进思路

在打完代码后,由于考虑到不知道测试文本是否很大,如果很大的话,那么我用排序的方法必然会花费很多时间在这部分上,想遍历10遍的数组,每次找到频次最多的单词,输出单词和次数,然后在哈希表中删除这个单词,这样来减少遇到大数据量的运行时间。

代码说明

关键代码一

int Text::countword(ofstream *outfile)//统计单词数
{
	int flag = 0;
	string temp = "";
	int len = all.length();//计算文本的长度
	for (int i = 0; i < len; i++)
	{
		if ((all[i] >= 65 && all[i] <= 90) || (allg[i] >= 97 && all[i] <= 122))//找到第一个字母 
		{
			flag = 0;
			for (int j = i; j <= i + 3; j++)//判断是不是匹配单词 
			{
				if (all[j] <= 64 || (all[j] >= 91 && all[j] <= 96) || all[j] >= 123 || len - i < 4)
				{
					flag = 1;
					break;
				}
			}
			if (flag == 0)//如果是匹配单词就提取单词到temp
			{
				temp = "";
				for (; i < len && ((all[i] >= 65 && all[i] <= 90) || (all[i] >= 97 && all[i] <= 122) || (all[i] >= 48 && all[i] <= 57)); i++)
				{
					if (all[i] >= 65 && all[i] <= 90)//当遇到大写字母时变为小写
						all[i] += 32;
					temp += all[i];
				}
				count_word++;
				//cout << temp << endl;
				Text::insert(temp);//把每个单词插入哈希表中
			}
			else//如果不是匹配单词就跳到下一个单词的第一个字母
			{
				for (; (all[i] >= 65 && all[i] <= 90) || (all[i] >= 97 && all[i] <= 122||(all[i] >= 48 && all[i] <= 57)); i++) {}
			}
		}
		else if (all[i] >= 48 && all[i] <= 57)//如果单词是以数字开头的话就跳过这个单词
		{
			for (; (all[i] >= 65 && all[i] <= 90) || (all[i] >= 97 && all[i] <= 122) || (all[i] >= 48 && all[i] <= 57); i++) {}
		}
	}
	*outfile << "words:" << count_word << endl;//输出单词数
	return count_word;
}
    

关键代码二

    void Text::insert(string w)//把单词插入哈希表
{
	int hash = ((w[0] - 96)) + ((w[1] - 96) * 26) + ((w[2] - 96) * 26 * 26);//计算哈希值
	node *p = new node("", 1);
	node *q = new node("", 1);
	if (hash_table[hash]->next == NULL)//空表插入
	{
		p = hash_table[hash];
		hash_table[hash] = new node(w, 1);
		hash_table[hash]->next = p;
	}
	else//非空表
	{
		int flag = 0;
		q = p = hash_table[hash];
		while (p->next != NULL)//遍历链表
		{
			if (p->word == w)//在表中找到该单词,并且times加1
			{
				p->times++;
				flag = 1;
			}
			q = p;
			p = p->next;
		}
		if (flag == 0)//在链表中没有找到该单词,则在链表尾部插入新结点
		{
			node *newnode = new node(w, 1);
			q->next = newnode;
			newnode->next = p;
		}
	}
	return;
}

void Text::rank(ofstream *outfile)//统计词频
{
	int num;
	int flag = 0;//判断出现次数最大的结点是不是表首 0不是 1是
	node *max, *q, *p, *front_max;
	front_max = new node("", 0);
	for (int j = 0; j < 10 && j < count_word; j++)//遍历10次哈希表
	{
		max = new node("", 0);//初始化max
		for (int i = 0; i <= 18279; i++)
		{
			if (hash_table[i]->next == NULL) continue;//空表跳过
			else//遍历非空表
			{
				q = p = hash_table[i];
				while (p->next != NULL)
				{
					if (p->times > max->times || (p->times == max->times&&p->word < max->word))
					{

						if (p == hash_table[i])
						{
							flag = 1;//表示该单词在表头
							num = i;
						}
						else flag = 0;//表示该单词在表中
						max = p;
						front_max = q;
					}
					q = p;
					p = p->next;
				}
			}
		}
		if (max->times != 0)//如果max被替换过,则说明哈希表中有单词
		{
			cout << "<" << max->word << ">:" << max->times << endl;//输出一个结果
			*outfile << "<" << max->word << ">:" << max->times << endl;//输出一个结果
		}
		else //如果max没有被替换,则此时哈希表是空的,不需要输出
		break;

		if (flag == 1)	hash_table[num] = max->next;//如果频次最大的单词在表首,替换表首指针
		else front_max->next = max->next;//如果频次最大的单词在链表中,删除结点
	}
	return;
}

实践心得

从这次实践作业中学到了很多东西,比如说知道了怎么接口封装,怎么从文本中读入数据,其实很多的东西自己上网看别人的代码一看就懂,可是自己动手的时候就不会了,这说明看懂了不是真的懂,关键还是要自己动手敲敲代码,这样才能加深自己的记忆。

posted @ 2018-09-10 16:49  XINGYE丶  阅读(193)  评论(1)    收藏  举报