哈希表在查找方面有非常大应用价值,本文记录一下利用哈希散列表来统计文本文件中每个单词出现的重复次数,这个需求当然用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. animationx详解

    animation是CSS3中极其强大的功能,它可以完成许多炫酷有趣的动画效果,网上也有非常不错的类库.下面将做详细介绍. 1.@keyframes:用于定义动画的具体动作(帧动作),一般要加上浏览器 ...

  2. [CSAcademy]Colored Forests

    csacademy description 有\(M\)种颜色编号为\(1-M\).现给树上的每个点染上这\(M\)种颜色中的一种,定义一棵树是\(\mbox{colorful}\)的当且仅当这棵树上 ...

  3. LG4717 【模板】快速沃尔什变换

    题意 题目描述 给定长度为\(2^n\)两个序列\(A,B\),设\(C_i=\sum_{j\oplus k}A_jB_k\)分别当\(\oplus\)是or,and,xor时求出C 输入输出格式 输 ...

  4. QLoo graphql engine 学习二 基本试用(kubernetes)

    已经测试过docker&& docker-compose 的运行模式,下面测试下kubernetes的运行模式 kubernetes 我使用docker for mac qloo 安装 ...

  5. eclipse 3.7 中英文自由切换

    最近在学习Java的开发,然后又很多的资料是对于的英文环境讲解,有的资料是对应的中文环境讲解,所以很都对不上号,郁闷啊....... 而且开发的时候,每个人都使用习惯也不相同:有的人喜欢英文界面,有的 ...

  6. PHP安全性漫谈

    最近刚做完两个PHP的网站项目,客户虽然没有安全性的相关需求,但是自己不能放过对自己的要求,何况对以后做电子商务的项目相当有帮助,呵呵,早准备早超生,经过查看PHP 帮助和相关资料~~~~       ...

  7. 全是干货!UI设计的30条黄金准则!

    http://www.wex5.com/portfolio-items/js-1/ 全是干货!UI设计的30条黄金准则!   总的来说,好的UI界面有几个特征:简洁.便利.目标明确.人性化.字面上看这 ...

  8. Java 从原字符串中截取一个新的字符串 subString()

    Java 手册 substring public String substring(int beginIndex) 返回一个新的字符串,它是此字符串的一个子字符串.该子字符串从指定索引处的字符开始,直 ...

  9. Executors中的几种线程调用方式

    一.Executors是java5以后提供的一套api,使用跟上面非常方便.Sun在Java5中,对Java线程的类库做了大量的扩展,其中线程池就是Java5的新特征之一,除了线程池之外,还有很多多线 ...

  10. CentOS下MySQL的彻底卸载

      #################CentOS7下MySQL的卸载#################### 1:查看MySQL是否安装: 方式1: [root@localhost usr]# yu ...