大数问题

1、假设在32位机器上,请在2亿个随机的、未经排序的32位整型数字中找出中间值

 

2亿个32位整型数字共占用空间大小:2*10^8*4(个字节)= 2*10^8*4/(1024*1024)<1G

32位机器可表示的最大的值为2^32

 

1)如果是查找大小为中间值的数:

定义一个bit数组,大小为2^32,读入数字的时候讲该bit位置1,并且统计1的个数n,然后再取出n/21的下标,就是所求

2)如果是查找中位数

方法1:使用类似快排,当partion

              当partion>mid时候,在start,partion-1间找mid

 

3)桶排序,但是需要遍历一遍

 

拓展1:当数据量非常大内存放不开的时候,

如题 “在一个文件中有 10G 个整数,乱序排列,要求找出中位数(内存限制为 2G)”假设整数用32bit来表示。
第一步:要表示10G个整数,最少需要一个64位的数据空间。(10G =5 * 2^31 > 2^32 ) 解释:假如说10G个整数全是1,那么映射后,会全部映射到第一个区间。此时,第一个区间的数值应该表示10G,其他的所有区间的数值都为0。要想表示一个数,这个数的大小是10G,只能是64位了。
第二步:分区间
2G的内存,能够表示多少个64bit,就能分多少个区间。(一个区间 就表示一个64bit的数据空间)区间数位:2G / 64bit = 256M 个区间。
第三步:求区间表示范围
32bit的整数最大值为2^32-1,所以区间的范围是2^32 / 256M = 16.
即0 ~ 15 ,16 ~ 31,32 ~ 47,......(总共256M个)
此时我们有 256M个区间,大小总共为256M * 64bit = 2G内存。
第四步:遍历10G个整数。每读取一个整数就将此整数对应的区间+1。
第五步:找出中位数所在的区间
统计每个区间中整数的值。然后从第一个区间的整数值开始累加。当累加到5G时,停止。此时的区间便包含中位数。记下此区间所表示的范围,设为[a,a+15].并且记下此区间之前所有区间的累加和,设为m。释放掉除包含中位数区间的其他所有区间的内存。
第六步:再次遍历10G个整数,统计出现在区间[a,a+15]中每个值的计数,有16个数值,按照a到a+15排序。设为n0,n1,n2,...n15
第七步:当m+n0+n1+...+nx首次大于5G时,此时的 a+x 就是所求的中位数。

拓展二:

当数据量大,求前最小或最大的K个数的时候,( K比较小)可以使用堆排序,或者set(见剑指offer面30,解法二)


拓展三:

假设淘宝一天有5亿条成交数据,求出销量最高的100个商品并给出算法的时间复杂度。

 

1)维护一个前100大的最小堆,然后遍历一次O(nlogk),显然当n很大时候效率也不是很高,

2)数据分桶,对数量大于100的最后几个桶做堆排序建小顶堆去除100以后的,复杂度是n+log100

 

桶排序的话每个桶的容量怎么确定啊?有可能同样的数据有好多条,但是有的数据只有几条桶的大小怎么确定?

方法:比如现在要在0,2,1,2,1,4,5,8,9,4这10个数里找前三,首先遍历一遍找出最大值9和最小值0,然后自己假定一个平均的桶容量,因为最后要找前三嘛,那么可以定平均每个桶3个元素,那么就需要(9-0)/3=3个桶,所以[0,3]是第一个桶,(3,6]是第二个桶,(6,9]是第三个桶,这时候并没有真的把数据分桶来存,然后再遍历一遍,求得第一个桶有5个元素,第二个桶有3个元素,第三个桶有两个元素,这时候我们发现除了最后两个桶之外,前面的桶都不可能有前三的数,所以不需要对他们进行存储和排序,这时候再遍历一遍,把第二三个桶的数据,也就是>6的数存到一个数组里,数组长度=后两个桶实际容量的总和也就是5,然后对这个数组做堆排序,就能得到前三了,我这个例子数比较少,5亿的数据最后剩下的桶里应该只有几百的数据量,堆排就很快了,而且5亿的初始数据存到数组里内存勉强够用,更大的数据量可以用分布式的系统来做上面的操作

 2种思路比较:

先遍历一遍找最值,复杂度n+计算各桶容量复杂度n+堆排序复杂度100*log k,k是几百的量级,总复杂度就是2n+100logk,直接堆排的话是n*log100,,当n很大的时候明显第一种复杂度低吧~

 

对找中位数的题目来说就是:算完每个桶里有多少个数之后就知道第n/2个元素在第几个桶里了,然后对那个桶排序找第n/2个数就行了~



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