1亿个整数求top 10000
来源:互联网 发布:座机电话录音软件 编辑:程序博客网 时间:2024/06/06 08:43
参考资料:
http://bbs.csdn.net/topics/250038051
【1】遍历数组,求出最大值,与arr[0]元素交换,再在arr[1]到arr[100000000-1]之间求最大值,与arr[1]交换。。类似选择排序。
#include <iostream>#include <fstream>#include <iterator>#include <sys/time.h>#include <stdlib.h>using namespace std;const int N=100000000; // 1亿const int M=10000; // top 1万const int x=0x40000000-1;int arr[N];int main(){ // 生成随机数 int i=0; for(i=0; i<N;i++) arr[i]=rand() & x; struct timeval starttime,endtime; gettimeofday(&starttime,0); // 选择排序。记录各个最大值 for(i=0;i<M; i++) { int j; int m=i; for(j=i+1; j<N; j++) { if(arr[j]>arr[m]) m=j; } if(i!=m) { int t=arr[i]; arr[i]=arr[m]; arr[m]=t; } } gettimeofday(&endtime,0); double timeuse = 1000000*(endtime.tv_sec - starttime.tv_sec) + endtime.tv_usec - starttime.tv_usec; timeuse /=1000; cout<<timeuse<<" ms"<<endl; cout<<"0-10"<<endl; copy(arr,arr+5, ostream_iterator<int>(cout, " ") ); cout<<"9990-10000"<<endl; copy(arr+9990,arr+10000, ostream_iterator<int>(cout, " ") ); return 0; }
运行结果:
chen@chen-book1:~$ time ./count_0-634229 ms0-101073741822 1073741791 1073741788 1073741787 1073741783 9990-100001073634978 1073634973 1073634956 1073634953 1073634935 1073634926 1073634918 1073634907 1073634906 1073634904 real61m3.238suser60m57.797ssys0m0.580schen@chen-book1:~$一个小时。。等不住了吃完饭回来才跑完。
【2】对这1万个数排序,遍历剩下的数字,如果比一万个数字中的最小值大,那么将其插入到合适位置。
#include <iostream>#include <fstream>#include <iterator>#include <sys/time.h>#include <string.h>#include <algorithm>using namespace std;const int N=100000000;const int M=10000;const int x=0x40000000-1;int arr[N];inline void swap(int &a, int &b){ int t=a; a=b; b=t;}int main(){ int i=0; for(i=0; i<N;i++) arr[i]=rand() & x; struct timeval starttime,endtime; gettimeofday(&starttime,0); // sort(arr, arr+M); for(i=M; i<N; i++) { if(arr[0] < arr[i]) swap(arr[0], arr[i]); else continue; // dirty // 1优化 if(arr[0] > arr[M-1] ) //优化 { int t=arr[0]; memmove(arr, arr+1, sizeof(int)*(M-1) ); arr[M-1] = t; }else { int j; for(j=1; arr[0]>arr[j]; j++); if(j==1) continue; int t=arr[0]; memmove(arr, arr+1, sizeof(int)* (j-1) ); arr[j-1]=t; } /* 2 去掉优化 { int j; for(j=1; j<M && arr[0]>arr[j]; j++); if(j==1) continue; int t=arr[0]; memmove(arr, arr+1, sizeof(int)* (j-1) ); arr[j-1]=t; }*/ // /* 3 二分查找 int *p=lower_bound(arr+1, arr+M, arr[0]); if(p!=arr) { int t=arr[0]; memcpy(arr,arr+1,sizeof(int) * (p-arr-1) ); *(p-1)=t; }*/ } // gettimeofday(&endtime,0); if(endtime.tv_usec<starttime.tv_usec) { endtime.tv_sec--; endtime.tv_usec+=1000000; } cout<<(endtime.tv_sec-starttime.tv_sec)<<" s, "<<(endtime.tv_usec-starttime.tv_usec)<<" us"<<endl; cout<<"0-10"<<endl; copy(arr,arr+10, ostream_iterator<int>(cout, " ") ); cout<<endl; cout<<"90-100"<<endl; copy(arr+90,arr+100, ostream_iterator<int>(cout, " ") ); return 0; }
运行
chen@chen-book1:~$ time ./count_22 s, 106089 us0-101073634904 1073634906 1073634907 1073634918 1073634926 1073634935 1073634953 1073634956 1073634973 1073634978 90-1001073635879 1073635888 1073635895 1073635899 1073635902 1073635906 1073635909 1073635918 1073635937 1073635945 real 0m4.605suser 0m4.212ssys 0m0.352s
运算时间居然已经到了2.1ms!总时间4.6s,主要花在了生成随机数上。这里有个优化但是没有发挥作用,去掉优化:
chen@chen-book1:~$ time ./count_22 s, 40210 us
二分:
chen@chen-book1:~$ time ./count_20 s, 578971 us0-101073634904 1073634906 1073634907 1073634918 1073634926 1073634935 1073634953 1073634956 1073634973 107363497890-1001073635879 1073635888 1073635895 1073635899 1073635902 1073635906 1073635909 1073635918 1073635937 1073635945real 0m3.285suser 0m2.864ssys 0m0.388s
优化:2.4s
去掉优化:2.1s
二分查找:579ms
记得当M=100时,二分的效果还比前两者要差,M=10000的时候就已经是前者的1/4了!半秒中有木有!!
PS:N=4亿时:
优化: 3.5s
去掉优化:3.3s
二分查找:1.85s
【3】堆排序。
建立一个小根堆,然后后面的依次跟堆顶比,如果比堆顶大,那么就跟堆顶换,然后调整堆。
#include <iostream>#include <fstream>#include <iterator>#include <sys/time.h>#include <string.h>#include <algorithm>using namespace std;const int N=100000000;const int M=10000;const int x=0x40000000-1;int arr[N];inline void swap(int &a, int &b){ int t=a; a=b; b=t;}struct cmp{ bool operator()(int &a, int &b){return a>=b;}};int main(){ int i=0; for(i=0; i<N;i++) arr[i]=rand() & x; struct timeval starttime,endtime; gettimeofday(&starttime,0); make_heap(arr, arr+M, cmp()); for(i=M; i<N; i++) { if(arr[i]>arr[0]) swap(arr[i],arr[0]); __adjust_heap(arr,0,M,arr[0],cmp()); } gettimeofday(&endtime,0); cout<<(endtime.tv_sec-starttime.tv_sec)<<" s, "<<(endtime.tv_usec-starttime.tv_usec)<<" us"<<endl; cout<<"0-10"<<endl; copy(arr,arr+10, ostream_iterator<int>(cout, " ") ); cout<<endl; cout<<"90-100"<<endl; copy(arr+90,arr+100, ostream_iterator<int>(cout, " ") );/*int a[10]={3,36,12,13,6,78,34,2,5,7};copy(a,a+10, ostream_iterator<int>(cout, " ") );cout<<endl;make_heap(a,a+5, cmp());copy(a,a+10, ostream_iterator<int>(cout, " ") );cout<<endl;for(i=5;i<10;i++){ if(a[i]>a[0]) swap(a[i],a[0]); __adjust_heap(a,0,5,a[0],cmp());}copy(a,a+10, ostream_iterator<int>(cout, " ") );cout<<endl;*/ return 0; }
运行:
chen@chen-book1:~$ time ./count_234 s, -60310 us
34s!我最爱的堆排序,怎么会这么慢。。。
PS:程序貌似有问题
【4】当然,还有直接对整个数组排序,然后取前1万个。。。排序用快排
#include <iostream>#include <fstream>#include <iterator>#include <sys/time.h>#include <string.h>#include <algorithm>using namespace std;const int N=100000000;const int M=10000;const int x=0x40000000-1;int arr[N];inline void swap(int &a, int &b){ int t=a; a=b; b=t;}struct cmp{ bool operator()(const int &a, const int &b){return a>=b;}};int main(){ int i=0; for(i=0; i<N;i++) arr[i]=rand() & x; struct timeval starttime,endtime; gettimeofday(&starttime,0); // sort(arr, arr+N, cmp() ); // gettimeofday(&endtime,0); cout<<(endtime.tv_sec-starttime.tv_sec)<<" s, "<<(endtime.tv_usec-starttime.tv_usec)<<" us"<<endl; cout<<"0-10"<<endl; copy(arr,arr+10, ostream_iterator<int>(cout, " ") ); cout<<endl; cout<<"90-100"<<endl; copy(arr+90,arr+100, ostream_iterator<int>(cout, " ") ); return 0; }运行:
chen@chen-book1:~$ time ./count_244 s, 747807 us0-101073741822 1073741791 1073741788 1073741787 1073741783 1073741782 1073741777 1073741771 1073741756 1073741754 90-1001073740859 1073740858 1073740844 1073740841 1073740837 1073740832 1073740826 1073740826 1073740811 1073740789 real0m47.247suser0m46.807ssys0m0.340s
先快排再取前10000,用时44s。要是换成堆排序呢?把sort改成sort_heap,运行:
chen@chen-book1:~$ time ./count_2
67 s, -486231 us
0-10
1073741822 1073741791 1073741788 1073741787 1073741783 1073741782 1073741777 1073741771 1073741756 1073741754
90-100
1073740859 1073740858 1073740844 1073740841 1073740837 1073740832 1073740826 1073740826 1073740811 1073740789
real 1m9.013s
user 1m8.540s
sys 0m0.340s
用了67s。快排的确是N logN排序算法里最快的。
【5】部分排序。STL里有,基于堆排序的,看看效果如何!
#include <iostream>#include <fstream>#include <iterator>#include <sys/time.h>#include <string.h>#include <algorithm>using namespace std;const int N=100000000;const int M=10000;const int x=0x40000000-1;int arr[N];inline void swap(int &a, int &b){ int t=a; a=b; b=t;}struct cmp{ bool operator()(const int &a, const int &b){return a>=b;}};int main(){ int i=0; for(i=0; i<N;i++) arr[i]=rand() & x; struct timeval starttime,endtime; gettimeofday(&starttime,0); // partial_sort(arr, arr+M, arr+N, cmp() ); // gettimeofday(&endtime,0); if(endtime.tv_usec<starttime.tv_usec) { endtime.tv_sec--; endtime.tv_usec+=1000000; } cout<<(endtime.tv_sec-starttime.tv_sec)<<" s, "<<(endtime.tv_usec-starttime.tv_usec)<<" us"<<endl; cout<<"0-10"<<endl; copy(arr,arr+10, ostream_iterator<int>(cout, " ") ); cout<<endl; cout<<"90-100"<<endl; copy(arr+90,arr+100, ostream_iterator<int>(cout, " ") ); return 0; }
运行:
chen@chen-book1:~$ time ./count_2
0 s, 729513 us
0-10
1073741822 1073741791 1073741788 1073741787 1073741783 1073741782 1073741777 1073741771 1073741756 1073741754
90-100
1073740859 1073740858 1073740844 1073740841 1073740837 1073740832 1073740826 1073740826 1073740811 1073740789
real 0m3.282s
user 0m2.896s
sys 0m0.312s
用了730ms,很不错了!可是为什么我自己用堆排序来模拟,就要那么久呢!!
PS:当N为4亿时,时间为2.65s。
【6】类似计数排序。按比特位,先申请32长度的数组,第一个表示元素表示最高比特位为第0比特的元素个数,第31个元素表示最高比特位为31的元素个数。
遍历数组,得到了直方图。然后从后向前算,就可以知道,最高比特位为多少的整数,是肯定在top10000里的,例如,算得最高比特位为20的整数,肯定在top 10000里,
而最高比特位为19的整数,则有一部分是,有一部分不是。于是,再遍历一遍,将最高比特位为20的放在整个数组开头,再将最高比特位为19的紧随其后,再对最高比特位为19的这部分做部分排序即可!
#include <iostream>#include <fstream>#include <iterator>#include <sys/time.h>#include <string.h>#include <algorithm>using namespace std;const int N=100000000;const int M=10000;const int x=0x40000000-1;int arr[N];inline void swap(int &a, int &b){ int t=a; a=b; b=t;}struct cmp{ bool operator()(const int &a, const int &b){return a>=b;}};int hbit(int x){ int i=0; while(x>>=1)i++; return i;}int main(){ int i=0; for(i=0; i<N;i++) arr[i]=rand() & x; int bits[32]={0}; struct timeval starttime,endtime; gettimeofday(&starttime,0); // for(i=0; i<N; i++) { bits[ hbit(arr[i]) ]++; } int s=0; for(i=32-1; i>=0; i--) { s+=bits[i]; if(s>M)break; } int s0=s; s-=bits[i]; int threshold= (1<<(i+1) ); i=0; while(arr[i]>=threshold) ++i; int j=i+1; for(; j<N; j++) { if(arr[j]>=threshold) { swap(arr[i], arr[j]); ++i; } } threshold>>=1; if(s<M) { while(arr[i]>=threshold) ++i; j=i+1; for(; j<N; j++) { if(arr[j]>=threshold) { swap(arr[i], arr[j]); ++i; } } partial_sort(arr+s, arr+M, arr+s0, cmp()); } // gettimeofday(&endtime,0); if(endtime.tv_usec<starttime.tv_usec) { endtime.tv_sec--; endtime.tv_usec+=1000000; } cout<<(endtime.tv_sec-starttime.tv_sec)<<" s, "<<(endtime.tv_usec-starttime.tv_usec)<<" us"<<endl; cout<<"0-10"<<endl; copy(arr,arr+10, ostream_iterator<int>(cout, " ") ); cout<<endl; cout<<"90-100"<<endl; copy(arr+90,arr+100, ostream_iterator<int>(cout, " ") ); return 0; }
运行:
chen@chen-book1:~$ time ./count_2
13 s, 863604 us
0-10
1073741822 1073741791 1073741788 1073741787 1073741783 1073741782 1073741777 1073741771 1073741756 1073741754
90-100
1073740859 1073740858 1073740844 1073740841 1073740837 1073740832 1073740826 1073740826 1073740811 1073740789
real 0m16.352s
user 0m15.865s
sys 0m0.420s
13秒。怎么会这么久。。可能是移动的地方太多了。。
PS:N=4亿时,时间为55s。
【7】nth_element(arr,arr+M,arr+N, greater<int>() );
耗时:2.9s。
综上,第一名:对1万个小数组维持排序;
第二名:partial_sort based on heap
- 1亿个整数求top 10000
- 40亿个整数,求上中位数
- 求20个整数之和
- 海量数据处理之求1亿个整数中的最大的k个数
- 求整数的二进制表达中有多少个1
- 求整数转二进制中存在多少个1
- 输入一个整数,求该整数的二进制表达中有多少个1
- 输入一个整数,求该整数的二进制表示中有多少个1
- 输入一个整数,求该整数的二进制表达中有多少个1
- 求4个整数中的最大值
- 求海量个无序整数的中位数
- 求若干个整数的平均数
- 求10 个整数中最大值
- 求10个整数中的最大值
- 求10 个整数中最大值
- 求2个整数的正差值
- 求10 个整数中最大值。
- 求10 个整数中最大值
- 博弈 题集
- 设计模式(一):里氏代换原则
- android异步加载图片并缓存到本地实现方法
- 14-斐波那契(算法)
- WinDbg调试器
- 1亿个整数求top 10000
- android上的一个网络接口和图片缓存框架enif简析
- JAVA学习之:类与类之间的关系
- 理解not exists()——执行过程
- Zend Framework 数据库(Db)操作总结
- 一套网络配置随时随地上网
- EAP协议和EAPoL协议
- Gesture Recognizers与触摸事件分发
- 高级Bash脚本编程指南(26):文本处理命令(二)