您的位置:首页 > 理论基础 > 数据结构算法

【数据结构与算法】哈希表

2016-04-11 11:34 465 查看
哈希表是一种随机存取的数据结构,用于存放关键字的集合。以往只能使用链表,但是查找时On时间,哈希表则可以实现O1时间。原理是,使用一个哈希函数,把关键字直接映射为地址或者下标。

哈希函数:

(1)直接地址法:关键字的线性函数;

(2)数字分析法:如果关键字某几位随机出现,取这几位为下标;

(3)平方取中法:位数太长时,平方后取其中的几位,可以利用到全部的位数;

(4)除留取余法:mod

假设一共有k个关键字,有n个槽,那么平均每一个槽要存放k/n个关键字,这个值称为是装填因子。一般我们希望为0.75。

非常有可能的是,不同关键字通过哈希哈数被映射到了同一个位置,就产生了冲突。

解决:

(1)开放地址法:就是发生冲突以后,需要尝试另一个地址,即在当前地址上加一个偏移量,另一个也不行就继续尝试其他的,因此哈希函数需要改变,原本是h(k),现在必须加入一个尝试次数的概念,变为了h(k,i),k为关键字,i尝试次数,第一次调用i=0。

所以,插入的算法就变成了:

i=0;
index=h(k,i);
while(T[index] != null)
index=h(k,++i);
T[index]=k;当发现槽已被占,则需要尝试下一个槽,通过传入次数作为参数。

i=0;
index=h(k,i);
while(T[index] != null){
if(T[index] == k)
return true;
else
index=h(k,++i);
}
return false;如何实现函数h(k,i)?最简单是的线性法,就是当前地址不对,就尝试下一个地址,h(k,i)=h(k)+i。这种方法有一个弊端就是会出现聚集现象,假设现在有连续个槽被占用,那么下一个空槽被占用的概率会大大增加,因此这个连续区域会很容易一直增长,使得查找时间变久。假设有连续i个槽被占,那么下一个空槽被占用的概率是至少为i/n,可见i越大,概率越大,这个聚集也会越大。
相应的改进是二次探测法,即添加一个关于i的二次函数,而非之前的线性。虽然会缓解,但是仍无法摆脱聚集现象的发生。最好的办法是再散列,即偏移量也是关于k的哈希函数。h(k,i)=h1(k)+i*h2(k)。这种随机性的哈希函数可以避免聚集现象。

开放地址法的缺点是无法实现删除功能,因为如果这是连续的槽,删除其中的一个,那么后面的槽就丢失了。

因此,如果对删除操作有要求,必须使用另一种方法,链表法。

(2)链表法:每一个哈希值对应一个链表。

最坏情况可能退化为链表,但是平均情况下是O(1+a)的,a是装填因子,在《算法导论》中被证明。

Java中的HashMap:

也是基于拉链法实现的,不过默认的裝载因子是0.75,默认的大小是16,如果超过了装载因子*size,那么需要做一个resize操作,比较费时,因为resize是把容量扩为2倍,然后把之前的关键字重新哈希,存储到扩容以后的哈希表。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息