参考:《大话数据结构》
1.定义
散列技术是通过查找关键字而不需要比较就能获得需要的记录的存储位置,主要是面向查找的存储结构。
散列技术是在记录的存储位置和它的关键字之间建立的一个确定的对应关系f,使得对于每个关键字key对应一个存储位置f(key)。
对应关系f成为散列函数(或哈希(Hash)函数)。采用散列技术将记录存储在一块连续的存储空间中,这块连续的存储空间成为散列表或哈希表。
对于散列技术,最关键的的问题是散列函数的设计,如何设计一个简单、均匀、存储利用率高的散列函数是散列技术中最关键的问题;另一个问题是地址冲突,即两个关键字key1≠key2,结果出现f(key1) = f(key2),如何处理冲突是一个很重要的问题。
2.散列函数的构造方法
2.1 直接地址法
散列函数为:f(key) = key 或者 f(key) = a*key + b (a,b为常数)
这样的散列函数优点是简单、均匀,也不会产生冲突,但问题是这需要事先知道关键词的分布情况,适合查找表较小且连续的情况。此方法虽然简单,但是不常用。
2.2 数字分析法
比如关键字是位数较多的数字(手机号),前7位一般是相同的,可以抽取后四位。
如果后四位出现冲突的问题,可以对抽取的数字进行反转(1234改为4321)、右环位移、左环位移等方式。
抽取是使用关键字的一部分来计算散列表存储位置的方法,这在散列函数中是常常用到的手段。
该方法通常适用于处理关键字位数比较大的情况,如果事先知道关键词的分布,且关键词的若干位分布比较均匀,可以考虑用这种方式。
2.3 平方取中法
关键字1234,平方为1522756,抽取中间的3位227,作为散列地址。
适合于不知道关键词的分布,而位数又不是很大的很大的情况。
2.4 折叠法
比如关键字9876543210,设散列表表长为3为,分成4组,折叠求和987+654+321+0 = 1962,再取后3位得到散列表地址为962。
2.5 除留余数法
最常用的构造散列函数的方法。对于散列表长为m的散列函数的公式为:
f(key) = key mod p (p <= m)
关键在于p的选择,根据前辈的经验,p通常选小于等于表长(最好接近m)的最小质数或不包括小于20质因子的合数。
2.6 随机数法
散列函数为:
f(key) = random(key)
当关键词长度不等时,可以考虑这种方式。
工业界比较著名的哈希函数包括MD4,MD5和SHA-1。其中MD5和SHA-1(安全哈希算法)可以说是目前应用最广泛的Hash算法,而它们都是以MD4为基础设计的。
注意:对于字符串,无论是何种字符(包括中文和英文),它们都可以转化为某种数字来对待,比如ASCII码或者Unicode码,再使用上述方式。
3.处理散列冲突的方法
3.1 开放定址法
线性探测法公式为:
fi(key) = (f(key) + di) mod m (di = 1,2,...,m - 1)
二次探测法公式为:
fi(key) = (f(key) + di) mod m (di = 1^2,-1^2,2^2,-2^2,...,q^2,-q^2,q <= m/2)
3.2 再散列函数法
实现准备多个散列函数:
fi(key) = RHi(key) (i = 1,2,...,k)
3.3 链地址法
将所有关键词为同义词的记录存储在一个单链表中。
3.4 公共溢出区法
出现冲突的关键词存到溢出表中。