哈希表在查找方面有非常大应用价值,本文记录一下利用哈希散列表来统计文本文件中每个单词出现的重复次数,这个需求当然用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(哈希散列表)实现统计文本每个单词重复次数(频率)的更多相关文章

  1. Hash表(hash table ,又名散列表)

    直接进去主题好了. 什么是哈希表? 哈希表(Hash table,也叫散列表),是根据key而直接进行访问的数据结构.也就是说,它通过把key映射到表中一个位置来访问记录,以加快查找的速度.这个映射函 ...

  2. Hash表 hash table 又名散列表

    直接进去主题好了. 什么是哈希表? 哈希表(Hash table,也叫散列表),是根据key而直接进行访问的数据结构.也就是说,它通过把key映射到表中一个位置来访问记录,以加快查找的速度.这个映射函 ...

  3. 哈希表(散列表)—Hash表解决地址冲突 C语言实现

    哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.具体的介绍网上有很详 ...

  4. 散列表(Hash table)及其构造

    散列表(Hash table) 散列表,是根据关键码值(Key value)而直接进行访问的数据结构.它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函数叫做散列函数,存放记录 ...

  5. 哈希表(Hash Table)原理及其实现

    原理 介绍 哈希表(Hash table,也叫散列表), 是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映 ...

  6. java资料——哈希表(散列表)(转)

    哈希表       散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度. ...

  7. 数据结构 -- 哈希表(hash table)

    简介   哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函 ...

  8. 【阅读笔记:散列表】Javascript任何对象都是一个散列表(hash表)!

    什么是散列表? 散列表是Dictionary(字典)的一种散列表实现方式,字典传送门 一个很常见的应用是使用散列表来表示对象.Javascript语言内部就是使用散列表来表示每个对象.此时,对象的每个 ...

  9. linux内核的双链表list_head、散列表hlist_head

    一.双链表list_head 1.基本概念 linux内核提供的标准链表可用于将任何类型的数据结构彼此链接起来. 不是数据内嵌到链表中,而是把链表内嵌到数据对象中. 即:加入链表的数据结构必须包含一个 ...

随机推荐

  1. threejs 通过bufferGeometry处理每一个点的位置和颜色

    let positions = new Float32Array(points.length * 3); let colors = new Float32Array(points.length * 3 ...

  2. jenkins初始化配置完后设置了管理员账号密码 网页停留时间长了刷新登录不了了

    好像陆陆续续在几台机子安装到最后正式使用的这台机器都是这样.难道是它自己本身的问题吗?只能网上帖子凑了. 找到.jenkins/config.xml文件:(windows环境就是和initialsec ...

  3. Hadoop序列化机制及实例

    序列化 1.什么是序列化?将结构化对象转换成字节流以便于进行网络传输或写入持久存储的过程.2.什么是反序列化?将字节流转换为一系列结构化对象的过程.序列化用途: 1.作为一种持久化格式. 2.作为一种 ...

  4. TS流解析 三

    应该说真正了解TS,还是看了朋友推荐的<数字电视业务信息及其编码>一书之后,MPEG2 TS和数字电视是紧密不可分割的,值得总结一下其中的一些关系. ISO/IEC-13818-1:系统部 ...

  5. mac上 自己安装的python 和 自带python 的可执行文件位置

  6. C++ is-a关系

    首先举一个例子: 在日常生活中,我们所说的眼镜大都是带框的眼镜,但是当提起隐形眼镜时,我们想一下它属不属于眼镜呢?答案肯定是属于的.这里的隐形眼镜和眼镜就是属于 is-a 的关系. 在面向对象编程过程 ...

  7. Linux C 一些函数 所属的头文件

    在编写程序时,有时总是不记得所使用的函数在哪个库函数中.现在先把自己以前经常用到的函数头文件总结一下. 有不对的地方还请指教. 1,系统调用文件的操作函数 #inlclude <fcntl.h& ...

  8. Splunk安装部署基础篇

    Splunk安装(以4.3.4版本为例) 下载splunk软件包,并解压,直接启动即可. --Linux-x86_64.tgz -C /optcd /opt/splunk/bin./splunk st ...

  9. 关于centos6升级python3.6无法使用pip的问题

    用find / -name "pip",也找不到类似/usr/bin/pip类似的命令,说明pip没安装好,那么运行下面的命令 yum install python-pip 然后可 ...

  10. Vue 获取数据、事件对象、todolist

    vue中在方法里获取data里的msg:this.msg 在微信小程序里this.data.msg 改变data里的msg:this.msg="改变后的msg" 可以通过list. ...