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

 题目:在一个文件中有 10G 个整数,乱序排列,要求找出中位数。内存限制为 2G。只写出思路即可(内存限制为 2G的意思就是,可以使用2G的空间来运行程序,而不考虑这台机器上的其他软件的占用内存)。

关于中位数:数据排序后,位置在最中间的数值。即将数据分成两部分,一部分大于该数值,一部分小于该数值。中位数的位置:当样本数为奇数时,中位数=(N+1)/2 ; 当样本数为偶数时,中位数为N/2与1+N/2的均值(那么10G个数的中位数,就第5G大的数与第5G+1大的数的均值了)。

分析:明显是一道工程性很强的题目,和一般的查找中位数的题目有几点不同。
1. 原数据不能读进内存,不然可以用快速选择,如果数的范围合适的话还可以考虑桶排序或者计数排序,但这里假设是32位整数,仍有4G种取值,需要一个16G大小的数组来计数。

2. 若看成从N个数中找出第K大的数,如果K个数可以读进内存,可以利用最小或最大堆,但这里K=N/2,有5G个数,仍然不能读进内存。

3. 接上,对于N个数和K个数都不能一次读进内存的情况,《编程之美》里给出一个方案设k<K,且k个数可以完全读进内存,那么先构建k个数的堆,先找出第0到k大的数,再扫描一遍数组找出第k+1到2k的数,再扫描直到找出第K个数。虽然每次时间大约是nlog(k),但需要扫描ceil(K/k) 次,这里要扫描5次。(编程之美 寻找最大的K个数)

解法:首先假设是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时停止,此时的这个计数所对应的数就是中位数。

总结:
1.以上方法只要读两遍整数,对每个整数也只是常数时间的操作,总体来说是线性时间。

2. 考虑其他情况。
若是有符号的整数,只需改变映射即可。若是64为整数,则增加每个区段的范围,那么在第二次读数时,要考虑更多的计数。若过某个计数溢出,那么可认定所在的区段或代表整数为所求,这里只需做好相应的处理。噢,忘了还要找第5G+1大的数了,相信有了以上的成果,找到这个数也不难了吧。

3. 时空权衡。
花费256个区段也许只是恰好配合2GB的内存(其实也不是,呵呵)。可以增大区段范围,减少区段数目,节省一些内存,虽然增加第二部分的对单个数值的计数,但第一部分对每个区段的计数加快了(总体改变??待测)。

4. 映射时尽量用位操作,由于每个区段的起点都是2的整数幂,映射起来也很方便。

 

题目:设计一个数据结构,包括两个函数,插入数据和获得中位数。

 

利用大根堆和小根堆,其中大根堆维护较小的一半数据,小根堆维护较大的一半数据。

然后根据相应的情况,对两个堆做相应的堆化操作,以满足两个堆中元素数目一致。时间复杂度O(lgn)

 

extension:

设计一个堆栈,除了常见的堆栈操作,还有一个返回中位数的操作。

同样利用大根堆和小根堆,来维护中位数。时间复杂度O(lgn)

时间: 2024-12-08 06:16:01

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

Shell脚本实现乱序排列文件内容的多种方法(洗牌问题)_linux shell

洗牌问题:洗一副扑克,有什么好办法?既能洗得均匀,又能洗得快?即相对于一个文件来说怎样高效率的实现乱序排列? ChinaUnix 确实是 Shell 高手云集的地方,只要你想得到的问题,到那里基本上都能找到答案.r2007 给出了一个取巧的方法,利用 Shell 的 $RANDOM 变量给原文件的每一行加上随机的行号然后根据这个随机行号进行排序,再把临时加上去的行号给过滤掉,这样操作之后得到的新文件就相当于被随机"洗"了一次: 复制代码 代码如下: while read i;do ec

安卓-实现一个gridview有9个图片.要乱序排列.怎么为图片设置标志?.乱序后知道是原来是哪个位置?

