1. 在一个文件中有 10G 个整数,乱序排列,要求找出中位数。内存限制为 2G。只写出思路即可。
海量数据处理的问题。10G 个数,中位数就是第 5G、第 5G+1 个数。回想一下,一般情况下求中位数的做法:类似于快排的 partition,找到一个数,使比它小的数的个数占到总数的一半就行。所以,可以把数值空间分段,然后统计每一段中数据的个数,这样就可以很容易的确定中位数在那一段。找个该段后,数据量已经急剧减小了,剩下的问题就好处理了。这种方法可以说是桶排序的思想,也可以说是 hash 的思想。下面具体分析一下:
因为要统计每一段中数据的个数,所以可以用一个 unsigned int 型。unsignedint 一般占 4 个字节,可以计数到 2^32-1,大约是 4G。题目中有 10G 个数,如果有很多数落在同一个段中,unsigned int 肯定不够用。所以,这里的计数用要 8 字节的 long long。即,相当于有一个数组,数组是 long long 性,数组的每一个元素,代表了一个数据段内的数据个数。这个数组有多大?为了充分利用 2G 内存,数组大小 2G/8= 256M。即,有数组 long long cnt[256M].
假设题目中的 10G 个数都是 4 字节的 int。如何把这 10G 个整数,映射到 cnt[256M] 的数组中。可以使用计算机中的虚拟地址到物理地址的转换。取 int 的高 28 位作为数组下标的索引值,这样就可以完成映射。
整个算法的流程:
1)扫描 10G 个整数,对每个整数,取高 28 位,映射到数组的某个元素上,给数组的这个元素加 1,表示找到一个属于该数据段的元素
2)扫描完 10G 个整数后,数组 cnt 中就记录了每段中元素的个数,从第一段开始,将元素个数累计,直到值刚好小于 5G,则中位数就在该段
3)这时对 10G 个整数再扫描一遍,记录该段中每个元素的个数。直至累计到 5G 即可。