看数据结构写代码(61) 哈希表

来源:互联网 发布:企业级网管软件 编辑:程序博客网 时间:2024/05/22 04:47

前面说的 各种查找都是 基于 “比较” 的基础 来进行 查找的。查找的 效率 要 看 比较的 次数。那么 有没有 不需要 比较,就可以 找到 想要的数据的 方法呢?

哈希表 就是 这样的 一种方法,它用  数组 作为 保存 关键字的 数据原型,通过 一个 哈希 函数f(k),来找到 关键字 存储的位置,从而 找到想要的信息。

例如 我们 想要解决 这样的一个问题:

假设这有一个各种字母组成的字符串,假设这还有另外一个字符串,而且这个字符串里的字母数相对少一些。什么方法能最快的查出所有小字符串里的字母在大字符串里都有?

比如,如果是下面两个字符串:

String 1: ABCDEFGHLMNOPQRS

String 2: DCGSRQPOM

我们 可以用 一个 分配 一个 26 个 int 型的 整形数组 a,将 0~25 分别 代表 A~Z 是否 出现,如果 出现则 值为 1,没有出现 值为0.

则 我们 只需 遍历 String1,然后 将 对应的 元素 设置 为1,然后 遍历 String2 ,如果 查找 过程中 ,遇到了 0 值, 则 不是 。否则 String2 的 字母 在 String1 中 都 存在。

哈希表 虽然 快速,但是 其 数据 原型 基于 数组,同样 有缺陷。

当 查找的 元素 集合 太大,不同的 关键字,却 得到 同样的 地址。即 k1 != k2,, F(K1) = = F(K2),这时 叫做 冲突。冲突 是无法避免的。只能 通过一些方法 减少 冲突。当 我们 插入 元素时,寻找 插入位置,造成的 冲突次数 太多,影响查找效率,我们 只能 重新 建表,这是个 费时的过程。

而且 哈希 是 无法 按 从小到 大 遍历 数据的。


所以 我们在 用哈希的时候得考虑这些:

1.哈希函数

2冲突函数

3初始表长 

4冲突多少次,我们就重新建表,

5.是否需要 顺序遍历。



下面代码 用的是

 哈希函数:除整取余法

冲突函数:开发定址法(线性)

冲突次数 到达 表长的一半 就重新建表。


哈希表基本结构 ,初始化 和销毁

#include "stdafx.h"#include <cstdlib>int hashSize[] = {11,13,17,19};//哈希表容量增加 数组.#define NULL_KEY0struct HashTable{int * base;//数据的基址int count;//表的数量int sizeIndex;//表的容量大小的索引};void initHash(HashTable * t){t->sizeIndex =0;t->base = (int *)calloc(hashSize[t->sizeIndex],sizeof(int));t->count = 0;}void destoryHash(HashTable * t){free(t->base);t->base = NULL;t->sizeIndex = 0;t->count = 0;}


哈希函数:

//除留余数法int hash(HashTable t,int key){return key % hashSize[t.sizeIndex];}

冲突函数:

//开发定址 线性探索解决冲突法int collision(HashTable t,int key,int times){return (key + times) % hashSize[t.sizeIndex];}


查找函数:

int search(HashTable t,int key,int * index,int *ctimes){*index = hash(t,key);*ctimes = 0;while (t.base[*index] != NULL_KEY && t.base[*index] != key){(*ctimes)++;*index = collision(t,key,*ctimes);}printf("------------查找%d, 查找了%d次--------------\n",key,*ctimes+1);if (t.base[*index] == key){return t.base[*index];}else{return NULL_KEY;}}


插入关键字,以及 重建表函数:

void reCreateHashTable(HashTable * t,int key);void insertHash(HashTable *t,int key){int index;//插入位置intctimes;//冲突次数int result = search(*t,key,&index,&ctimes);if (result == NULL_KEY && ctimes < hashSize[t->sizeIndex]/2){//没找到t->base[index] = key;t->count ++;}else{//重新建表reCreateHashTable(t,key);}}//void reCreateHashTable(HashTable * t,int key){printf("--------------重建哈希表----------------\n");int * oldBase = t->base;//保存老空间.int oldSize = hashSize[t->sizeIndex];//老空间的容量大小t->sizeIndex++;int newSize = hashSize[t->sizeIndex];//新空间大小t->base = (int *) calloc(newSize,sizeof(int));//新空间//插入之前将 表的数量置0t->count = 0;for (int i = 0; i < oldSize; i++){if (oldBase[i] != NULL_KEY){insertHash(t,oldBase[i]);}}free(oldBase);//释放老空间insertHash(t,key);//插入冲突的关键字.}

测试函数:

static int testArray[10] = {1,18,7,55,23,45,98,76,35,29};int _tmain(int argc, _TCHAR* argv[]){HashTable table;initHash(&table);for (int i = 0; i < 10; i++){insertHash(&table,testArray[i]);}int index ,count;for (int i = 0; i < 10; i++){search(table,testArray[i],&index,&count);}destoryHash(&table);return 0;}

代码工程文件网盘地址:http://pan.baidu.com/s/1kToXLcj






0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 手上沾到502胶水怎么办 手上弄上502胶水怎么办 手指粘到502胶水怎么办 502粘在桌子上怎么办 脚底起茧走路疼怎么办 脚底有茧走路疼怎么办 脚趾长茧子很疼怎么办 脚底的老茧很痛怎么办 脚底老皮严重厚怎么办 脚趾起茧走路疼怎么办 脚底厚厚的死皮怎么办 脚上老茧走路疼怎么办 脚底很厚的茧怎么办 长螨虫的脸应该怎么办 荞麦皮枕头生虫怎么办 车保养手册丢了怎么办 乳胶枕发黄掉渣怎么办 拉完头发太贴了怎么办 头发又厚又蓬松怎么办 手捻葫芦去皮后怎么办 苹果5s屏幕脱胶怎么办 夏天车内温度高怎么办 反复长粉刺痘痘怎么办 砂锅烫到手很痛怎么办 低压高怎么办吃什么好 熬夜多了掉头发怎么办 复蚕丝被洗过了怎么办 买了梅邦虫草精怎么办 医院不开转院证怎么办 棕垫一直有味道怎么办 棕子床垫味道大怎么办 羊绒大衣洗坏了怎么办 无痕内裤开胶了怎么办 衬衫洗了会缩水怎么办 脾虚引起的眼袋怎么办 沙漠玫瑰根烂了怎么办 多肉种子不发芽怎么办 多肉植物掉叶子怎么办 白色衣服染了蓝色怎么办 白色的衣服染色了怎么办 白毛衣染上金纺怎么办