Hash冲突的概念
哈希算法 的目的就是将一串很大的数据根据一定的规则转换为较小的数据。
把任意长度的二进制值串映射为固定长度的二进制值串,这个映射的规则就是哈希算法,而通过原始数据映射之后得到的二进制值串就是哈希值。
在这个转换过程中,总会出现两个不同的数据在经过哈希算法的计算后生成了相同的哈希值。这就是哈希冲突。
哈希冲突带来的影响:
在哈希表中,两个不同数据的哈希值相同,那么不论这两个数据中任意一个先存放到指定位置之后,第二个数据都没有地方可以存放了。所以设计哈希算法的时候一定要注意哈希冲突问题!
哈希算法满足的几点要求:
- 从哈希值不能反向推导出原始数据(所以哈希算法也叫单向哈希算法);
- 对输入数据非常敏感,哪怕原始数据只修改了一个 Bit,最后得到的哈希值也大不相同;
- 散列冲突的概率要很小,对于不同的原始数据,哈希值相同的概率非常小;
- 哈希算法的执行效率要尽量高效,针对较长的文本,也能快速地计算出哈希值
常见的三种解决哈希冲突的方法
1. 开放地址法
为产生冲突的地址Hash(key)求得一个地址序列:
H0,H1,H2,...,Hn 1 <= n <= m - 1 其中m为表的大小
H0 = H(key) Hi = (H(key)+ di)% m i=1,2,...n
形象地一句话来说,就是根据增量di不断地往后找可以存放的下标。
增量di可以有下面三种取值:
- 线性取值,1,2,3…这样,也就是从冲突位置不断往后找下一个可以存放的下标
- 二次取值,1,4,9…这样,也就是从冲突位置不断往后找x的二次方的下标,其中x从1开始线性增大
- 随机取值,di可以去任意随机值,随机找一个
开放定制法有很明显的缺点
元素不能删除
当哈希表中元素越来越满时,效率明显下降
2. 二次哈希法
若通过一次哈希算法计算出来的结果相同,那么久在原基础上再用另外的哈希函数进行计算,直到不再产生相同的哈希值为止。需要设计不同的哈希算法,类似于开放地址法;
3. 链地址法
每个下标中存的都是一个链表,相同哈希值的key直接往下标中的链表后面插入就行了
链地址法也是目前最常用的一种方法,尤其是当今的电脑性能较好时候。
但是也存在一定的缺陷:
- 需要稍微多一点的空间来存放元素,因为还要有一个指向下一个节点的指针
- 每次探测也要花费较多的时间,因为它需要间接引用指针,而不是直接访问元素
目前稍微总结了一下,还有一些不完善,欢迎评论指出,而且可能不同的人有不同的命名法则,链地址法也称拉链法,或者哈希桶。