您的位置:首页 > 其它

哈希表总结

2016-05-27 08:00 211 查看

一、哈希表/散列表

简单的来说将数据按规律放,然后按照规律来查找的这么一个存放数据的表

它通过一个关键值的函数将所需的数据映射到表中对应的位置来存放数据和访问数据

这个映射的函数就叫做散列函数

这个存放记录的表就叫做散列表

二、构造哈希表的方法

1、.直接定址法

取关键字的某个线性函数为散列地址,Hash(Key)= Key 或 Hash(Key)= A*Key + B,A、B为常数。

优点:简单没有哈希冲突

缺点:所开辟的空间过大,利用率不高

2、除留余数法

取关键值被某个不大于散列表长m的数p除后的所得的余数为散列地址。Hash(Key)= Key % P。

优点:空间利用率高

缺点:设计复杂,要处理哈希冲突

三、哈希冲突/哈希碰撞

不同的Key值经过哈希函数Hash(Key)处理以后可能产生相同的值哈希地址,我们称这种情况为哈希冲突。任意的散列函数都不能避免产生冲突

四、影响哈希表效率的因素

(1)哈希函数是否均匀

(2)处理冲突的方法

(3)哈希表的负载因子(简单的来说就是填入表中的元素个数/散列表的长度)

下面这幅图片是载荷因子的定义:



五、处理哈希冲突的闭散列的方法

1、线性探测

简单的来说就是遇到哈西冲突就查找下一个位置,看位置上是否有数据,假如有则继续查找,假如没有则将数据放入到当前位置

局限性:引发洪水式的冲突,冲突越来越多,找的越来越慢(因为找到的是一片冲突,找到空才停下来),效率低

具体过程如图所示:



2、二次探测

以二次方的形式进行探测

具体过程如下图所示:



六、处理哈希冲突的开链法(哈希桶)

闭散列最大的局限性就是空间利用率低,例如载荷因子为0.7,那么仍有0.3的空间未被利用

使用开链法可以使载荷因子为1,每个链上都挂常数个数据,对于哈希表的开链法来说,其开的空间都是按素数个依次往后开的空间

· 那么什么时候扩容呢?当每个链上都挂上数据之后,载荷因子为1的时候,就可以开始扩容了

具体过程如下图所示:



七、优化

对于除留余数法,capacity的选择很重要,选择好的话可以大大降低发生哈希冲突的概率,所以使用素数表对齐做哈希表的容量,降低哈希冲突;

const int _PrimeSize = 28;
static const unsigned long _PrimeList[_PrimeSize] =
{
53ul, 97ul, 193ul, 389ul, 769ul,
1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
1610612741ul, 3221225473ul, 4294967291ul
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  哈希表