如何排序10亿个数--外排小试
0.思路
10亿个32位整数需要4G左右的内存,一次性载入内存是不现实的,必须要采用外排。第一次接触,当然是从最简单的办法入手。
我们可以利用大容量的外存作为中转,将10亿个数切分成小块,每一块排序好后写入外存。
切分完成后,对这些小块进行归并排序。同时在归并排序过程中,获得最大(小)值将实时写入文件,这样就可以保证低内存占用。
注:下面的例子为升序排序
1.切分10亿个数
假设’billion’文件为包含10亿个32位整数数的二进制文件,我们需要将’billion’切分为n个小块(我取n为100,即每块10000000个数)暂存在外存。其中每块文件均需被排序,这里我用的是c的库函数qsort
需要注意的是,如果块大小过大(比如我取的10000000*4字节),块将无法作为auto数组分配,只能设为静态数组
static __int32 piece[PIECESIZE]; //PIECESIZE为块大小FILE *billion = fopen( "billion", "rb" );
int i = 0;
while( i < TOTAL / PIECESIZE ){ //TOTAL为billion文件中整数的数量//读取一块fseek( billion, PIECESIZE * i, SEEK_SET );fread( piece, sizeof( *piece ), PIECESIZE, billion );//排序qsort( piece, PIECESIZE, sizeof( *piece ), comp );char fileName[200];snprintf( fileName, sizeof(fileName), "piece/piece%d.bin", i );//输出FILE *outFile = fopen( fileName, "wb" );fwrite( piece, sizeof( *piece ), PIECESIZE, outFile );fclose( outFile );++i;
}
其中comp函数为一个比较函数,返回1或0,可设置为(按升序排列)
int comp( const void *a, const void *b )
{return *(__int32*)a - *(__int32*)b;
}
2.对这n块进行归并排序
10亿个文件已经切分成n块了,并且这n块已经为有序,于是我们可以利用归并排序读取这n块,并将每次的结果实时写入文件。在这期间内存的消耗将维持在很低的水平。
FILE *outFile = fopen( "out", "wb" );
FILE *fileList[FILEAMOUNT]; //FILEAMOUNT即为块的数量
int i;
//打开n个块
for( i = 0; i < FILEAMOUNT; ++i ){char filePath[200];snprintf( fileName, sizeof(fileName), "piece/piece%d.bin", i );fileList[i] = fopen( filePath, "rb" );
}//每个块读取第一个(最小的)元素
int numbers[ FILEAMOUNT ];
for( i = 0; i < FILEAMOUNT; ++i ){fread( numbers + i, sizeof( __int32 ), 1, fileList[i] );
}int n = 0;
//归并
while( 1 ){int minIndex = MinIndex( numbers );if( minIndex == -1 ) break; //所有文件读取完毕//实时写入fwrite( numbers + minIndex, sizeof( __int32 ), 1, outFile );++n;fread( numbers + minIndex, sizeof( __int32 ), 1, fileList[minIndex] );if( feof( fileList[minIndex] ) ){numbers[minIndex] = -1; //本文件读取完毕}
}//操作完成,关闭文件
for( i = 0; i < FILEAMOUNT; ++i ){fclose( fileList[i] );
}
fclose( outFile );
其中MinIndex函数获取数组中最小的值的下标,同时遇到-1会跳过(因为我用-1作为文件读取完毕的标记)。MinIndex函数如果返回-1则代表所有文件读取完毕(数组中全是-1)
int MinIndex( int *arr )
{int i, index = -1;for( i = 0; i < FILEAMOUNT; ++i ){if( arr[i] == -1 ) continue; //判断文件是否读取完毕if( index == -1 || arr[index] > arr[i] ) index = i;}return index;
}
3.总结
根据计时器可知,分割+每块排序用时281s,归并用时453s,可见硬盘IO性能是这个程序主要的耗时
刚接触外排,所以用的方法比较原始和简陋,先去补补算法吧。。
如何排序10亿个数--外排小试相关推荐
- 在10亿个数中找出前1000个最大的
在10亿个数中找出前1000个最大的 假设现在有一个文件,里面存放了10亿个整数,需要找出前1000个最大的. 方法: 1.普通排序,部分排序:几乎不可取. 2.分治法:随机选一个数t,然后对整个数组 ...
- 利用最小堆找出10亿个数中最大的10000个数
最小堆 最小堆是一种完全二叉树,特点是根节点比两个子节点都小(或者根节点比子节点都大) 过程 先找10000个数构建最小堆 依次遍历10亿个数,如果比最小堆的最小值大,则替换这个最小值,并重新构建最小 ...
- 谈从10亿个数中找出前10万个最大的
谈从10亿个数中找出前10万个最大的 期的实验显示10亿个浮点数大概占据3G左右的空间,因此全部一次性读入内存目前在个人PC上是不太现实的.本次讨论不考虑内存等等,只考虑算法. 如果一次性比较排序,然 ...
- 海量数据处理 - 10亿个数中找出最大的10000个数(top K)
海量数据处理 - 10亿个数中找出最大的10000个数(top K问题) 版权声明:本文为博主原创文章,未经博主允许不得转载 前两天面试3面学长问我的这个问题(想说TEG的3个面试学长都是好和蔼,希望 ...
- 10亿个数中找出最大的10000个数
转载自 海量数据处理 - 10亿个数中找出最大的10000个数(top K问题) 前两天面试3面学长问我的这个问题(想说TEG的3个面试学长都是好和蔼,希望能完成最后一面,各方面原因造成我无比想去鹅 ...
- 如何在10亿个数中找到前1000大的数?
2019独角兽企业重金招聘Python工程师标准>>> 如何在10亿个数中找到前1000大的数? 定位 TopN问题 算法 排序不是最优的解决方案: 可以考虑分治法: 类似快速排序中 ...
- 10亿个数中找出最大的10000个数(top K问题)
原博链接: https://blog.csdn.net/cbjcry/article/details/84917432 问题引入:10亿个数中找出最大的10000个数(top K问题) top K问题 ...
- 在存有10亿个数的文件中找到最大的100万个数
这是<编程珠玑>中的一道题目.10亿个整数,假设每个整数需要四个字节,如果使用排序的话,需要大约4G的内存,现在的很多pc都没有多这么内存,更不用说作者那个年代. 我们借助最小堆来解决这个 ...
- 10亿个数中求最大的10个数字
10亿个数中求最大的10个数字 应用场景 比如求10亿个数中的最大的前10个数,此时构建只有10个元素的小顶堆,如果比堆顶小,则不处理:如果比堆顶大,则替换堆顶,然后依次下沉到适当的位置. 比如求10 ...
最新文章
- java 生成pdf itext_使用Java组件itext 生成pdf介绍
- 接口有class类对象吗
- 目前我国家庭计算机用户接入因特网的下述,目前我国家庭计算机用户接入因特网的下述几种方法中,速度最快的是________ 。...
- 互联网基础知识_数字化工业网络—工业互联网的网络技术.pptx
- Swift基础--方法
- makefile之目标与依赖(1)
- 一道NP中的EIGRP拓扑表的题
- 基于SSM实现的网上书城系统【附源码】(毕设)
- [EXCEL高级应用与数据分析].沈浩.扫描版 百度云盘
- C# 正态分布图 标准偏差 STDEV 概率密度函数 NORM.DIST
- uniapp 最接近微信的图片压缩插件 Ba-ImageCompressor
- 无线路由器常用的五种工作模式详细介绍
- 基于asp.net028住院部病人管理系统
- 信息隐藏与数字水印实验:图片类隐写(MATLAB)
- Java程序员如何写简历,给大家一个小建议?
- PtCMS采集,PtCMS采集插件,PtCMS全自动采集无需采集规则详解(图文)
- mysql5.6解压包卸载_windows下安装、卸载mysql服务的方法(mysql 5.6 zip解压版安装教程)...
- 计算机中的图形(Graphic)和图像(Image)
- [转贴]让板载声卡支持ASIO
- 通过可视化图了解您的 Spark 应用程序