散列表(哈希表)查找
-
我们要在a[]中查找key关键字的记录:
顺序表查找:挨个儿比较
有序表查找:二分法查找
散列表查找:? -
记录的存储位置=f(关键字)
散列技术是在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使得每个关键字key对应一个存储位置f(key)。 -
这里我们把这种对应关系称为散列函数,又成为哈希(Hash)函数。采用散列技术将记录存储在一块连续的存储空间中,这块连续存储空间成为散列表或哈希表(Hash table)。
-
散列表的查找步骤:
1 当存储记录时,通过散列函数计算出记录的散列地址
2 当查找记录肘,我们通过同样的是散列函数计算记录的散列地址,并按此散列地址访问该记录 -
构造好的散列函数的两个基本原则: 计算简单 分布均句
直接定址法
- 我们可以取关键字的某个线性函数值为散列地址,即:f(key)=a*key+b
- 例:有一个从1到100岁的人口数字统计表,其中,年龄作为关键字,哈希函数取关键字自身
即:f(key)=key
数字分析法
- 数字分析法通常适合处理关键字位数比较大的情况,倒如我们现在要存储某家公司员工登记表,如果用手机号作为关键字,那么我们发现抽取后面的四位数字作为散列地址是不错的选择。
平方取中法
平方取中法是将关键字平方之后取中间若干位数字作为散列地址。
折叠法
折叠法是将关键字从左到右分割成位数相等的几部分,然后将这几部分叠加求和,并按散列表表长取后几体作为散列地址。
除留余数法
-
此方法为最常用的构造散列函数方法,对于散列表长为m的散列函数计算公式为 f(key)= key mod p(p<=m)
-
事实上,这个方法不仅可以对关键字直接取模,也可以通过折叠、平方取中后再取模。
-
例如下表,我们对有12个记录的关键字构造散列表时
就可以用f(key)= key mod12的方法 -
p的选择是关键,如果对于这个表格的关键字,p还选择12的话,那得到的情况未免也太糟糕了:
-
p的选择很重要,如果我们把p改为11,那结果就另当别论:
随机数法
选择一个随机数,取关键字的随机函数值为它的散列地址。 即:f(key)= random(key)。
- 这里的 random是随机函数,当关键字的长度不等时,采用这个方法构造散列函数是比较合适的。
视不同的情况采用不同的散列函数
现实中,我们应该视不同的情况采用不同的散列函数,这里给大家一些参考方向:
1 计算散列地址所需的时间
2 关键字的长度
3 散列表的大小
4 关键字的分布情况
5 记录查找的频率
处理散列冲突的方法
开放定址法
所谓的开放定址法就是一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入。
线性探测法
- 它的公式是 fi(key)=(f(key )+di) MOD m (di=1, 2,.,m-1)
平方探测法
可以修改di的取值方式,
例如使用平方运算来尽量解决堆积问题
fi(key)=(f(key)+di) MOD m(di=1,-1,4,-4,……,q2,-q2,q<=m/1)
随机探测法
还有一种方法是,在冲突时,对于位移量d采用随机函数计算得到,我们称之为随机探测法
fi(key)=(f(key)+di)MODm(di是由一个随机函数获得的数列)
再散列函数法
fi (key)= RHi(key ) (i=1, 2,3,.k)
链地址法
例:假设关键字集合为{12,67,56,16, 25,37,22,29,15,47,48,34},同样使用除留余数法求散列表。
公共溢出区法
例:假设关键字集 合为{12,67,56,16,25,37,22,29,15,47,48,34},同样使用除留余数法求散列表。