问题描述 实现一个gridview有9个图片.要乱序排列.怎么为图片设置标志?.乱序后知道是原来是哪个位置? 实现一个gridview有9个图片.要乱序排列.怎么为图片设置标志?.乱序后知道是原来是哪个位置. gridview每一次初始化都要不同的位置排列(乱序排列).排好后要知道原来的位置.怎么设置.小白求教 O(∩_∩)O谢谢 解决方案 程序里用一个数组,记录原始位置就可以了 解决方案二: 不知道要怎么实现可以具体点吗?怎么乱序处理?.谢谢 可以留个联系方式吗?qq什么的. 解决方案三: 在

Chrome谷歌浏览器中js代码Array.sort排序的bug乱序解决办法

[现象] 代码如下: var list = [{ n: "a", v: 1 }, { n: "b", v: 1 }, { n: "c", v: 1 }, { n: "d", v: 1 }, { n: "e", v: 1 }, { n: "f", v: 1 }, { n: "g", v: 1 }, { n: "h", v: 1 }, { n: &qu

文件中有一组整数,要求排序后输出到另一个文件中

 这个主要复习一下文件输入输出流~~ //文件中有一组整数,要求排序后输出到另一个文件中 #include <iostream> #include <fstream> //文件输入输出流 #include <vector> using namespace std; int main() { ifstream InFile("in.txt"); if(InFile.good()) { cout<<"open file succe

c#-如何将多个txt文本合并在一个文本里面并且完全打乱行序

问题描述 如何将多个txt文本合并在一个文本里面并且完全打乱行序 我现在有几个个txt文件,每个文件里面都是一行一行的数据,单个文件差不多1G, 我现在想把他们合并在一个txt文件中,并且打乱他们的行序,我原本想各个文件先读取几行,放在一个数组里面打乱写入新的文本,接着在读取这些文件接下来的几行,还是合并打乱写入,知道全部读完,但是我不知道怎么去控制这个每次读取那些行 解决方案 文本文件是没有办法随机读写的,如果你能得知每行的最大字符数(假定用maxcharsnum表示),你可以先将这些文本文件

电信发送彩信乱序

问题描述 最近公司开发了一个短信平台系统:使用的是电信接口发彩信安卓手机接收正常,苹果的就乱序我使用的是电信的制作规范代发彩信,每一帧的文字内容放在一个TXT文件中,每一帧的图片保存为一个JPG文件.文件名为帧号的数字,比如:第一帧的图片的文件名为1.jpg,第一帧的文字的文件名为1.text,以此类推 解决方案

Linux du命令查看文件夹大小并按降序排列_linux shell

1. df -lh 2. du -s /usr/* | sort -rn 这是按字节排序 3. du -sh /usr/* | sort -rn 这是按兆(M)来排序 4.选出排在前面的10个 du -s /usr/* | sort -rn | head 5.选出排在后面的10个 du -s /usr/* | sort -rn | tail du -h –-max-depth=0 user du -sh –-max-depth=2 | more 总结du常用命令 du -h --max-dept

解决Android ListView异步加载图片乱序问题

在Android所有系统自带的控件当中,ListView这个控件算是用法比较复杂的了,关键是用法复杂也就算了,它还经常会出现一些稀奇古怪的问题,让人非常头疼.比如说在ListView中加载图片,如果是同步加载图片倒还好,但是一旦使用异步加载图片那么问题就来了,这个问题我相信很多Android开发者都曾经遇到过,就是异步加载图片会出现错位乱序的情况.遇到这个问题时,不少人在网上搜索找到了相应的解决方案,但是真正深入理解这个问题出现的原因并对症解决的人恐怕还并不是很多.那么今天我们就来具体深入分析一

乱序写入导致的索引膨胀(B-tree, GIN, GiST皆如此)

标签 PostgreSQL , 索引分裂 , 乱序写入 背景 有些场景,用户会发现重建索引,索引比原来更小. 通常这种情况是索引字段乱序写入,导致索引频繁分裂,使得索引页并不是百分百填满.膨胀使然. B-Tree索引 由于索引页中的数据是有序的,因此在乱序写入时,索引页可能出现分裂,分裂多了,空洞就会多起来(一页里面没有填满). 例子 1.先建索引,乱序写入. postgres=# create table t_idx_split(id int); CREATE TABLE postgres=#