`

有一亿个随机数,不排序如何找出其中位数【转】

阅读更多

 

有一亿个随机数,不排序如何找出其中位数

题目:在一个文件中有 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次

 

解法:首先假设是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的整数幂,映射起来也很方便。

分享到:
评论

相关推荐

    按照百十个位分拆链表,然后组合排序

    一时间为种子,生成十个小于1000的随机数,这十个随机数赋给链表得节点,然后按照个十百位进行分拆链表,分拆后的链表按照位大小进行排序组合,三次拆分组合之后,这十个随机数就会按照从小到大排序。

    基于Python的GUI库Tkinter实现的【随机数生成器】源代码

    文章【Python小项目之Tkinter应用】【实用工具】基于Python的GUI库Tkinter实现随机数生成器,随机数可选整数或浮点数、取值范围、个数、排序、分割符、是否重复、保存结果等(文章链接:...本资源实现了一个实用小工具...

    js取0-9随机取4个数不重复的数字代码实例

    本文实例为大家分享了js取0-9随机取4个数不重复的数字的具体代码,供大家参考,具体内容如下 html &lt;input type="button" value="随机生成4位数" onclick="f1()"&gt; script function f1(){ var arr_4=new ...

    VB6常用模块

    2、一维数组排序 3、数组去重复 4、将变量转化为SQL语句的字段值,文本加单引号数字就不加单引号 5、整理字符串,去除连续字符,仅保留N个 6、取指定范围内不重复的随机数序列集合 7、把总额(指定的小数位数)按范围...

    你必须知道的495个C语言问题

    可我找不到任何方法来声明这样的函数——感觉我需要一个返回指针的函数,返回的指针指向的又是返回指针的函数……,如此往复,以至无穷。 数组大小 1.23 能否声明和传入数组大小一致的局部数组,或者由其他参数...

    delphi 开发经验技巧宝典源码

    0086 用回溯法找出n个自然数中取r个数的所有组合 58 0087 0~N位数的任意组合 59 0088 在数组中快速查找近似值 60 0089 实现直接插入法排序 61 第4章 函数应用 63 4.1 字符串处理函数 64 0090 使用...

    《你必须知道的495个C语言问题》

    可我找不到任何方法来声明这样的函数——感觉我需要一个返回指针的函数,返回的指针指向的又是返回指针的函数……,如此往复,以至无穷。 12  数组大小 13 1.23 能否声明和传入数组大小一致的局部数组,或者由...

    VBSCRIPT中文手册

    Replace 函数 返回一个字符串,其中某个指定的子串被另一个子串替换,替换的次数也有规定。 Replace 方法 替换在正则表达式搜索中已发现的正文。 RGB 函数 返回表示 RGB 颜色值的数。 Right 函数 返回字符串最...

    vb Script参考文档

    Replace 函数 返回一个字符串,其中某个指定的子串被另一个子串替换,替换的次数也有规定。 Replace 方法 替换在正则表达式搜索中已发现的正文。 RGB 函数 返回表示 RGB 颜色值的数。 Right 函数 返回字符串最...

    VBScript 语言参考

    Replace 函数 返回一个字符串,其中某个指定的子串被另一个子串替换,替换的次数也有规定。 Replace 方法 替换在正则表达式搜索中已发现的正文。 RGB 函数 返回表示 RGB 颜色值的数。 Right 函数 返回字符串最...

    VBSCRIP5 -ASP用法详解

    Replace 函数 返回一个字符串,其中某个指定的子串被另一个子串替换,替换的次数也有规定。 Replace 方法 替换在正则表达式搜索中已发现的正文。 RGB 函数 返回表示 RGB 颜色值的数。 Right 函数 返回字符串最...

    VBScript 语言参考中文手册CHM

    Replace 函数 返回一个字符串,其中某个指定的子串被另一个子串替换,替换的次数也有规定。 Replace 方法 替换在正则表达式搜索中已发现的正文。 RGB 函数 返回表示 RGB 颜色值的数。 Right 函数 返回字符串最...

    R语言经典实例(中+英)

     12.8 每隔n个选定一个向量元素 330  12.9 找到成对的最小值或者最大值 331  12.10 生成多个因子的组合 332  12.11 转换一个数据框 333  12.12 对数据框排序 334  12.13 对两列排序 335  12.14 移除变量属性 ...

    该压缩包里是Java的复习材料,适合初学者练习,包括简单计算器、分段函数、找素数、水仙花数、质数的和与积、哥德巴赫猜想等等

    该压缩包里是Java的复习材料,适合初学者练习,包括三十五个基本代码练习:简单计算器、分段函数、计算邮资、水仙花数、找素数、绝对素数、星期几、成绩评定、球弹跳高度的计算、统计满足条件的4位数、阶乘和、质数...

    c语言经典案例

    实例190 找出最高分 271 实例191 信息查询 272 实例192 候选人选票程序 274 实例193 计算开机时间 276 实例194 取出整型数据的高字节数据 277 实例195 使用共用体存放学生和 老师信息 278 实例196 使用共用体处理...

    delphi 开发经验技巧宝典源码06

    0086 用回溯法找出n个自然数中取r个数的所有组合 58 0087 0~N位数的任意组合 59 0088 在数组中快速查找近似值 60 0089 实现直接插入法排序 61 第4章 函数应用 63 4.1 字符串处理函数 64 0090 使用...

    Java开发技术大全(500个源代码).

    HelloWorldApp.java 第一个用Java开发的应用程序。 firstApplet.java 第一个用Java开发的Applet小程序。 firstApplet.htm 用来装载Applet的网页文件 第2章 示例描述:本章介绍开发Java的基础语法知识。 ...

Global site tag (gtag.js) - Google Analytics