哈希表(散列表)解析以及哈希桶算法解析

博主通过阅读大量关于哈希的网络文献,摘取哈希表以及为解决哈希冲突的哈希桶算法思想中的最重要的内容,更重要的是容易理解;相信阅读此文,即可很直观理解关于哈希的中心思想。

哈希表:

哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

记录的存储位置=f(关键字)

这里的对应关系f称为散列函数,又称为哈希(Hash函数),采用散列技术将记录存储在一块连续的存储空间中,这块连续存储空间称为散列表或哈希表(Hash table)。

哈希表hashtable(key,value) 就是把Key通过一个固定的算法函数既所谓的哈希函数转换成一个整型数字,然后就将该数字对数组长度进行取余,取余结果就当作数组的下标,将value存储在以该数字为下标的数组空间里。(或者:把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。)
而当使用哈希表进行查询的时候,就是再次使用哈希函数将key转换为对应的数组下标,并定位到该空间获取value,如此一来,就可以充分利用到数组的定位性能进行数据定位。

数组的特点是:寻址容易,插入和删除困难;
而链表的特点是:寻址困难,插入和删除容易。
那么我们能不能综合两者的特性,做出一种寻址容易,插入删除也容易的数据结构?答案是肯定的,这就是我们要提起的哈希表。

哈希桶:

对不同的关键字可能得到同一散列地址,即k1≠k2,而f(k1)=f(k2),这种现象称为哈希冲突;
哈希表存在哈希冲突,而哈希桶算法即为解决哈希冲突的方法之一链地址解决冲突。

举个例子,有一组序列为[1,2,3,4,5,6,7,8,9],使用的哈希函数为f(key) = key mod 5,那么依次得到的hasvalue就是[1,2,3,4,0,1,2,3,4],显然在key值为1,6的时候得到的哈希值都为1,如下所示:
在这里插入图片描述
这个时候就产生了冲突了,(也就是不同的key通过映射后得到了同样值的hashvalue。而所谓的哈希桶算法其实就是链地址解决冲突的方法,如上面的例子所示,就可以设置桶的个数为5,也就是f(key)集合的个数,而这样的话,hashvalue就可以作为桶的索引,将1,2,3,4,5分别通过f(key)得到1,2,3,4,0,则可将这几个key放入桶1,2,3,4,0的首地址所指的内存中,然后处理值为6的key,得到hashvalue值为1,这个时候需要放入桶1中,但桶1的首地址已经有了元素1,怎么办?那么就可以为每个桶开辟一片内存,内存中存放所有hashvalue相同的key,冲突的key之间用单向链表进行存储,这样就解决了哈希冲突,在查找对应key的时候,只需要通过key索引到对应的桶,然后从桶的首地址对应的节点开始查找,就是链表顺序找到,对比key的值,直到找到对应key的信息。所以,在冲突的时候,特别是冲突率比较高的时候,桶内的链表就会很长,使得查找效率比较低,而在最坏的情况下,所有的key都对应同一个hashvalue,当然这种情况不会出现,这样的哈希函数选取的也没有意义了,假设这种情况出现,那么哈希表就退化成了单链表,其他桶内存浪费,且将查找效率从O(1)直接降到了O(N),所以上面才说,哈希函数的选择也是很关键的。

注意:典型的如STL容器的unordered_map(C++11)即使用此数据结构

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值