大家好我是苏麟 , 今天继续聊聊海量数据问题 .
理解了前面的题目之后,本文,我们来详细看几道典型的海量数据场景下的查找问题
从40个亿中产生一个不存在的整数
题目要求: 给定一个输入文件,包含40亿个非负整数,请设计一个算法,产生一个不存在该文件中的整数,假设你有1GB的内存来完成这项任务
本题不用写代码,如果能将方法说清楚就很好了,我们接下来一步步分析该如何做
位图存储大数据的原理
假设用哈希表来保存出现过的数,如果 40 亿个数都不同,则哈希表的记录数为 40 亿条,存一个 32 位整数需要 4B,所以最差情况下需要 40 亿*4B=160 亿字节,大约需要16GB 的空间,这是不符合要求的。
40 亿*4B=160 亿字节,大约需要16GB 16GB / 32 = 0.5GB
40 亿/8 字节=5亿字节,大约0.5GB的数组就可以存下40亿个
如果数据量很大,采用位方式(俗称位图)存储数据是常用的思路,那位图如何存储元素的呢? 我们可以使用 bit map 的方式来表示数出现的情况。具体地说,是申请一个长度为 4 294 967 295 的 bit 类型的数组 bitArr (就是boolean类型),bitArr 上的每个位置只可以表示0或1 状态。8个bit 为 1B,所以长度为 4 294 967 295 的 bit 类型的数组占用 500MB 空间,这就满足题目给定的要求了。
那怎么使用这个 bitArr 数组呢? 就是遍历这 40 亿个无符号数,遇到所有的数时,就把 bitArr 相应位置的值设置为 1。例如,遇到 1000,就把bitArr[1000]设置为 1。
遍历完成后,再依次遍历 bitArr,看看哪个位置上的值没被设置为 1,这个数就不在 40 亿个数中。例如,发现 bitArr[8001]==0,那么 8001 就是没出现过的数,遍历完 bitArr 之后,所有没出现的数就都找出来
位存储的核心是: 我们存储的并不是这40亿个数据本身,而是其对应的位置。这一点明白的话,整个问题就迎刃而解了。
40 亿个非负整数中找到出现两次的数
题目要求:32 位无符号整数的范围是 0~4 294 967 295,现在有 40 亿个无符号整数,可以使用最多1GB的内存,找出所有出现了两次的数。
本题可以看做第一题的进阶问题,这里将出现次数限制在了两次
首先,可以用 bit map 的方式来表示数出现的情况。具体地说,是申请一个长度为4 294 967 295x2 的bit 类型的数组bitArr,用 2 个位置表示一个数出现的词频,1B 占用 8 个bit,所以长度为 4 294 967295x2 的 bit 类型的数组占用 1GB 空间。怎么使用这 bitArr 数组呢? 遍历这 40 亿个无符号数,如果初次遇到 num,就把bitArr[num*2 + 1]和 bitArr[num*2]设置为 01,如果第二次遇到 num,就把bitArr[num*2+1]和bitArr[num*2]设置为 10,如果第=次遇到 num,就把bitArr[num*2+1]和bitArrInum*21设置为11。以后再遇到 num,发现此时 bitArrInum*2+11和 bitArrInum*2]已经被设置为11,就不再做任何设置。遍历完成后,再依次遍历 bitArr,如果发现bitArr[i*2+1]和bitArrli*2]设置为10,那么 i就是出现了两次的数。
这期就到这里 , 下期见!