目录
写在前面:小结内容大部分来自UESTC本科数据结构教材,书名《数据结构与算法》,ISBN:978-7-301-29776-6
基本概念
- 一般查找:比较要查找的值的key(关键字)和保存的值的key
- 设hash函数 H为从key到地址空间(即保存的值的位置的标识,如数组下标)的映射
- 映射可能一对多,所以需要解决H(key1)=H(key2)的问题,即解决冲突
- hash将查找的“比较”改成了“映射”,提高了效率(但冲突处理的不好会降低效率,最坏情况会使hash退化为“比较”)

hash函数构造方法(怎么算key)
1.直接法
取关键字本身或关键字的某个线性函数作为函数值(hash地址)
- 如直接将key作为数组下标(hash地址),将数组作为地址空间,数组大小即地址空间大小
- 如线性函数ax+b:a*key+b=hash地址
2.数字分析法(对序列各位的分析)
对由r个元素的集合(每个元素可重复取)组成的n位的一个序列,如一串由0-9组成数字串,取其中r个元素出现概率大致相等的s位(1≤s≤n)作为H(key)的值
- s的大小还应根据地址空间的大小调整,即不一定要选出全部符合条件的位
- H(key)的值:直接排列组合s位得到;或为每个位赋权、求和,取和为H(key)。如(从右到左)第一位乘10,第二位乘10^2,第三位乘10^3 ……以此类推
3.平方取中法
取key的平方的二进制数的中间几位为H(key)
- 具体取几位,根据地址空间的大小而定
- 平方原因:使key的各个(转为二进制前的)数位都参与了H(key)的计算;扩大差异,减小冲突
4.折叠法
将key分成位数相等的几部分(最后一部分位数可以不同),取叠加和
- 适用:当key的位数较长时
- 两种叠加:移位叠加、边界叠加
5.取模法
设地址空间大小为m,模设为p,p≤m,则H(key)=key%p
- 或设置基数Base和模Mod,对key的每一位乘以Base然后取模,全部相加,Base和Mod需为素数。如Base=13,Mod=101,对key=21,有H(key)=(1*13 % 101)+(2*13 % 101)。详见字符串hash
- p(Base和Mod同理)取素数原因:若p含质因子pf,对含有质因子pf的key,模p会得到pf的倍数,冲突概率增大。(即key=pf*其他因子,p=pf*其他因子,key除p取余数时,上下先提一个pf,也即key被除掉一个pf,那么,key剩下的其他因子相乘就得到key相对于pf的倍数了,于是,对于key和p剩下的其他因子,无论相除得到的余数是0还是其他值,都是整数,即都是pf的倍数)
6.随机数法
根据key算一个随机数作为H(key)
冲突处理
1.开放地址法
从冲突位置“向后”找第一个空位。注意取模(模大小为地址空间大小)保证不会越界(即遇到尾部了,就返回头部接着找,直到找到空位或找完整个地址空间)
- 线性探测:一个一个地“向后”找
- 二次探测:1^2,(-1)^2,2^2,(-2)^2,……这样跳着找
- 随机探测:取随机数,根据随机数跳着找
2.再hash法
第一个hash函数遇到冲突,就用第二个hash函数计算,再找位置,如果还冲突就用第三个,以此类推
- 缺点:计算量大了点,耗时间
- 优点:冲突较小
3.链地址法
冲突位置设置一个链表,将H(key)相同的点连在一起
- 设置一个指针的数组,初始都是空指针,H(key)对应数组下标,冲突的点,就以那个位置的指针为链表的头指针,建立一个链表
- (可选)每个链表内可以根据key的大小有序排列,即插入时考虑大小顺序
4.公共溢出法
另设一个地址空间(以下简称溢出表)存放冲突的点
- 溢出表最好能动态增长(即向量;c++的话就是vector)
- 溢出表里元素的顺序是时间顺序,即冲突了就往溢出表里面塞,不管原来是哪个位置冲突,就按顺序往溢出表后面塞。
- 因此,查找的时候,如果在地址空间没找到,就要从溢出表的表头找到表尾,直到找到或者找完了都找不到才能退出。故冲突过大的话,效率会退化成一般的查找,hash的映射就没什么意义了。
其他
- hash的平均查找长度与地址空间被占用的情况有关,即填入的元素占地址空间的百分比越大,查找越慢
本文介绍了哈希表的基本概念,包括哈希函数的构造方法(如直接法、数字分析法等)及其冲突处理策略(如开放地址法、再哈希法等),并探讨了这些方法如何影响哈希表的效率。
6964

被折叠的 条评论
为什么被折叠?



