当实际存储的关键字数目比全部的可能关键字总数要小时,采用散列表就能成为直接数组寻址的一种有效替代,因为散列表使用一个长度与实际存储的关键字数目成比例的数组来存储。
解决冲突:
链接(chaining)
在有冲突的槽里用一条链表存储数据,槽内存链表的头指针;
无论成功与否,查找一个元素的复杂度为
O(1+a)
, 其中a为每个槽内存储元素的个数的期望
(找不到的标志:槽为空,或者槽指向的链表遍历结束,则查找停止)
开放寻址法(open addressing)
如果冲突,则利用规则(探查方法)向下继续寻找,知道找到一个为空或者为DELETE的槽,然后存入;(为什么开放寻址法删除元素的时候,不能将槽置空而是用一个DELETE来标识?因为我们在这里找不到的标识是遇到一个为空的槽意味着所查找的元素不在数组内,查找停止;如果直接置空,会找不到那些和查找元素冲突的元素)
装载因子:0.72(哈希表内的元素n和哈希表的容量m的比值n/m大于0.72时,哈希表会扩充,所有元素重新哈希)
散列函数
好的散列函数应(近似地)满足简单均匀散列假设:每个关键字都被等可能地散列到m个槽位中的任意一个,并与其他关键字已散列到哪个槽位无关。
例子:
将关键字转换为自然数
除法散列法:
h(k)=kmodm
其中m最好是一个大素数
乘法散列法:
h(k)=⌊m(kAmod1)⌋
A为(0 < A < 1)的常数
一般取A= 0.618比较理想
全域散列法:
定义:H为一组有限散列函数,如果从H中随机选择一个散列函数,当关键字
k!=l
时,两者发生冲突的概率不大于
1/m
,这也正好是从集合
{0,1,...,m−1}
中独立地选择
h(k)
和
h(l)
时发生冲突的概率。
此时期望与散列函数的选取有关,不依赖于任何有关关键字分布的假设