一、散列函数的构造方法:
1.直接定址法
例,f(key) = a * key + b(a, b 为常数)
简单但不常用
2.数字分析法
如果关键字是位数较多的数字,抽取关键字的一部分来计算散列存储位置。还可以对抽取出来的数字再进行反转,右环位移等方法。
应用场景:通常适合处理关键字位数比较大的情况,如果事先知道关键字的分布且关键字的若干位分布较均匀,可以考虑使用这个方法。
3.平方取中法
计算数字的平方,再从中间取几位用作散列地址。
应用场景:适合于不知道关键字的的分布,而位数又不是很大的情况。
4.折叠法
将关键字从左到右分割成位数相等的几部分(最后一部分位数不够可以短些),然后将这几部分叠加起来求和,再按散列表表长,取后几位作为散列地址。
应用场景:折叠法事先不知道关键字的分布,适合关键字位数较多的情况。
4.除数留余法
此方法为最常用的构造散列函数的方法。对于散列表长为m的散列函数公式为:
f(key) = key mod p (p <= m)
此方法的关键在于选择合适的p,根据经验,通常p为小于或等于表长的最小质数或不包含小于20质因子的合数。
5.随机数法
取关键字的随机函数值为它的散列地址。
f = random(key)
应用场景:当关键字的长度不等时,采用这个方法构造散列函数是比较合适的。
二、处理散列冲突的方法
1 开放地址法
一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,
空的散列总能找到,将记录存入。
f i ( key ) = ( f( key )+ d i ) mod m ( i = 1,2,…… , k ( k ≤ m – 1))
其中: f ( key ) 为关键字 key 的直接哈希地址, m 为哈希表的长度, di 为每次再探测时的地址增量。
采用这种方法时,首先计算出元素的直接哈希地址 f ( key ) ,如果该存储单元已被其他元素占用,则继续查看地址为 f ( key ) + d 2 的存储单元,如此重复直至找到某个存储单元为空时,将关键字为 key 的数据元素存放到该单元。
增量 d 可以有不同的取法,并根据其取法有不同的称呼:
( 1 ) d i = 1 , 2 , 3 , …… 线性探测再散列;
( 2 ) d i = 1^2 ,- 1^2 , 2^2 ,- 2^2 , k^2, -k^2…… 二次探测再散列;
( 3 ) d i = 伪随机序列 伪随机再散列;
2.再散列函数法
对于散列表,准备多个散列函数。
fi=RHi(key), i=1,2,…,k RHi均是不同的散列函数(比如除留余数、折叠、平方取中),在同义词产生地址冲突时就换用另一个散列函数计算散列地址,直到碰撞不再发生,这种方法不易产生“聚集”,但增加了计算时间。
3.链地址法
将所有关键字为同义词的记录存储在一个单链表中,称这种表为同义词子表,在散列表中只存储所有同义词子表的头指针。
4 公共溢出区法
为所有冲突的关键字记录建立一个公共的溢出区来存放。在查找时,对给定关键字通过散列函数计算出散列地址后,先与基本表的相应位置进行比对,如果相等,则查找成功;如果不相等,则到溢出表进行顺序查找。如果相对于基本表而言,在有冲突的数据很少的情况下,公共溢出区的结构对查找性能来说还是非常高的