从海量数据中找出中位数
来源:互联网 发布:平安车险计算器软件 编辑:程序博客网 时间:2024/05/16 03:33
题目:在一个文件中有 10G 个整数,乱序排列,要求找出中位数。内存限制为 2G。只写出思路即可(内存限制为 2G的意思就是,可以使用2G的空间来运行程序,而不考虑这台机器上的其他软件的占用内存)。
分析:
这是topK问题的一个特殊情况,唯一变化点在于内存限制,解决该中位数问题的方案也可以推广到其他topK,k比较大无法放入内存的问题。
1.原数据不能一次性读进内存,所以不能选择常见的内排序-快排等;但可以利用外排序,然后在寻找中位数。
2.一般问题如果数的范围合适的话可以考虑桶排序或计数排序,但这里假设是32位整数,仍有4G中取值,假设计数也采用32位整数,需要16G数组来计数,超内存。
所以计数是不可以的了,但我们可以适当增大桶的大小,采用桶排序。
3. 对于N个数和K个数都不能一次读进内存的情况,《编程之美》里给出一个方案:设k<K,且k个数可以完全读进内存,那么先构建k个数的堆,先找出第0到k大的数,使用大顶堆,小于堆顶的入堆替换堆顶并调整,大于则pass,扫描一遍后topk小的选择出了了;再扫描一遍数组找出第k+1到2k的数,重建一次堆,这次建堆还要加上大于第k大的元素条件。。。再扫描直到找出第K个数。虽然每次时间大约是nlog(k),但需要扫描ceil(K/k)次。
通过分析可以发现大致以下解法:
1.外排序
2.多次堆排序topk
3.桶排序
前两种方法涉及过多的IO操作,会影响效率,下面着重说下桶排序:
首先假设是32位无符号整数。
1. 读一遍10G个整数,把整数映射到256M个区段中,用一个64位无符号整数给每个相应区段记数。
说明:整数范围是0 - 2^32 - 1,一共有4G种取值,映射到256M个区段,则每个区段有16(4G/256M = 16)种值,每16个值算一段, 0~15是第1段,16~31是第2段,……2^32-16 ~2^32-1是第256M段。一个64位无符号整数最大值是0~8G-1,这里先不考虑溢出的情况。总共占用内存256M×8B=2GB。
2. 从前到后对每一段的计数累加,当累加的和超过5G时停止,找出这个区段(即累加停止时达到的区段,也是中位数所在的区段)的数值范围,设为[a,a+15],同时记录累加到前一个区段的总数,设为m。然后,释放除这个区段占用的内存。
3. 再读一遍10G个整数,把在[a,a+15]内的每个值计数,即有16个计数。
4. 对新的计数依次累加,每次的和设为n,当m+n的值超过5G时停止,此时的这个计数所对应的数就是中位数。
以上方法只要读两遍整数,对每个整数也只是常数时间的操作,总体来说是线性时间。- 从海量数据中找出中位数
- 从海量数据中找出中位数
- 从海量数据中找出中位数
- 从海量数据中找出中位数
- 从海量数据中找出中位数
- 从海量数据中找出中位数
- 从海量数据中找出中位数
- 从海量数据中找出中位数
- 从海量数据中找出中位数
- 海量数据中找出中位数
- 海量数据中查找中位数
- 海量数据中寻找中位数
- 海量数据中寻找中位数
- 海量数据中寻找中位数
- 海量数据中寻找中位数
- 从海量数据中找出重复次数最多的一个
- 从海量数据中找出最小的k个数
- excel如何从海量数据中找出中文
- 如何让你的C#写的更规范
- 文件操作几个简例
- 程序出错后 程序员给测试人员的20条高频回复
- RSA Bad Arguments
- 集锦
- 从海量数据中找出中位数
- GetEnumName应用
- HttpClient 和 HttpURLConnection 共用session
- 第十一次实验任务
- 秒杀多线程第十四篇 读者写者问题继 读写锁SRWLock
- 哪儿不健康,看脸就知道
- OpenCV轮廓---多边形逼近
- Value of type java.lang.String cannot be converted to JSONObject
- (int &)问题