1亿个数据取前1万大的整数
来源:互联网 发布:nib文件怎么打开 mac 编辑:程序博客网 时间:2024/05/25 08:12
数据规模分析
不考虑操作系统的区别,通常将C++中的一个整型变量认为4bytes。那么1亿整型需要400M左右的内存空间。当然,就现代PC机而言,连续开辟400M的内存空间还是可行的。因此,下面的讨论只考虑在内存中的情况。为了讨论方便,假设M=1亿,N=1万。
用大拇指想想
略微考虑一下,使用选择排序。循环1万次,每次选择最大的元素。源代码如下:
//解决方案1,简单选择排序//BigArr[]存放1亿的总数据、ResArr[]存放1万的总数据void solution_1(int BigArr[], int ResArr[] ){ for( int i = 0; i < RES_ARR_SIZE; ++i ){ int idx = i; //选择最大的元素 for( int j = i+1; j < BIG_ARR_SIZE; ++j ){ if( BigArr[j] > BigArr[idx] ) idx = j; } //将最大元素交换到开始位置 ResArr[i] = BigArr[idx]; std::swap( BigArr[idx], BigArr[i] ); }}
性能分析: 哇靠!时间复杂度为O(M*N)。 有人做过实验《从一道笔试题谈算法优化(上)》,需要40分钟以上的运行时间。太悲剧了......
当然,用先进的排序方法(比如快排),时间复杂度为O(M*logM)。虽然有很大的改进了,据说使用C++的STL中的快排方法只需要32秒左右。确实已经达到指数级的优化了,但是否还能够优化呢?
稍微动下脑子
我们只需要1万个最大的数,并不需要所有的数都有序,也就是说只要保证的9999万个数比这1万个数都小就OK了 。我们可以通过下面的方法来该进:
(1) 先找出M数据中的前N个数。确定这N个数中的最小的数MinElement。
(2) 将 (N+1) —— M个数循环与MinElement比较,如果比MinElement还小,则不处理。如果比MinElement大,则与MinElement交换,然后重新找出N个数中的MinElement。
//解决方案2void solution_2( T BigArr[], T ResArr[] ){ //取最前面的一万个 memcpy( ResArr, BigArr, sizeof(T) * RES_ARR_SIZE ); //标记是否发生过交换 bool bExchanged = true; //遍历后续的元素 for( int i = RES_ARR_SIZE; i < BIG_ARR_SIZE; ++i ){ int idx; //如果上一轮发生过交换 if( bExchanged ){ //找出ResArr中最小的元素 int j; for( idx = 0, j = 1; j < RES_ARR_SIZE; ++j ){ if( ResArr[idx] > ResArr[j] ) idx = j; } } //这个后续元素比ResArr中最小的元素大,则替换。 if( BigArr[i] > ResArr[idx] ){ bExchanged = true; ResArr[idx] = BigArr[i]; }else bExchanged = false; }}
性能分析: 最坏的时间复杂度为O((M-N)*N)。咋一看好像比快排的时间复杂度还高。但是注意是最坏的,实际上,并不是每次都需要付出一个最小值O(N)的代价的。因为,如果当前的BigArr[i]<ResArr[idx]的话,就不需要任何操作,则1——N的最小值也就没有变化了。下一次也就不需要付出O(N)的代价去寻找最小值了。当然,如果M基本正序的话,则每次都要交换最小值,每次都要付出一个O(N)代价。最坏的情况比快排还要差。
就平均性能而言,改进的算法还是比快排要好的,其运行时间大约在2.0秒左右。
使劲动下脑子
上面的解决方案2还有一个地方不太好。当BigArr[i]>ResArr[idx]时,则必须交换这两个数,进而每次都需要重新计算一轮N个数的最小值。只改变了一个数就需要全部循环一次N实在是不划算。能不能下一次的最小值查找可以借助上一次的比较结果呢?
基于这样一个想法,我们考虑到了堆排序的优势(每一次调整堆都只需要比较logN的结点数量)。因此我们再做一次改进:
(1) 首先我们把前N个数建立成小顶堆,则根结点rootIdx。
(2) 当BigArr[i]>ResArr[rootIdx]时,则交换这两个数,并重新调整堆,使得根结点最小。
性能分析:显然,除了第一次建堆需要O(N)时间的复杂度外,每一次调整堆都只需要O(logN)的时间复杂度。因此最坏情况下的时间复杂度为O((M-N)*logN),这样即使在最坏情况下也比快排的O(M*logM)要好的多了。
另外:实际上也可以使用二分查找的思想,第一次找N中的最小值的时候将N排序。以后每次替换最小值,都使用二分查找在logN代价下找到当前N的最小值即可。与使用堆的过程如出一辙
- 腾讯-1亿个数据取前1万大的整数-题解答
- 1亿个数据取前1万大的整数
- 【腾讯】1亿个数据取前1万大的整数
- 【腾讯】1亿个数据取前1万大的整数
- 大数据:随机生成10万个整数找出出现次数前一百的数
- 2010/6/25 (10亿个数取前1万个)
- 1亿数据取前1w个数据不超过4秒的java 程序
- 1亿数据取前1w个数据不超过4秒的java 程序
- 面试题-100万个数据前100大的数据
- 也论从1亿个整数中找出最大的1万个(上)
- 也论从1亿个整数中找出最大的1万个(下)
- 10个数取1万个最大的
- 求前k个大的数据
- 从大量整数中选取最小/大的若干个
- 从大量整数中选取最小/大的若干个
- 经典笔试题:从十亿个整数中选择前100大整数的算法实现
- n个数里找出前m个数(或者 从10亿个浮点数中找出最大的1万个)
- 大整数的加减乘除取模
- javascript的Prototype属性 、解释及常用方法
- Pro Android学习笔记(一一七):Location(3):获取位置更新
- TOmcat启动后报:java.io.EOFException错误
- Linux 查看监听端口的方法
- Color the ball——树状数组
- 1亿个数据取前1万大的整数
- 堆排序
- CSS水平居中和垂直居中的各种方法
- 美国最受欢迎的25个App都是哪些?
- 介绍 JSON
- 【Nutch2.2.1源代码分析之5】索引的基本流程
- 解决:Bitmap too large to be uploaded into a texture exception
- Highstock图表插件的一个详细的Demo,日期什么全部中文
- 2405_Specialized Four-Digit Numbers(进制)