散列表学习笔记(HashTable)
散列表在实际应用中比较多,也是各种面试中出现频率比较高的内容(一般都是考你如何应用)。
散列表是实现字典操作的一种有效数据结构,其最突出的是查找性能,在一些合理的假设下,散列表中查找的平均时间为O(1)。下面介绍几种常见的散列表。
直接寻址表(适用于关键字的全域U比较小的情况)
直接寻址表就是一个数组,其为每一个可能的关键字提供位置,每个位置对应于全域中的一个关键字(可以讲一一对应)。对于直接寻址表,字典操作都是常数时间内完成(插入,查询,删除)。直接寻址表中存储的内容包括: 用来确定某个槽是否为空的标记(可以为关键字本身)和卫星数据(非必要)。
直接寻址表的缺点是有可能浪费空间,比如在实际存储的关键字个数比所有可能的关键字总数小时,而且实际上有可能没有那么多的空间来为每一个可能的关键字都分配一个位置。散列表是片普通数组的推广,但是它是根据关键字计算出相应的下标。由于不在为每一个可能的关键字分配空间,所以可能会存在冲突,即多个关键字映射到同一个位置。
如何得到性能良好的散列表呢?
1) 选择尽可能好的散列函数
除法散列法:选择一个尽可能大的素数且距离2的幂较远
乘法散列法:关键字乘上一个0到1之间的数,提出乘积的小数部分,然后用散列表大小乘以这个小数并向下取整。这里A的选取比较关键,Knuth建议使用2 654 435 769/4 294 967 296
全域散列法:设计一组散列函数,每次从中选择一个进行散列。
2) 选择适当解决冲突的方法
比较常见的有链接法和开放寻址法来解决冲突。
链接法 (比较简单的一个方法,适用于装载因子较大时)
链接法将所有散列到同一个位置的元素都放到一个链表中,而散列表槽中存储一个指针,指向一个链表,其中所有关键字的散列值都一样。链接法查找时间与链表的长度成线性关系,插入为常数时间,删除操作依赖于使用的是单链表还是双链表。
链接法在简单均匀散列的假设下(任何一个给定元素等可能的散列到m个位置,且与其他元素的散列没有关系) ,查找的平均时间为Θ(1+n/m)。
开放寻址法(装载因子小于等于1)
在开放寻址法中,所有的元素都放在散列表里,相比于链接法来说它不使用指针,可以分配更多的槽。为了使用开放寻址法插入一个元素,需要连续的检查散列表,或称为探查。探查的顺序依赖于待插入的关键字。
不成功查找的期望时间为1/(1-n/m) 成功查找的期望时间为 m/n * ln (1/(1-n/m))
探查的几种方法:
线性探查:
缺点:一次集群,当一个空槽前有i 个满的槽时,该空槽被占用的概率为 (i+1)/m 连续背占用的槽就会越来越长,因而平均查找时间会越来越长
二次探查 :
缺点:会有轻微的群集效应
双重散列:比较好的一种探查方法,提供了Θ(n2)种探查序列,而前面两种只有Θ(n)种。
posted on 2015-04-13 19:15 Natsukashiii 阅读(221) 评论(0) 编辑 收藏 举报