编程珠玑 | 如何给磁盘文件排序

第一章

输入:文件最多包含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];}这样就可以获得一天中任意时间的在线人数。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值