数据结构和算法学习(11)-哈希表

来源:互联网 发布:ibm人工智能医学 编辑:程序博客网 时间:2024/04/29 19:21

哈希表是一种数据结构,它可以提供快速的插入和查找操作。它的优点多得难以置信,无论哈希表中有多少数据,插入和删除只需要接近常量的时间,即O(1)的时间级

哈希表不仅速度快,编程实现也相对容易。

哈希表也有一些缺点,它是基于数组的,数组创建后难以扩展。某些哈希表被基本填满时,性能下降的非常验证,所以程序员必须要清楚表中要存储多少数据

而且对于哈希表是没有简便方法可以以人以一种顺序遍历表中数据的,所以如果需要这种能力,就只能选择其它数据结构

哈希化简介

哈希化的重要概念就是如何把关键字转化为数组下标

举一个简单的例子,比如大家在公司或者学校的信息,主要由大家的工号或者学号来进行能够区分,而这种数据一般是顺序增长且不可重复的,即使你退休或者毕业后,你的信息也依旧会存储在系统中,所以这种数据可以直接作为数组的下标

但是如果关键字值不能恰好用于数组的下标时,我们该如何进行转换呢

字典案例

几个经典的例子是字典。如果想吧一本英文字典的每个单词,从a到zyzzyva,都写入计算机内存,以便快速的进行读写,那么哈希表是一个不错的选择。

把单词转换成数组下标需要哈希函数进行转换,不难想到,可以使用ASCII码进行转化,a是97,b是98,以此类推到z是122

然而其实数组为97不利于存储和查找,所以可以自己定义a是1,b是2,c是3等等(不考虑大写字母的情况),还要0代表空格

编码和

可以把各个单子字母的编码和作为下标,例如cats就是c=3,a=1,t=20,s=19,所以3+1+20+19=43

也就是说cats存储在数组下标为43的单元中,所有的英文单词都可以使用这个办法转换成数组下标。

字典最后一个单词可能是zzzzzzzzzz,所有的字符编码就是26*10=260

也就是单词的编码是从1-260

然而假设词典中有50000个单词,所以没有足够的数组下标来索引那么多单词,每个数组数据项大概要存储192个单词

幂的连乘

考虑另一种使用数字替换单词的方法:在一个大于10的数字钟,每一位数位代表用数字乘以从当前位到个位的位数那么多个10

例如7564的意思是7*1000+5*100+4+10+6*1

或者是7*10^3+5*10^2+4*10^1+6*10^0

类似的可以吧单词分解成字母组合,把字母转化成他们的数字代码,乘以适当的27的幂,然后将结果相加

例如把cats转换成数字,先要把书转化成数列,然后每个数诚意相应的27的幂,然后结果想加

3*27³+1*27²+20*27+19*1=60337

这样就生成了一个独一无二的整数

可是回到我们的zzzzzzzzzz上去,我们发现仅27^9就超过7000000000000,,而内存中的数组根本不可能有这么多单元

问题出在我们给每一个可能的单词分配了一个数组单元,不管这个单侧是不是真正的英语单词,导致有很多数组下标对应的单词都是空的

哈希化

我们的目的是尽可能的将幂的连乘算法得到的巨大的整数范围压缩到可接受的数组范围中。

如果只有50000个单词,我们可能会假设数组容量为50000,事实上我们需要多一倍的空间容纳这些单词

也就是说我们要找到一种方法把0到超过7000000000000的范围压缩为0到100000

一种简单的方法是使用取余操作符

假设把0-199的数字压缩为0-9,由于一个数被10整除时,余数一定在0-9之间,多疑0-199的压缩比为20:1

公式为arrayIndex = largeNumber % arraySize;

这就是一种哈希函数,把一个大范围的数字哈系成一个小范围的数字并对应着数组下标。

冲突

把巨大的数字空间压缩成一个娇小的数字空间并不能保证每个单词都可以映射到数组的空白单元

也就是说可能会产生把几个不同的单词哈希化到同一个数组单元,不同的单词有相同的数组下标

有两种方法可以解决这个问题:

开放地址法

前面说过指定的数组大小要两倍于存储的数据量,因此可能会有一般的单元是空的

当冲突发生时,一个方法是通过系统的方法找到数组的一个空位,并把这个单词填入,而不再使用哈希函数得到的数组下标

链地址法

这一种方法是通过创建一个存放单词链表的数组,数组内不直接存储单词

这样,当发生冲突时,新的数据项直接接到这个数组下表所指的链表中

哈希函数

哈希函数的主要优点和目的就是要求快速计算。哈希函数如果运行缓慢,速度就会降低。

哈希函数的目的是得到关键字值的范围,把它用一种方式转化为数组的下标值,这种方法应该使关键字值随机的分布在整个哈希表中。

对于随机关键字来讲,使用index = key % arraySize是令人满意的

然而对于非随机关键字而言,要遵循以下规则

1.不要使用无用数据

2.使用所有数据

3.实用指数作为取模的基数

哈希化的效率

在哈希表中执行插入和搜索操作可以达到O(1)的时间级

如果没有发生冲突,只需要使用一次哈希函数和数组的引用,就可以插入一个新的数据项或者找到一个已存在的数据项

如果发生冲突,存取时间就要依赖后来的探测长度。

在一次探测中,每个单元的存取时间要加上寻找一个空白单元(插入时)或者一个已存在单元的时间

在一次存取中,要检查这个单元是不是空的,以及(查找或删除时)这个单元是不是包含要查找的数据项

因此,一次单独的查找货插入时间与探测的长度成正比,这里还要加上哈希函数的常量时间

平均探测长度以及平均存取时间取决于装填因子(表中项数和表长的比率)

0 0
原创粉丝点击