很多小伙伴面试时,会碰到面试官问到如何解决哈希冲突的问题,要理解哈希冲突,首先要弄清楚hash函数和hash表(散列);
一、哈希表
hash函数:所谓hash函数其实就是指一类加密算法(MD5/SHA等),将任意长度的输入变换为固定长度的输出的不可逆的单向密码体制,即index=Hash(key);
简单的讲,hash函数就是根据key值计算出数据应该存放的地址,而哈希表则是基于哈希函数建立的一种查找表;
二、常见hash函数的构造方法
1、直接定制法:哈希函数为关键字的线性函数如 H(key)=a*key+b,这种构造方法比较简便均匀,但是有很大限制,仅限于地址大小=关键字集合的情况;
2、数字分析法:假设关键字集合中的每个关键字key都是由s位数字组成(key1,key2,key3,....,keyn),分析key中的全体数据,并从中提取分布均匀的若干位或他们的组合构成全体;
3、平均取中法:如果关键字的每一位都有某些数字重复出现频率很高的现象,可以先求关键字的平方值,通过平方扩大差异,而后取中间数位作为最终存储地址;
4、折叠法:如果数字的位数很多,可以将数字分割为几个部分,取他们的叠加和作为hash地址;
5、除留余数法:H(key)=key MOD p (p<=m m为表长)
三、hash冲突的常见解决方案
不论hash函数设计的如何巧妙,总会有特殊的key导致hash冲突,即H(key1)=H(key2),特别是对动态查找表来说,为了解决此类冲突,有以下几种方案:
1、开放定址法(开放寻址法):
首先有一个H(key)的哈希函数
如果H(key1)=H(keyi)
那么keyi存储位置Hi=(Hash(key)+di) MOD m (m为hash表长度)
di通常有三种取法:
1)线性探测再散列:di=c∗i
2) 平方探测再散列:di = 1^2,-1^2,2^2,-2^2....
3) 随机探测再散列(双探测再散列):di是一组伪随机数列
2、链地址法:
产生hash冲突后在存储数据后面添加一个指针,指向后面冲突的数据,如下所示:
3、公共溢出区法:建立一个特殊存储空间,专门存放冲突的数据,此种方法适用于数据和冲突较少的情况
4、再hash法(再散列法):准备若干个hash函数,如果使用第一个hash函数发生了冲突,则换一个hash函数,以此类推...
hash函数设计的考虑因素
1.计算散列地址所需要的时间(即hash函数本身不要太复杂)
2.关键字的长度
3.hash表的长度
4.关键字分布是否均匀,是否有规律可循
5.设计的hash函数在满足以上条件的情况下应尽量减少冲突