`
大胖墩子儿
  • 浏览: 2029 次
  • 性别: Icon_minigender_1
  • 来自: 长春
社区版块
存档分类
最新评论

从一亿个数中找出最大的一万个数

阅读更多

问题定义:

        从一亿个数中找出最大的一万个数

不假思索:

        拿到这道题,马上就会想到的方法是建立一个数组把1亿个数装起来,然后用for循环遍历这个数组,找出最大的1万个数来。原因很简单,如果要找最大的那个数,就是这样解决的;而找最大的一万个数,只是重复一万遍。这个解法类似于选择排序,一次将一个正确解放在合适的位置,重复一万次,所以时间复杂度为O(n *m),如果你愿意去实现一下,会发现不等个几十分钟是不会出结果的。

稍做思考:

        上面的解决方案类似于一个选择排序,而我们知道,所有排序算法中选择排序是比较慢的,所以我们选择快速排序,将整个数组都排好续,然后取前一万个数就是我们想要的结果,solution1就是采用这种方法,将时间减少到只要几秒,可见快速排序真的很快。

深入思考:

        上面的方法已经有一个不错的效率了,但是,这里我们做了很多无用功,题目只要求我们将前一万个最大的数找到,我们却排序了整个数组,稍微相一下就知道还有很大的优化空间。方法二是解设前一万个数是我们需要找的一万个数,但是假设不一定成立,那么,我们只需要讲后续元素与前一万个数中的最小元素比较,如果最小元素比后续元素小,则交换数据,这样只需要遍历一遍大数组就能得到正确解。时间复杂度为O(n).solution2就是采用这种方法

深思熟虑:

        solution3的基本思路和solution2是一样的,不过做了两点优化。在solution2中,我们需要不断的找出前一万个数中最小的元素,是否可以进行优化呢?答案是肯定的,优化的方法就是维持前一万个数基本有序,则每次只需要查找一个很小的范围,就能找到前一万个数中最小的元素。还有点优化就是,前一万个数无序的时候,查找时间就变长了,就退化成solution2了,所以再交换600次数据以后,再对前一万个数进行排序,这样能提高查找最小元素的时间。

不断否定自己的方法:

        solution4测试了使用mutilset来保存前一万个数的情况,我们知道mutilset采用的是红黑树,且容器中的元素是有序的,正好符合我们的需求,实际测试发现,先率没有solution3快。

 

 

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <string.h>  
  4. #include <set>  
  5. #include <algorithm>  
  6. #include <iostream>  
  7. #include <sys/times.h>  
  8. #include <unistd.h>  
  9. #define DEBUG  
  10. using namespace std;  
  11.   
  12. multiset<int> s;  
  13. const int BIG_ARR_SIZE = 100000000;  
  14. const int RESULT_ARR_SIZE = 10000;  
  15. bool compre( int a, int b)  
  16. {  
  17.         return a > b;  
  18. }  
  19.   
  20. void solution1( int *buff)  
  21. {  
  22.         sort( buff, buff + BIG_ARR_SIZE, compre);  
  23. }  
  24.   
  25. void swap( int *buff, int i, int j)  
  26. {  
  27.         int temp = buff[i];  
  28.         buff[i] = buff[j];  
  29.         buff[j] = temp;  
  30. }  
  31. void solution2( int *buff)  
  32. {  
  33.         bool bExchanged = true;  
  34.         int i, idx, j;  
  35.   
  36.         for( i = RESULT_ARR_SIZE; i < BIG_ARR_SIZE; i++)  
  37.         {  
  38.                 if( bExchanged )  
  39.                 {  
  40.                         //找出前一万个数中最小的  
  41.                         for( idx = 0, j = 1; j < RESULT_ARR_SIZE; j++)  
  42.                         {  
  43.                                 if( buff[idx] > buff[j])  
  44.                                         idx = j;  
  45.                         }  
  46.                 }  
  47.                 //在后续元素比前一万个元素最小元素大,则替换  
  48.                 if( buff[i] > buff[idx])  
  49.                 {  
  50.                         swap( buff, i, idx);  
  51.                         bExchanged = true;  
  52.                 }  
  53.                 else  
  54.                 {  
  55.                         bExchanged = false;  
  56.                 }  
  57.         }  
  58. }  
  59.   
  60. void solution3( int *buff)  
  61. {  
  62.         sort(buff, buff+RESULT_ARR_SIZE, compre);  
  63.         int minElemIdx = RESULT_ARR_SIZE -1;  
  64.         int zoneBeginIdx = minElemIdx;  
  65.         forint i = RESULT_ARR_SIZE; i < BIG_ARR_SIZE; i++)  
  66.         {  
  67.                 if( buff[i] > buff[minElemIdx] )  
  68.                 {  
  69.                         swap(buff, i, minElemIdx);  
  70.                         if( minElemIdx == zoneBeginIdx )  
  71.                         {  
  72.                                 zoneBeginIdx--;  
  73.                                 if( zoneBeginIdx < RESULT_ARR_SIZE - 600 )  
  74.                                 {  
  75.                                         sort( buff, buff + RESULT_ARR_SIZE, compre);  
  76.                                         zoneBeginIdx = minElemIdx = RESULT_ARR_SIZE - 1;  
  77.                                 }  
  78.                                 continue;  
  79.                         }  
  80.   
  81.                         int idx = zoneBeginIdx;  
  82.                         int j = idx + 1;  
  83.                         //查找最小元素      
  84.                         for(; j < RESULT_ARR_SIZE; j++)  
  85.                         {  
  86.                                 if( buff[idx] > buff[j])  
  87.                                         idx = j;  
  88.                         }  
  89.                         minElemIdx = idx;  
  90.                 }  
  91.         }  
  92. }  
  93.   
  94.   
  95. void solution4(int *buff)  
  96. {  
  97.         int i;  
  98.         for( i = 0; i < RESULT_ARR_SIZE; i++)  
  99.         {  
  100.                 s.insert( buff[i]);  
  101.         }  
  102.   
  103.         for(i = RESULT_ARR_SIZE; i < BIG_ARR_SIZE; i++)  
  104.         {  
  105.                 if( buff[i] > *s.begin() )  
  106.                 {  
  107.                         s.insert(buff[i]);  
  108.                         s.erase( s.begin());      
  109.                 }  
  110.         }  
  111. }  
  112.   
  113. int main(int argc, char* argv[])  
  114. {  
  115.   
  116.         //生成1亿个整数  
  117.         int deno = BIG_ARR_SIZE * 10;  
  118.         int i;  
  119.         int *buff;  
  120.         int *backup;  
  121.         struct tms begTime, endTime;  
  122.         int result[RESULT_ARR_SIZE];  
  123.         long beg,end;  
  124.         buff = new int[BIG_ARR_SIZE];  
  125.         backup = new int[BIG_ARR_SIZE];  
  126.   
  127.         int clocks_per_sec = sysconf( _SC_CLK_TCK);  
  128.         srand(time(0));  
  129.         for( i = 0; i < BIG_ARR_SIZE; i++ )  
  130.         {  
  131.                 buff[i] = rand() % deno;  
  132.         }  
  133.   
  134.         //将原始数据备份,其他解决方案使用同样的数据,才有可比性  
  135.         memcpy(backup, buff, sizeof(int) * BIG_ARR_SIZE);  
  136.   
  137. #ifdef DEBUG  
  138.         beg = times(&begTime);   
  139.         solution1(buff);  
  140.         end = times(&endTime);   
  141.         cout << "1.Use sort algorithm in STL: " << (end - beg) * 1000 / clocks_per_sec << " ms" << endl;  
  142.         for( i = 0; i <9; i++)  
  143.         {  
  144.                 cout<< buff[i] << "\t";  
  145.         }  
  146.         cout << endl;  
  147. #endif  
  148.   
  149.         memcpy( buff, backup, sizeof(int) * BIG_ARR_SIZE);  
  150.         beg = times(&begTime);   
  151.         solution2(buff);  
  152.         end = times(&endTime);   
  153.         cout << "2.Assume the first 10000 numbers is larger then the later number: " << (end - beg) * 1000 / clocks_per_sec  << " ms" << endl;  
  154. #ifdef DEBUG  
  155.         sort( buff, buff + RESULT_ARR_SIZE, compre);  
  156.         for( i = 0; i <9; i++)  
  157.         {  
  158.                 cout<< buff[i] << "\t";  
  159.         }  
  160.         cout << endl;  
  161.   
  162. #endif  
  163.         memcpy( buff, backup, sizeof(int) * BIG_ARR_SIZE);  
  164.         beg = times(&begTime);   
  165.         solution3(buff);  
  166.         end = times(&endTime);   
  167.         cout << "3.Assume the first 10000 numbers is larger then the later number(with optimization): " << (end - beg) * 1000 / clocks_per_sec  << " ms" << endl;  
  168.   
  169. #ifdef DEBUG  
  170.         sort( buff, buff + RESULT_ARR_SIZE, compre);  
  171.         for( i = 0; i <9; i++)  
  172.         {  
  173.                 cout<< buff[i] << "\t";  
  174.         }  
  175.         cout << endl;  
  176. #endif  
  177.         memcpy( buff, backup, sizeof(int) * BIG_ARR_SIZE);  
  178.         beg = times(&begTime);   
  179.         solution4(buff);  
  180.         end = times(&endTime);   
  181.         cout << "4.Assume the first 10000 numbers is larger then the later number(with multiset): " << (end - beg) * 1000 / clocks_per_sec  << " ms" << endl;  
  182.   
  183.         return 0;  
  184. }  

 

测试结果:

 

结论:

        经过层层优化,这个难题只需要半秒时间就解决了,可见算法好坏对于程序效率的影响是巨大的。

参考资料:

        赖永浩 . 算法优化 . 某某杂志期刊.51--54.

分享到:
评论

相关推荐

    从一亿个数中找出最大的100个 或者n个

    从一亿个数中找出最大的100个 或者n个 用了个堆

    从一亿个数里找出最大的一万个数

    本文探讨了从一亿个数中找出最大的一万个数的问题,并介绍了六种不同的解决方法。从最简单的遍历方法到利用优先队列进行优化,我们逐步提高了算法的效率。通过对比不同方法的时间复杂度,我们可以看到,通过适当的...

    面试之大数找关键值(如从10亿个浮点数中找出最大的1万个)

    "面试之大数找关键值(如从10亿个浮点数中找出最大的1万个)" 本文讨论了一道常见的笔试面试题目:从10亿个浮点数中找出最大的1万个。这个问题看似简单,但实际上却具有很高的难度,因为处理如此大量的数据需要考虑...

    1.5 数的产生、十进制计数法及亿以上数的读写.docx

    而最接近100亿的数,需要将99亿9千万这个数与给定的数字进行比较,找出最接近的组合,即8765300000。 综上所述,理解和掌握数的产生、十进制计数法以及亿以上数的读写,是学习数学和计算机科学的基础,它不仅帮助...

    青岛版四年级上册数学第一单元测试卷(大数知多少——万以上数的认识).docx

    3. **数的组成与换算**:一万是10个一千,100个一百万是1亿,这体现了计数单位之间的进率关系。 4. **数的位数**:最高位是千万位的数是八位数,一个七位数的最高位是百万位。 5. **数的写法与近似数**:一个数的...

    13亿以内数的大小比较.pptx

    5. **实践应用**:课件提供了多组数让学生进行比较,训练他们的比较能力,如586000和5860000,74520000和95275695,6000859和6000849等,要求学生找出每个组中最大的数。此外,还有一项排序练习,让学生将一组人口...

    万以内数的大小比较.doc

    《万以内数的大小比较》是数学教育中的一个重要主题,主要针对小学阶段的学生,旨在帮助他们掌握比较万以内数大小的基本方法。以下是该主题的知识点详解: 1. 数位概念:在万以内数的比较中,数位的概念至关重要。...

    新北师版四上数学第1单元《认识更大的数》试卷A.pdf

    - 三千万,六千万,九千万,一亿二千万,一亿五千万,一亿八千万。 15. 四舍五入的应用: - 六位数,四舍五入精确到万位约是50万,这个六位数最大是504999,最小是495000。 综上所述,这些知识点涵盖了数位的...

    新西师大版四年级上册数学 第2课时 万以上数的写法及比较大小 教学课件.pptx

    其次,如果两个数位数相同,那么需要从最高位开始,逐一比较各个位的数值,直至找出不同之处。 在这一过程中,教师应当引导学生注意数位之间的关系和比较的策略。比如,在比较两个五位数时,如果千位上的数字不同,...

    四年级上册数学认识更大的数PPT学习教案.pptx

    例如,10个一万等于十万,10个十万等于一百万,依此类推。 4. **读数技巧**:读数时应从高位读起,遵循“读数要从高位起,哪位是几就读几”的规则。如果某位是零,通常不读,除非是连续的零,这时只读一个零。如果...

    小四数学第7讲:数表(教师版).docx

    通过观察分数数列中每个分数与前一个分数之间的关系,我们能够确定数列的规则,并进而找出第10个数。例如数列是1/2, 1/3, 2/5, 3/8...,教师需要引导学生发现分子和分母的增加模式,以找到解决问题的关键。 例4...

    易语言大写测试源码,易语言数值到中文数字模块代码及测试

    例如,数字“1234567890”应该被转换成“一亿二千三百四十五万六千七百八十”。在实现这个功能时,开发者可能使用了循环、条件判断以及字符串操作等编程技术。模块可能会包含一系列的函数或过程,如将个位、十位、...

    南城一小六年级数学总复习检测试卷精选.doc

    5. 组合数字:利用给定的数字组合出最大和最小的数,要组成最大的数,需将数字按从大到小排列;反之,组成最小的数,则按从小到大的顺序排列。如3、7、1、5、0、8组成的最大六位数是875310,最小五位数是10357。 6....

    人教版数学四年级上册第一单元测试卷及答案.pdf

    10. 数字的最大最小值:对于特定条件下组成的数(如七位数中各个数位上数字和为36的数),学生需要找出符合条件的最大数和最小数,这不仅需要对数的性质有深刻理解,还要能进行有效的逻辑推理。 这些知识点的掌握...

    百度、google海量数据搜索算法题解

    方法2是采用分块策略,比如每100万个数作为一个块,分别找出每个块的最大1万个数,最后再处理剩余的数据找出最大的1万个数。在寻找每个块中第k大的数时,可以利用快速排序的变种,例如“堆排序”或“快速选择”,...

    四年级下册数学苏教版周测培优卷2(含答案).pdf

    试卷还包含了对数字错误书写情况进行调整的练习,即如何从错误的数字中找出正确的数字。 知识点包括: - 数字书写中位值的错位和校正。 - 数字书写中多余的数字移除和正确的数字写入。 通过这些知识点的学习和练习...

    2021年小升初数学专项复习训练一数与代数数的认识2含解析202107051137

    3. 第三题中,要找出能被2整除的四位数,即□必须是0或2,共有5种可能。 4. 第四题保留三位小数,即看小数点后第四位,如果大于等于5则进1,所以是3.879。 5. 最简分数是指分子和分母没有共同因子的分数,选项B和C都...

    四年级上大数的认识练习题(超经典);.doc

    11. **数的性质**:例如一个四位数,个位数字与百位数字的和为12,十位数字与千位数字的和为9,若个位上和百位上的数字互换,千位上与十位上的数字互换,新数比原数增加2376,通过分析可以找出原数。但此问题的具体...

    2020部编版四年级数学上册第一单元考试题附答案.pdf

    9. **判断题**:涉及到了亿位的概念(1亿包含10个千万或100个百万)、比较数的大小(看最高位不全面)、数位的值(770000中两个7的差值)、多位数的读法(0的读法)以及近似数的估算。 10. **读写题**:要求学生能...

    人教版四年级数学上知识点归纳.doc

    - 当给定一个数的近似值时,可以找出最大的可能值和最小的可能值。 - 如五位数四舍五入后是5万,最大数考虑“四舍”(54999),最小数考虑“五入”(45000)。 这些知识点是四年级数学学习的基础,理解和掌握它们...

Global site tag (gtag.js) - Google Analytics