海量数据查找中位数

现在 有10亿个int型的数字(JAVA中 int 型占4B),以及一台可用内存为1GB的机器,如何找出这10亿个数字的中位数?

中位数定义:数字排序之后,位于中间的那个数。比如将10亿个数字进行排序(位置从1到10亿),排序之后,位于第5亿个位置的那个数 就是中位数。

关于中位数,可参考:快速排序中的分割算法的解析与应用

一种方法是定义一个长度为10亿的整型数组,采用排序算法排序。但是:

10亿个数字,每个数字在内存中占4B,10亿个数字完全加载到内存中需要:10*108*4B ,约为:4GB内存。显然不能把所有的数字都装入内存。

这里,采用基于二进制位比较 和 快速排序算法中的“分割思想”来寻找中位数。具体如下:

假设10亿个数字保存在一个大文件中,依次读一部分文件到内存(不超过内存的限制:1GB),将每个数字用二进制表示,比较二进制的最高位(第32位),如果数字的最高位为0,则将这个数字写入 file_0文件中;如果最高位为 1,则将该数字写入file_1文件中。【这里的最高位类似于快速排序中的枢轴元素】

从而将10亿个数字分成了两个文件(几乎是二分的),假设 file_0文件中有 6亿 个数字,file_1文件中有 4亿 个数字。那么中位数就在 file_0 文件中,并且是 file_0 文件中所有数字排序之后的第 1亿 个数字。

【为什么呢?因为10亿个数字的中位数是10亿个数排序之后的第5亿个数。现在file_0有6亿个数,file_1有4亿个数,file_0中的数都比file_1中的数要大(最高位为符号位,file_1中的数都是负数,file_0中的数都是正数,也即这里一共只有4亿个负数,排序之后的第5亿个数一定是正数,那么排序之后的第5亿个数一定位于file_0中)】。除去4亿个负数,中位数就是6亿个正数从小到大排序之后 的第 1 亿个数。

现在,我们只需要处理 file_0 文件了(不需要再考虑file_1文件)。对于 file_0 文件,同样采取上面的措施处理:将file_0文件依次读一部分到内存(不超内存限制:1GB),将每个数字用二进制表示,比较二进制的 次高位(第31位),如果数字的次高位为0,写入file_0_0文件中;如果次高位为1,写入file_0_1文件 中。

现假设 file_0_0文件中有3亿个数字,file_0_1中也有3亿个数字,则中位数就是:file_0_0文件中的数字从小到大排序之后的第1亿个数字。

抛弃file_0_1文件,继续对 file_0_0文件 根据 次次高位(第30位) 划分,假设此次划分的两个文件为:file_0_0_0中有0.5亿个数字,file_0_0_1中有2.5亿个数字,那么中位数就是 file_0_0_1文件中的所有数字排序之后的 第 0.5亿 个数。

......

按照上述思路,直到划分的文件可直接加载进内存时(比如划分的文件中只有5KW个数字了),就可以直接对数字进行快速排序,找出中位数了。当然,你也使用“快排的分割算法”来找出中位数(比使用快速排序要快)

总结:上面的海量数据寻找中位数,其实就是利用了“分割”思想,每次将 问题空间 大约分解成原问题空间的一半左右。(划分成两个文件,直接丢弃其中一个文件),故总的复杂度可视为O(logN) N=10亿。

参考资料:

快速排序中的分割算法的解析与应用

五种常用的算法设计技巧之二:分治算法

海量数据处理之BitMap

原文:http://www.cnblogs.com/hapjin/p/5769087.html

时间: 2024-10-14 00:23:18

海量数据查找中位数的相关文章

Google 面试题:Java实现用最大堆和最小堆查找中位数 Find median with min heap and max heap in Java

