用Hash Table(哈希散列表)实现统计文本每个单词重复次数(频率)
哈希表在查找方面有非常大应用价值,本文记录一下利用哈希散列表来统计文本文件中每个单词出现的重复次数,这个需求当然用NLP技术也很容易实现。
一、基本介绍
1、Hash Key值:将每个单词按照字母组成通过一个乘子循环运算得出一个小于29989的整数,29989是一个比较大的质数。0~29989即为Key值。
2、哈希函数:
//哈希函数
unsigned int hashIndex(const char* pWord) //返回hash表的索引(即hash指针数组的下标)
{
assert(pWord != NULL);
unsigned int index = ; //以下四行为将一个单词映射到一个小于HASHNUMBER的正整数的函数
for (; *pWord != '\0'; pWord++)
index = MULT * index + *pWord;
return index % HASHNUMBER;
}
3、数据结构定义:
(1)总体采用数组法,数组下标就是Key值,Key取值范围是1~29989,也即数组大小为29989,数组的每个项存储该Key值下含有的单词链表的头指针,根据头指针就能遍历整个单词链表
hashNodePtr bin[HASHNUMBER] = { NULL }; //HASHNUMBER大小的指针数组 作为hash表
(2)单词节点定义: 链表存储同一Key值下的单词,单词节点主要包含单词内容、单词的重复次数、指向下一个单词的指针;
typedef struct hashnode
{
//链表中每个节点的结构
hashnode()
{
word = NULL;
count = 0;
next = NULL;
}
char* word; //单词
int count; //出现频率
struct hashnode *next; //指向链表中具有相同hash值的下个节点
}hashNode,*hashNodePtr;
4、哈希表解决冲突的途径:链地址法。 即上面定义的存储结构为链表。
二、源代码
// case1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
// #include "pch.h"
#include <iostream>
#include <assert.h>
#define HASHNUMBER 29989 //散列表的大小,29989为质数
#define MULT 31 //hash函数的一个乘子
//单词节点的定义
typedef struct hashnode
{
//链表中每个节点的结构
hashnode()
{
word = NULL;
count = 0;
next = NULL;
}
char* word; //单词
int count; //出现频率
struct hashnode *next; //指向链表中具有相同hash值的下个节点
}hashNode,*hashNodePtr; hashNodePtr bin[HASHNUMBER] = { NULL }; //HASHNUMBER大小的指针数组 作为hash表 //这里将每个单词映射为一个小于HASHNUMBER的正整数 //哈希函数
unsigned int hashIndex(const char* pWord) //返回hash表的索引(即hash指针数组的下标)
{
assert(pWord != NULL);
unsigned int index = 0; //以下四行为将一个单词映射到一个小于HASHNUMBER的正整数的函数
for (; *pWord != '\0'; pWord++)
index = MULT * index + *pWord;
return index % HASHNUMBER;
} //想hash表中插入单词
void insertWord(const char* pWord) //在hash表中插入单词,如果已经存在了,则增加单词的出现次数count
{
assert(pWord != NULL);
hashNodePtr p;
unsigned int index = hashIndex(pWord); //用hash函数得到单词的hash值,也就是hash数组的下标
for ( p = bin[index]; p !=NULL; p++)
{
//查找单词是否已经在hash表中了
if (strcmp(pWord,p->word)==0)
{
//找到的话,直接将单词的次数增加1即可
(p->count)++;
return;
}
}
//如果上面没返回,也就是说hash表中没有这个单词,添加新节点,加入这个单词
p = (hashNodePtr)malloc(sizeof(hashNode));
p->count = 1; //新节点的出现次数设置为1
p->word = (char *)malloc(strlen(pWord) + 1);
strcpy(p->word, pWord);
p->next = bin[index]; //将新生成的节点插入到index为下标的链表中去
bin[index] = p;
} //读取Data.txt中的单词,并将每个单词插入到前面设计好的hash表中
void readWordToHashTable(const char *path)
{
//从文本文件中读取单词,插入到hash表中
FILE *fp;
char buf[1024]; //存储一行字符串
char *p;
fp = fopen(path, "r");
if (fp==NULL)
{
printf("open file error!exit\n");
exit(-1);
} while (NULL!=fgets(buf,sizeof(buf),fp)) //数据读完,到文本末尾了
{
buf[strlen(buf) - 1] = '\0'; //出去单词最后的换行符
//print("%s/n",buf);
if (strcmp("",buf)==0) //如果是空行,则继续
{
continue;
} p = strtok(buf, "'\t','\n',' '"); //用strtok函数从一行字符串中分离出每个单词,分隔符设置为(空格、逗号、换行、制表符)
while (p!=NULL)
{
insertWord(p); //调用insertWord(),向hash表中插入分隔出来的单词
p = strtok(NULL, "'\t','\n'");
}
}
fclose(fp);
} void writeHashTable(const char *path)
{//将结果写到path中。
FILE *fp;
hashNodePtr p;
int i;
fp = fopen(path, "w");
if (fp == NULL)
{
printf("write file error!exit");
exit(-1);
}
for (i = 0; i < HASHNUMBER; i++)
{
for (p = bin[i]; p != NULL; p = p->next)
{
fprintf(fp, "index %d:<%s,%d>", i, p->word, p->count);
if (p->next == NULL)
fprintf(fp, "\n");
}
}
fclose(fp);
} //释放hash表中占用的内存
void freeHashTable()
{
int i;
hashNodePtr p, q;
p = q = NULL;
for (i = 0; i < HASHNUMBER; i++)
{
p = bin[i];
while (p!=NULL)
{
q = p;
p = p->next;
free(q->word);
free(q);
}
}
} int main()
{
readWordToHashTable("data.txt");
writeHashTable("result.txt");
return 0;
}
三、测试
由于这里无法上传测试文件,请自己构造一个单词文件,单词与单词之间的间隔只能是换行或者制表符,因为目前代码中定义的区分单词的间隔只有制表符和换行符,所以构造文件的时候,直接复制一篇英语作文进去,将其中的标点符号全部删除,空格一律改成制表符,然后将该文本文件命名成data.txt,放入项目目录下,运行程序,即可读取该文件,并将统计结果的文件存储在项目目录下。
最后,附上笔者的实现项目源码(包含data.txt测试文件):https://pan.baidu.com/s/17OVIuhf5tbaJ3TwsWzw-HA
参考链接:https://blog.csdn.net/shangshanhu/article/details/5917230
用Hash Table(哈希散列表)实现统计文本每个单词重复次数(频率)的更多相关文章
- Hash表(hash table ,又名散列表)
直接进去主题好了. 什么是哈希表? 哈希表(Hash table,也叫散列表),是根据key而直接进行访问的数据结构.也就是说,它通过把key映射到表中一个位置来访问记录,以加快查找的速度.这个映射函 ...
- Hash表 hash table 又名散列表
直接进去主题好了. 什么是哈希表? 哈希表(Hash table,也叫散列表),是根据key而直接进行访问的数据结构.也就是说,它通过把key映射到表中一个位置来访问记录,以加快查找的速度.这个映射函 ...
- 哈希表(散列表)—Hash表解决地址冲突 C语言实现
哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.具体的介绍网上有很详 ...
- 散列表(Hash table)及其构造
散列表(Hash table) 散列表,是根据关键码值(Key value)而直接进行访问的数据结构.它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函数叫做散列函数,存放记录 ...
- 哈希表(Hash Table)原理及其实现
原理 介绍 哈希表(Hash table,也叫散列表), 是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映 ...
- java资料——哈希表(散列表)(转)
哈希表 散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度. ...
- 数据结构 -- 哈希表(hash table)
简介 哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函 ...
- 【阅读笔记:散列表】Javascript任何对象都是一个散列表(hash表)!
什么是散列表? 散列表是Dictionary(字典)的一种散列表实现方式,字典传送门 一个很常见的应用是使用散列表来表示对象.Javascript语言内部就是使用散列表来表示每个对象.此时,对象的每个 ...
- linux内核的双链表list_head、散列表hlist_head
一.双链表list_head 1.基本概念 linux内核提供的标准链表可用于将任何类型的数据结构彼此链接起来. 不是数据内嵌到链表中,而是把链表内嵌到数据对象中. 即:加入链表的数据结构必须包含一个 ...
随机推荐
- Linux 定制X86平台操作系统
/********************************************************************************* * Linux 定制X86平台操作 ...
- supervisor 使用tips
Supervisor (http://supervisord.org) 是一个用 Python 写的进程管理工具,可以很方便的用来启动.重启.关闭进程,supervisor可以同时监控多个进程,并可以 ...
- HDU 3973 AC's String 字符串哈希
HDU 3973 通过哈希函数将一个字符串转化为一个整数,通过特定的方式可以使得这个哈希值几乎没有冲突(这就是关键之处,几乎没有视为没有= =!, 其实也可以考虑实现哈希冲突时的处理,只是这道题没必要 ...
- eclipse工程 'cocostudio/CocoStudio.h' file not found
android.mk里有这样配置: LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) $(call import-add-path,$(LOCAL_ ...
- .NET泛型解析(下)
上一篇对.NET中的泛型进行了详细的介绍以及使用泛型的好处是什么,这篇将更加深入的去了解泛型的其他的知识点,重头戏. [1]泛型方法 上一篇我们也说过了,泛型可以是类,结构,接口,在这些泛型类型中定义 ...
- visualvm 和jdk 对应版本下载地址列表
http://visualvm.java.net/releases.html VisualVM Corresponding Java VisualVM VisualVM 1.3.7Released: ...
- ASP.NET 获得当前网页名字
Code string currentFilePath = HttpContext.Current.Request.FilePath; string CurrentPageName = current ...
- 黄聪:WordPress 多站点建站教程(三):主站如何调用子站的文章内容、SQL语句如何写?
1.如果懂得编程的朋友可以SQL语句,然后加上PHP函数等操作就可以通过直接调用网站的数据库信息来实现想要达到的目的. 既然要用到SQL语句首先得对WordPress多站点数据库有一个了解,多站点激活 ...
- 汇编_指令_JMP
JMP指令 JMP是汇编语言中的无条件跳转指令.无条件跳转指令可转到内存中任何程序段.转移地址可在指令中给出,也可以在寄存器中给出,或在储存器中指出. 中文名:无条件跳转指令 外文名:JMP 和调用指 ...
- SpringAOP的两种实现方式
1.SpringAOP,面向切面编程.在实际应用汇总很常见,一般用于日志.异常保存.也可以针对于相应的业务做处理 AOP核心概念 1.横切关注点 对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横 ...