算法基础21-《进阶》哈希函数有关的结构和岛问题

1 哈希函数

1.1 认识hash函数

1)输入参数data,假设是in类型,特征:可能性无穷大,比如str类型的参数

2)输出参数类型out,特征:可能性可以很大,但一定是有穷尽的

3)哈希函数没有任何随机的机制,固定的输入一定是固定的输出

4)输入无穷多但输出值有限,所以不同输入也可能输出相同(哈希碰撞)

5)再相似的不同输入,得到的输出值,会几乎均匀的分布在out域上(离散处理)

重点:第5条!所以hash函数又叫做散列函数

通过hash散列之后的值,如果模上一个数,模之后的数仍然是散列的!具有传递性

对于两个输入,即使长的再像,hash函数也会散列,均分分布在值域上

1.2 hash应用函数举例

假设有一个含有40亿个无符号整数的文件,每一个无符号整数含有4个字节,该文件每一行含有一个无符号整数。无符号整数的范围是0到42亿,即0到2的32次方减1的范围。假设我们有一个含有1G字节的内存,试着统计该文件中哪一个整数出现的次数最多

我们用这一个G内存,做一张hash表,key和value都是无符号整数。所以key和value都是4字节,每一条kv含有8字节,hash函数内部索引空间不计。假设我们文件中每一个无符号整数都不相同,需要40亿个kv,大约为8乘以40亿为320亿字节。转化为内存大约需要32G内存空间。所以我们不能直接通过1G内存直接统计,有可能内存会爆掉;

我们1G内存只能装大概1亿条8字节的kv。该文件大概需要32G内存,我们直接通过Hash函数散列后的值,模上40。范围变为0到39,编号0到39号的文件,每一个状态发送到一个文件。同一种数字key,肯定会发送到相同编号的文件中去。经过这样的处理,假设最差的情况文件中40亿个整数均不同,我们大概会发送到0到39的文件中,每个文件大概1亿个整数

用1G的内存,先统计0号子文件中的词频,再释放内存去统计1号,2号直到39号文件。每个文件最多不超过1亿条记录。1G内存不会爆掉。选出40个词频最高的数字,再进行处理

这样处理,即使文件中40亿个数都相同,落到相同的子文件0中去。那么1G内存统计相同的key,只会再原有基础上增大value,内存绝对不会爆掉

1.3 hash函数实现

Hash函数使用的时候,理论上任务增删改查的时间复杂度都为O(1);

1.3.1 认识经典hash(数组加单链表)

假设我们的Hash的key的范围为17,我们新添加的key再这17个格子上,很大可能会出现碰撞,假设我们第一条需要保存的kv为'abc':1,我们用一个函数算出hash值,用该hash值模17,假设得到5。那么我们把这条记录放在5的位置;

同样的方式第二条kv'def':32,算出来的位置为10。第三条kv'bbq':44,算出的位置也为5,那么我们用单链表去串在之前'abc':1的下面

假设我们get我们的’abc’,通过相同的函数算出hash值,再模17,肯定得到5,我们去5的下面去遍历链表,找到’abc’拿出它的值即可

由于使用的hash值进行填充,理论上我们17长度的数组,很容易就碰撞,而且每个格子均匀的碰撞。我们感知到某个位置上的链表长度大于等于6,可以认为其他格子的链表长度也差不多大于等于6。此时我们进行hash扩容,增大我们的数组长度。假设扩容为原数组的两倍,范围为0到34;接着我们用非常暴力的手段,把老的数组上的每个链表上的节点都取出来,重新计算hash值,模34,决定放在新数组的哪个位置,那么根据散列的性质,我们大概知道,样本分配到新的数组中,每个位置链表的长度,大概为3

复杂度分析:对于一个key_value,算key的hash值认为O(1);hash值模一个值O(1);找到数组中的桶,而且桶长度不超过6,那么也是O(1)。所以不涉及到扩容,hash结增删改查操作严格O(1);但是Hash函数是会涉及到扩容的,我们可以假设初始结构的数组长度为2进行推演,那么对于样本容量为N的hash结构,如果扩容,那么N长度的哈希结构会经历log2N,log以2为底的N次。每次扩容的代价时间复杂度为O(N), 对于N样本,之前所有扩容的总代价为O(N)✖log2N。均摊到每次hash值的增删改查,所有hash表考虑扩容的增删改查时间复杂度不是O(1)。而是(O(N)✖log2N)➗ N

但是Hash表有很多改进,比如扩容倍数不是扩两倍,而是扩更多被,用以减少扩容次数,从而减少log的底数。或者假设在Jvm中,用户申请的hash表不够用了,JVM离线扩容,用户无感知;或者我们在数组中放有序表而不是单链表,例如treeSet结构,我们长度就不需要到6再扩容了,等等。我们还是认为hash表在使用时,增删改查操作就是O(1)的,虽然理论上并不是

!!!上述订正,注意上述说扩容代价为O(logN)可以认为为O(1),这种说法是错误的,hash扩容总代价是O(N),均摊下来就是O(1)。因为当我们数据量已经扩容到N,之前的扩容是一次一次叠加而来,可以假设从样本为1的时候开始扩容,N的数据量对应的扩容就是1+2+…+n/4+n/2; 均摊到当前的N,就是O(1)

2 布隆过滤器

1)利用哈希函数的性质

2)每一条数据提取特征

3)加入描黑库

布隆过滤器解决什么问题?

类似没有删除的黑名单系统。常用来解决爬虫黑名单问题,例如我们的爬虫系统爬到一个url把它放到黑名单系统中,另外一个爬虫爬到该url时,先去检查有没有其他系统已经爬过。

假设我们有100亿个url构成的黑名单,首先考虑使用MapSet,一个url假设64字节,100亿个url,大

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值