哈希表
优点:
1. 提供快速的插入和查找, 插入(有时包括删除)只需要接近常量的时间,即 O(1);
2. 编程实现相对容易;
缺点:
1. 基于数组,数组创建后难于扩展,某些哈希表被基本填满时,新能下降的非常严重, 所以开发者需要清楚表中将要存储多少数据, 或者准备好定期的将数据转移到更大的哈希表中,这个过程是费时的;
2. 没有一种简便的方法可以以任何一种顺序(如从小到大)遍历表中数据项,若需要这样只能选择其他数据结构;
若不需要有序遍历,并且可以提前预测数据量大小,那么哈希表的速度和易用性方面是无与伦比的;
关于哈希表和哈希化,一个关键点在于,如何把关键字转换成数组下标;
哈希算法
将任意长度的二进制值映射为较短的固定长度的二进制值, 但是会导致多个长值对应同一个hash值;
如: 将关键字值转成数组的下标值.若关键字是随机的,index = key % arraySize;
折叠: 把关键字的数组分成几组,把这几组数字相加,再取余;
这就引发一个关机问题,冲突的解决. 解决的方法:
1. 开放地址法: 通过在哈希表中再寻找一个空位解决冲突问题,三种方法:
a. 线性探测: 探测下一个可用单元,会引发原始聚焦问题, 当装填因子(已填入hash表的数据项与表长的比)不太大时,聚焦分布的比较连贯;
b. 二次探测:探测相隔较远(步数的平方)的单元,而不是和原始位置相邻的单元,可以消除原始聚焦问题,但是会有二次聚焦的问题 (因为探测序列固定.当不同关键字恰好映射到相同的数组下标时,若按照相同的探测序列寻找下一个可用单元,那么寻找到的都是一样的);
c. 再哈希法:根据关键字使用哈希函数算出不同的步长(依赖关键字的探测序列),但要求表的容积是一个质数 (第二个哈希函数需要具备两个特点:1.和第一个哈希函数不同; 2.不能输出0(否则将没有步长,每次探测都是原地踏步,陷入死循环)) (例如:stepSize=constant-(key%constant))(constant是一个常数,步长的最大值);
2. 链地址法:在哈希表每个单元中设置链表,将数据项的关键字映射到哈希表的单元,而数据项本身插入到这个单元的链表中;
哈希表的实现
1. 数据项的模型类
2. 哈希表的实现类HashTable
3. 哈希表的测试
4. 链地址法 + 有序链表 实现 哈希表
这里因为Link是之前实现链表时写的,只有data字段,就不在改了,理想的Link应该有key(做关键字),value(即data,数据域)两个字段方便使用;代码中的OrderedLinkList即有序链表的实现类,可以参考之前的文章《数据结构和算法-5.1-单链表&有序链表》;
5. 测试哈希表 = 链地址法 + 有序链表
我是今阳,如果想要进阶和了解更多的干货,欢迎关注公众号”今阳说“接收我的最新文章