Google面试题 股市上一个股票的价格从开市开始是不停的变化的,需要开发一个系统,给定一个股票,它能实时显示从开市到当前时间的这个股票的价格的中位数(中值). SOLUTION 1: 1.维持两个heap,一个是最小堆,一个是最大堆. 2.一直使maxHeap的size大于minHeap. 3. 当两边size相同时,比较新插入的value,如果它大于minHeap的最大值,把它插入到minHeap.并且把minHeap的最小值移动到maxHeap. ...具体看代码 1 /*********

海量数据查找排序

问题:假设一个文件中有9亿条不重复的9位整数,现在要求对这个文件进行排序. 一般解题思路: 1.将数据导入到内存中 2.将数据进行排序 (比如插入排序.快速排序) 3.将排序好的数据存入文件 难题: 一个整数为4个字节 即使使用数组也需要900,000,000 * 4byte = 3.4G内存 对于32位系统,访问2G以上的内存非常困难,而且一般设备也没有这么多的物理内存 将数据完全导入到内存中的做法不现实 其他解决办法: 1.导入数据库运算 2.分段排序运算 3.使用bit位运算 解决方案一:

第1章第1节练习题10 查找中位数

问题描写叙述 一个长度为L(L ≥1) 的升序序列S.处在第 ? L/2 ? 个位置的数称为S的中位数.比如,若序列S1=(11,13,15,17,19).则S1的中位数是15. 两个序列的中位数是含它们全部元素所组成的升序序列的中位数. 比如,若S2=(2,4,6,8,20).则S1和S2的中位数是11. 如今有两个等长升序序列A和B,试设计一个在时间和空间都尽可能高效的算法.找出两个序列A和B的中位数. 算法思想 分别求两个升序序列A.B中位数,设为a和b 1). 若a=b,则a或b即为所求

LeetCode 4 Median of Two Sorted Arrays 查找中位数,排除法 难度:1

思路:设现在可用区间在nums1是[s1,t1),nums2:[s2,t2) 1.当一个数组可用区间为0的时候,由于另一个数组是已经排过序的,所以直接可得 当要取的是最小值或最大值时,也直接可得 2.明显两个数组总长度为偶数的时候需要取最中间两个元素/2.0,长度为奇数时,只需要求最中间那个.所以只需要分别求出最多两个元素,这一步没有想到可以抛弃中位数,直接转化为求第k大的数,导致第一版代码非常难看. 3.当需要取第k个数的时候,设nums1[tmp1],nums2[tmp2]分别是从各自起点出

二分查找&&二分中位数

普通二分查找 1 int bs(int L,int R,int x) 2 {//在l到r区间上查找x,找不到就返回-1 3 int l=L,r=R; 4 while(l<=r){ 5 int m=l+r>>1; 6 if(a[m]==x){ 7 return m; 8 } 9 else if(a[m]>x){ 10 r=m-1; 11 } 12 else{ 13 l=m+1; 14 } 15 } 16 return -1; 17 } 普通版很简单就不详细总结了 二分查找中位数 题意

支线任务8——寻找中位数

题目描述 用以下的一个类实现两个函数 void addNum(int num) - Add a integer number from the data stream to the data structure. double findMedian() - Return the median of all elements so far. class MedianFinder { public: // Adds a number into the data structure. void add

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

题目:在一个文件中有 10G 个整数,乱序排列,要求找出中位数.内存限制为 2G.只写出思路即可(内存限制为 2G的意思就是,可以使用2G的空间来运行程序,而不考虑这台机器上的其他软件的占用内存). 关于中位数:数据排序后,位置在最中间的数值.即将数据分成两部分,一部分大于该数值,一部分小于该数值.中位数的位置:当样本数为奇数时,中位数=(N+1)/2 ; 当样本数为偶数时,中位数为N/2与1+N/2的均值(那么10G个数的中位数,就第5G大的数与第5G+1大的数的均值了). 分析:明显是一道工

10G 个整数找出中位数,内存限制为 2G

题目:在一个文件中有 10G 个整数,乱序排列,要求找出中位数.内存限制为 2G.只写出思路即可(内存限制为 2G的意思就是,可以使用2G的空间来运行程序,而不考虑这台机器上的其他软件的占用内存). 关于中位数:数据排序后,位置在最中间的数值.即将数据分 成两部分,一部分大于该数值,一部分小于该数值.中位数的位置:当样本数为奇数时,中位数=(N+1)/2 ; 当样本数为偶数时,中位数为N/2与1+N/2的均值(那么10G个数的中位数,就第5G大的数与第5G+1大的数的均值了). 分析:明显是一道

在一个文件中有10G个整数,乱序排列,要求找出中位数

 题目:在一个文件中有 10G 个整数,乱序排列,要求找出中位数.内存限制为 2G.只写出思路即可(内存限制为 2G的意思就是,可以使用2G的空间来运行程序,而不考虑这台机器上的其他软件的占用内存). 关于中位数:数据排序后,位置在最中间的数值.即将数据分成两部分,一部分大于该数值,一部分小于该数值.中位数的位置:当样本数为奇数时,中位数=(N+1)/2 ; 当样本数为偶数时,中位数为N/2与1+N/2的均值(那么10G个数的中位数,就第5G大的数与第5G+1大的数的均值了). 分析:明显是一道