当前位置:   article > 正文

【DS】Hash表及布隆过滤器_最小完美哈希和布隆过滤器的区别

最小完美哈希和布隆过滤器的区别

什么是Hash
     Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。

    HASH主要用于信息安全领域中加密算法,它把一些不同长度的信息转化成杂乱的128位的编码,这些编码值叫做HASH值. 也可以说,hash就是找到一种数据内容和数据存放地址之间的映射关系。

哈希表是根据关键字key直接访问在内存存储位置的数据的一种数据结构。也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。这个映射函数称做散列函数,存放记录的数组称做哈希表。

它通过一个关键值的函数将所需的数据映射到表中的位置来访问数据,这个映射函数叫做散列函数,存放记录的数组叫做散列表。

散列函数能使对一个数据序列的访问过程更加迅速有效,通过散列函数,数据元素将被更快定位。

  1. 直接定址法:取关键字或关键字的某个线性函数值为散列地址。即hash(key)=key或hash(key)=a*key+b{\displaystyle hash(k)=a\cdot k+b},其中{\displaystyle a\,b}为a,b常数(这种散列函数叫做自身函数)
  2. 数字分析法:假设关键字是以r为基的数,并且哈希表中可能出现的关键字都是事先知道的,则可取关键字的若干数位组成哈希地址。
  3. 平方取中法:取关键字平方后的中间几位为哈希地址。通常在选定哈希函数时不一定能知道关键字的全部情况,取其中的哪几位也不一定合适,而一个数平方后的中间几位数和数的每一位都相关,由此使随机分布的关键字得到的哈希地址也是随机的。取的位数由表长决定。
  4. 折叠法:将关键字分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位)作为哈希地址。
  5. 随机数法
  6. 除留余数法:取关键字被某个不大于散列表表长m的数p除后所得的余数为散列地址。即{\displaystyle hash(k)=k\,{\bmod {\,}}p}{\displaystyle p\leq m}。不仅可以对关键字直接取模,也可在折叠法平方取中法等运算之后取模。对p的选择很重要,一般取素数或m,若p选择不好,容易产生冲突。



     以下结构都采用除留余数法来建立哈希表:使用key%数组的大小所得值为哈希地址。

什么是Hash冲突

不同的key值经过哈希函数hash(key)处理之后可能产生相同的值哈希地址,这种情况为哈希冲突,任意的hash函数都不能避免哈希冲突。


哈希表的载荷因子 :



解决Hash冲突的方法

线性探测:当经过hash(key)得出的哈希位置被占用,则往后顺序依次key+i的顺序查找没有被使用的值,来存放数据,i递增

二次探测当经过hash(key)得出的哈希位置被占用,则往后顺序按照key+i^2的顺序查找没有被使用的值,来存放数据,i递增。

如图所示:


处理哈希冲突的开链法,哈希桶,结构如下:




由于hash函数采用除留余数法,而且除数一般是建立的哈希表的capacity(容量),所以为了减少哈希冲突,我们应该尽量使capacity为素数,这样可以一定程度上减少哈希冲突。

下面给上有关哈希表实现的代码,基于线性探测,二次探测,哈希桶的数据结构实现。

https://github.com/lauyoung/hash-Bloomfilter



什么是布隆过滤器:

在日常生活中,包括在设计计算机软件时,我们经常要判断一个元素是否在一个集合中。最直接的方法就是将集合中全部的元素存在计算机中,遇到一个新 元素时,将它和集合中的元素直接比较即可。一般来讲,计算机中的集合是用哈希表(hash table)来存储的。它的好处是快速准确,缺点是费存储空间。当集合比较小时,这个问题不显著,但是当集合巨大时,哈希表存储效率低的问题就显现出来 了。为此我们引入了布隆过滤器,它其实只是一种检测手段而已,而不会真正的存储数据值。

布隆过滤器是由bitmap和几个hash函数实现的,主要用于检查一个元素是否存在与一个集合中,他的优点就是查找时间和快空间效率都优于其他的算法,缺点就是他有误错率。如果想判断一个元素是不是在一个集合里,一般想到的是将所有元素保存起来,然后通过比较确定。链表,树等等数据结构都是这种思路. 但是随着集合中元素的增加,我们需要的存储空间越来越大,检索速度也越来越慢。不过世界上还有一种叫作散列表(又叫哈希表,Hash table)的数据结构。它可以通过一个Hash函数将一个元素映射成一个位阵列(Bit Array)中的一个点。这样一来,我们只要看看这个点是不是 1 就知道可以集合中有没有它了。这就是布隆过滤器的基本思想。

Hash面临的问题就是冲突。假设 Hash 函数是良好的,如果我们的位阵列长度为 m 个点,那么如果我们想将冲突率降低到例如 1%, 这个散列表就只能容纳 m/100 个元素。显然这就不叫空间有效了(Space-efficient)。解决方法也简单,就是使用多个 Hash,如果它们有一个说元素不在集合中,那肯定就不在。如果它们都说在,虽然也有一定可能性它们在说谎,不过直觉上判断这种事情的概率是比较低的。

布隆过滤器的缺点分析:可能你要查找的元素并不存在,但是以前插入的数据刚好将你的key经过几个映射函数的bit位置为1,这就造成一种假象,你要查找的数据存在。直觉上判断这种情况发生的概率还是比较低的,能想到的就是当你的数据量很大 的时候,这种错误率就明显上升了。

如图分析:x元素经过4个hash函数映射的bit位置为1,y,z同样如此,但是此时要映射M元素时,经过hash函数刚好映射到这几个bit位上,就会对其是否存在的判断存在影响。



在很多Key-Value系统中也使用了布隆过滤器来加快查询过程,如 Hbase,Accumulo,Leveldb,一般而言,Value 保存在磁盘中,访问磁盘需要花费大量时间,然而使用布隆过滤器可以快速判断某个Key对应的Value是否存在,因此可以避免很多不必要的磁盘IO操作,只是引入布隆过滤器会带来一定的内存消耗,下图是在Key-Value系统中布隆过滤器的典型使用:


1,当插入的数据增加时,判断效率就降低了。当插入的数据越来越多时,bit位的占用也就越来越多,因此造成的误差判断也就越来越多。判断效率下降。
2,无法增容,没有key值,无法得知原来的数。当扩容时,原来存储的节点的数据就不准确,因此还要重新设计
布隆过滤器无法增容是因为,它不具有hash表的key值,当你扩容时,以前存储的数据就没有映射到,增容后的位置。以前的映射也就没有用,因此得重新插入数据,进行映射。

3,无法删除。删除的时候可能影响其他节点哈希值
设计一个可以删除的布隆过滤器,对每个位记录其引用计数。

设计思路:bitmap<size_t> _arr;将bitmap 的一个int拆分出来,最高位作为bit位,判断数据存在与否,其他的31作为引用计数(引用计数值可达21亿,这个值可以根据具体的情况来分析,以此来设置引用计数的位数,当然也可以将vector<int>的int改为char),当引用计数位0时才真正的将此bit位置为0;其他情况引用计数减一;

参考链接:https://zh.wikipedia.org/wiki/%E5%93%88%E5%B8%8C%E8%A1%A8#.E5.9F.BA.E6.9C.AC.E6.A6.82.E5.BF.B5

http://www.cnblogs.com/haippy/archive/2012/07/13/2590351.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/859209
推荐阅读
  

闽ICP备14008679号