基于哈希表的词频统计Word文档格式.docx
《基于哈希表的词频统计Word文档格式.docx》由会员分享,可在线阅读,更多相关《基于哈希表的词频统计Word文档格式.docx(11页珍藏版)》请在冰豆网上搜索。
![基于哈希表的词频统计Word文档格式.docx](https://file1.bdocx.com/fileroot1/2022-11/16/c14c834f-3c7e-4147-b9f5-404e3c062a6f/c14c834f-3c7e-4147-b9f5-404e3c062a6f1.gif)
效果图如图20-4所示。
图20-4运行结果文件内容
3.功能说明
(1)本案例需要一个文本和一个词表,统计出每个词在文本中出现的次数。
统计的原则包括以下两种:
交集型:
如“内存在涨价”,需要统计“内存”和“存在”(假设这两个词都在词表中)。
组合型:
如“中美关系在发展”,需要统计“中美”、“关系”和“中美关系”(假设这三个词都在词表中)。
(2)文本和词表的格式是:
输入文本是一个长句,句中只包含汉字,不包含数字、标点、空格、回车以及其它任何特殊符号。
文本规模小于等于50,000汉字。
输入词表的规模小于等于100,000个词,所有词不重复,词在2~7个汉字之间,每个词占一行。
(3)实现基于词表的词频统计,从磁盘中读取词表和文本,将词频统计结果输出到磁盘中,输出结果要求按字典序排序,并计算出程序运行时间。
二、案例分析
首先分析选取哪种数据结构,以达到高速搜索的目的。
具备搜索功能的数据结构很多,如线性表、平衡树、哈希表等,当数据量庞大时,使用哈希表最合适。
哈希表的概念在案例“哈希表的演示”已经做了介绍。
根据需要构造一个哈希表类,在类中实现如下操作:
建立哈希表将词表在内存中存储起来,这个存储的过程就是类的构造函数。
案例中的词表是数量较大的词组,词与词之间用空格隔开。
因此可用文件流函数getline来实现。
每次调用getline函数便得到一个存有词的字符串,然后将字符串按照某种散列函数插入到哈希表中,一直到词表全部存储为止。
统计词频:
从词表中读取文本文件,存储在一个字符串里,因为每个汉字存储在两个字节里,所以词在4~14个字节之间,用charword[15]即可表示一个词。
考虑到词频统计的交集性和组合性原则,可对在文本字符串中的每个汉字与其后的汉字分别组成2~7个汉字的词,在词表中进行搜索,每被搜到一次,次数加1。
循环直到文本末尾。
哈希函数(散列函数)的实现:
用charword[15]存储的词得到一个关键字,然后除以某个素数,得到的余数为散列地址。
由于数据较多,要高速完成搜索,散列到每个相同地址的元素要尽量少,因此素数要很大,关键字的范围也很大且不重叠。
按字符的字典序排序输出:
而哈希表是乱序存储的,故可先遍历哈希表,将所有词频大于0的词存入数组中,用快速排序法将这个数组中的元素排序。
三、案例设计
1.类的设计
根据案例分析,需要设计出两个结构体NODE和TABLE,同时还需设计一个类SYMBOLTABLE。
其中:
结构体NODE是哈希桶(哈希桶--哈希表中各个同地址值的元素构成的链表)中节点的数据结构,
TABLE是哈希表的结构,SYMBOLTABLE类提供了诸如:
哈希函数、查找词汇、遍历哈希表、将词汇插入哈希表中、快速排序等功能。
(1)
结构体
NODE
structNODE
{
charword[15];
//关键字
intnumber;
//关键字被访问的次数
PNODEnext;
//指向下一结点的指针
};
(2)
TABLE
structTABLE
intprime;
//哈希桶数
PNODE*buckets;
//指向结点指针的指针,可构成动态的指针数组
(3)
SYMBOLTABLE类
图20-5
SYMBOLTABLE类图
数据成员
PSYMBOLTABLE
p;
哈希符号表指针。
intnum;
被遍历的词数。
函数成员
SYMBOLTABLE(char*argv);
构造函数、创建哈希表。
~SYMBOLTABLE()
析构函数。
intHash(char*word);
静态哈希函数,形参:
字符串,桶数。
返回桶的下标。
voidFindNode(char*s);
形参:
结点指针,字符串。
在某一链中找到某词汇,若找到则词频数加1,且返回。
voidInsertIntoSymTbl(charname[20]);
将词汇插入哈希表中。
voidSearchInSymTbl(char*argv);
搜索某一词汇
。
voidTraverseSymTbl(char*argv);
遍历哈希表。
voidQsort(PNODE*p,ints,intt);
使用快速排序法。
2.主程序设计
在主函数中声明了一个SYMBOLTABLE类的对象,依次调用哈希表类的构造函数、统计函数、输出函数即可。
另外,为了记录程序的运行时间,包含了time头文件,调用clock函数,能精确到毫秒。
主程序有详细的注释,清晰易懂,流程图略。
四、案例实现
//*****************************************************************
//*source.h
类声明头文件
#1
#ifndef_____SUPERMARKET_____
//防止头文件被多次包含
#2
#include<
string>
#3
fstream>
#4
typedefstructTABLE*PSYMBOLTABLE;
//符号表构造函数,哈希符号表指针
#5
typedefstructNODE*PNODE;
//结点指针
#6
#7
#8
charword[15];
//关键字
#9
intnumber;
//此词被访问的次数
#10
PNODEnext;
//指向下一结点的指针
#11
#12
#13
#14
intprime;
//哈希桶数
#15
PNODE*buckets;
//指向结点指针的指针,可构成动态的指针数组
#16
#17
classSYMBOLTABLE
#18
#19
public:
#20
//创建哈希表
#21
~SYMBOLTABLE(){}
#22
//静态哈希函数,形参:
字符串,桶数
//返回桶的下标
#23
//形参:
结点指针,字符串
//功能:
在某一链中找到某词汇,若找到则词频数加1,且返回;
#24
//将词表插入哈希表中
#25
//搜索某一词汇
#26
//遍历哈希表
#27
//使用快速排序法
#28
private:
#29
PSYMBOLTABLEp;
//哈希符号表指针
#30
//被遍历的词数
#31
#32
SYMBOLTABLE:
:
SYMBOLTABLE(char*argv)
#33
#34
ifstreamin(argv);
#35
inti,n;
#36
chars[15];
#37
p=newstructTABLE;
//建立哈希表
#38
p->
prime=100000;
//桶数
#39
num=0;
#40
buckets=newPNODE[p->
prime];
//建立每个散列链
#41
#42
for(i=0;
i<
p->
prime;
i++)
//动态分布内存
#43
buckets[i]=NULL;
#44
100000;
i++)
#45
{
#46
if(in.good())
#47
#48
in.getline(s,16,'
\n'
);
//读入每个词
#49
s[strlen(s)]='
\0'
;
#50
if(!
strcmp(s,"
\0"
))
#51
break;
#52
n=Hash(s);
#53
InsertIntoSymTbl(s);
//将词表插入到哈希表中
#54
}
#55
else
#56
break;
#57
#58