在一个文件中有 10G 个整数,乱序排列,要求找出中位数。内存限制为 2G。

将统计总体当中的各个变量值按大小顺序排列起来,形成一个数列,处于变量数列中间位置的变的量值就称为中位数。

数的个数太多了,不能进行内部排序。

可以使用桶来计数,然后找出中位数。

1.由于是10g个数据所以计数器不能用32bits的,用64bits大小的。每个桶64bits大小,用来计数。2GB/64bits = 256M,所以最多有256million个桶。

可以开辟一个数组,数组元素大小为64bits,数组元素个数为256M。确实是很大的数组啊。

2.数组中的一个元素对应一个桶,有256M个桶,所以需要用28位来表示桶的编号了。2^28 = 256M.

3.假设为32位的数据,且是无符号的。所以根据数据的前28bits放入对应编号的桶中,桶的计数器加1.遍历10g个数,对应的桶中的计数器加1.桶编号越小,对应的数据也越小了。

4.最后将每个桶中的数据相加,假设前面桶中数据个数一共为total(0~n-1), 这时再加上第n个桶中的数据个数时大于等于5g,那么中位数的前28位肯定为桶n的编号了,就是n了。然后再次遍历10g个数,将前28位为n的数的后4位计数,放入对应的桶0到15中。比如后四位为2,放入桶2中。最后从桶0到15,和total(0~n-1)相加,第一次大于等于5g的桶的编号就是中位数的后4位了。得到前28位和后4自然中位数就求出来了。


如果10g数为64位的呢?假设也是无符号的数。也是用256M个桶,根据数据的前28位放入对应的桶中,然后加和各个桶中的计数器,当大于等于5g时,桶的编号n就是中位数的前28位了。假设此时有total(0~n-1)<5g,total(0~n)>=5g.

然后求中间的28位,再次遍历数据,用数据前28位为n的数的中间的28位作为桶的编号,让对应的桶中的计数器加1,再次加和桶中的计数器,大于等于5g时,桶的编号就是中间的28位。假设此时桶的编号为0' 1' 2' ....有total(0~n-1)+total(0' ~ (m-1)') < 5g ,total(0~n-1)+total(0'~m') >= 5g , 中间28位就是m'

最后求后8位了,道理和前面一样。假设此次桶的编号为0'' 1'' 2'' 3'' 4'' .... (2^8-1)''有 total(0~n-1)+total(0' ~ (m-1)')+total(0''~(k-1)'') < 5g   total(0~n-1)+total(0' ~ (m-1)')+total(0''~k'')>5g 后八位就为k''。


如果为有符号的数时,可以将数据加上某个正数,让数据都大于等于0,再处理。

你可能感兴趣的:(算法)