第一章
输入:文件最多包含10,000,000 条记录,无重复记录,每条记录是一个7位电话号码(2773889)
输出:升序排列的输入蒸熟的列表
约束:最多1MB的内存空间可用,充足的磁盘存储空间;运行时间最多几分钟,最好10s内;
方法
1. 归并排序:输入文件读取一次,读写中间帮助文件多次
2. 多次遍历排序,根据整数特点排序,每个号码可以用32bit的整数表示,1MB内存可以读取250 000整数。
第一次:0~249 999区间的整数
第二次:250 000 ~ 499 999区间的整数 ...
3. bitmap:用一个1000万个位的字符串表示这个文件,文件读取一次,不使用中间帮助文件
a. for i = [1,n) bit[i] = 0
b. for each i in the input file: bit[i] = 1
c. for i = [0,n): if bit[i] == 1 {write i on the output file}
位图:利用该排序问题的一些特点:
1)数字集合范围受限(7位) <1000 0000
2)数字不会重复,只需记录有没有
3)只有单一整数,无其他关联信息
附录:如下是类似的海量数据问题
1、海量日志数据,提取出某日访问次数最多的那个IP。
如果日志文件足够大到计算机无法存储的情况下,那么可以考虑拆分策略。
我们将日志文件拆分到1024个文件中。拆分策略可以选择为按照ip地址的散列值,即除以1024的余数作为分配依据。每个文件最多容纳4M的ip地址。
对于每个小文件,构建以ip地址为key,出现次数为value的hash_map.这样统计出每个小文件出现最多的那个ip地址,然后就可以得到2014个文件中访问次数最多的那个ip地址。
2、有10个文件,每个文件1G,每个文件的每一行都存放的是用户的query,每个文件的query都可能重复。如何按照query的频度排序?
这其实就是一个归并排序的思路。
1)按照上一题的方法把重新得到10个文件,按照hash(query)%10的结果将query写到对应的文件中。这样我们就有了10个大小约为1G的文件。任意一个query只会出现在某个文件中。利用hash_map统计每个query出现的次数。
2)利用堆排序算法对query按照出现次数进行排序。这样我们就获得了10个文件,每个文件中都是按频率排序好的query。
3)对获得的10个文件进行归并排序,并将最终结果输出到文件中。
3、求一个论坛的在线人数,假设有一个论坛,其注册ID有两亿个,每个ID从登陆到退出会向一个日志文件中记下登陆时间和退出时间,要求写一个算法统计一天中论坛的用户在线分布,取样粒度为秒。
一天总共有3600*24=86400秒。定义一个长度为86400的整数数组int array[86400],每个整数对应这一秒的人数变化值,可能为正也可能为负。
开始时将数组元素都初始化为0。然后依次读入每个用户的登录时间和退出时间,将与登录时间对应的索引值加1,将与退出时间对应的索引值减1。
遍历一遍之后,数组中存储了每秒中的人数变化情况。可能为正也可能为负值。对前n个值累加即可得到第n秒的再现人数。
for(int i=1;i<86400;i++){array[i]+=array[i-1];}这样就可以获得一天中任意时间的在线人数。