求N个数中最大的K个数的几种方法与实现
来源:互联网 发布:stc52单片机控制浇花 编辑:程序博客网 时间:2024/04/29 00:18
直接贴代码吧,废话少讲(先说方法吧)~~~~解释在注释里:)
const static long N = 10000000;
const static long K = 100;
static long cnt;
struct Elem
{
Elem()
{
weight = rand()%100000;
}
long weight;
//char data[512];
};
void main()
{
srand(time(NULL));
//直接用数据会越过程序初始栈大小,所在要在堆里申请空间~~~运行时可以断一下点,看一下任务管理器占用多少内存
Elem * p = new Elem[N];
long take = GetTickCount();
//time_t first, second;
//first = time(NULL); /* Gets system */
//方法一
//先将最大的k个交换到前面,再对其全排
DirectSearch( p, K );
QuickSort( p, 0, K - 1 );
PrintElem( p, K );
//方法二
//先用半快排,求出长度为k的区间后,再对其全排
// PartQuickSort( p, 0, N - 1, K );
// QuickSort( p, 0, K - 1 );
// PrintElem( p, K );
//方法三
//用一个小根堆保存这k个数, 遍历一次即可,每次与第一个比较, 如果更新了就调整
//HeapK( p, K );
//估计做出以上三种方法的实现,面试官都基本满意啦,一般软件公司的offer也是八九不离十了.
//但是,继续还有方法...
//解法四: 如果加上限制条件(1) 所有数为整数 (2) 所有数的变化范围不大 这样就可以利用记数排序法的思想
//Countsort( p, K )
//second = time(NULL); /* Gets system time again */
cout<<"tick="<< GetTickCount() - take <<endl;
cout<<"count="<< cnt <<endl;
//cout<<"tick="<< difftime(second,first)<<endl;
delete p;
}
下面者是实现~~~
//解法一: 直接查找 O( N*k), 其实当 k < log2(N) 时是可以用的, 因为要完全排序需要 O( n* log2(n) )//但是如果要求k个数排序的话,还要至少加上 k*log2(k)的时间//直接将其交换到前面位置void DirectSearch( Elem * src, int k ){long i =0, j, l,idx;long max;Elem t;for( l=0; l<K; l++ ){max = src[l].weight;for( j=l; j <N; j++){if( max < src[j].weight ){max = src[j].weight;idx = j;}//计数器++cnt;}//交换到前面memcpy( &t, &src[idx], sizeof(Elem) );memcpy( &src[idx], &src[l], sizeof(Elem) );memcpy( &src[l], &t, sizeof(Elem) );}}//解法二: 部分快排//前置声明int PartPartion( Elem * src, int start, int end );//部分快排,实现将前K个最大的放在前端(N个无素无序)//完成后前k个最大数将会放在数组的前k的位置,无序void PartQuickSort( Elem * src, int start , int end, int k ){//按照快排的思想,以第一个为标记元素M,大于M的放交换到左边,小于M放到右边, 当左分区的要少于N时结束//返回上一次分区的大小//---------------//其实上面的想法,会导致分组过大的,如要在10个里找出前5个,当计算到m为3时,但前一个可能为8,//这里就直接全排这个8个元素就会做很我多无用的排序了//优化: //(1) 当找到 m < N 时, 继续在大的分区找出 N - m个//(2)递归进行,真到有m == N 时结束 //(3)算法复杂度为O(N* log2(k) )//if( k == 0 )//return;int m = 0;//m = PartPartion( src, cur , ElemLen - 1 );//if( m <= k )//PartQuickSort( src + m + 1, ElemLen - m -1 , k - m - 1, m + 1);if( start < end ){m = PartPartion( src, start , end );if( m <= k )PartQuickSort( src, m+1 , end, k - m + 1 );elsePartQuickSort( src, start , m - 1, k );}}//部分快排的分解int PartPartion( Elem * src, int start, int end ){Elem t, mid;int i,j;i = start;j = end;mid = src[start];while( i< j ){while( i<j && src[j].weight <= mid.weight )j--;while( i < j && src[i].weight >= mid.weight ) i++;if( i<j){//如果Elem结构里有数组,就不能直接赋值,所以改用memcpy直接复制内存memcpy( &t, &src[i], sizeof(Elem) );memcpy( &src[i], &src[j], sizeof(Elem) );memcpy( &src[j], &t, sizeof(Elem) );}}memcpy( &t, &src[i], sizeof(Elem) );memcpy( &src[i], &src[start], sizeof(Elem) );memcpy( &src[start], &t, sizeof(Elem) );++cnt;return i;}//对前N个元素进行快排void QuickSort( Elem * src, int start , int end ){//完全排序if( start < end ){int m = PartPartion( src, start , end );QuickSort( src, start, m -1 );QuickSort( src, m +1, end );}}//解法三: 将一个K个数据的堆,遍历一次即可,以最小堆形式,这样只要比较第一个元素F, 如果比F大,就替找F,之后调整堆//同样算法复杂度为 O(N* log2(k) ), 而且实现简单//前置声明bool AdjHeap( int * WArray, int i, int len );void MinHeap( int * WArray, int len );void HeapSort( int * WArray, int len );void HeapK( Elem * src, int k ){//所有元素以一个数组表示, 再按堆操作调整//这里只保存weight值int * weight = new int[ k ];memset( weight, 0, k );long i;int idx = 0;//先将前k 个元素的weight加入到堆中for( i=0; i<k; i++ )weight[i] = src[i].weight;//调整为小根堆,方便比较MinHeap( weight, k );//遍历一次即可for( i=k; i<N; i++ ){if( weight[0] < src[k].weight ){//每置换一次堆顶就要重新调整weight[0] = src[k].weight;AdjHeap( weight, 0, k - 1 );}}//最后weight数组为前k个最大的元素,如果要排序输出,那么要做一次堆排序HeapSort( weight, k ); for( i=0; i<K; i++ ) cout<< weight[i] << " "; cout<<endl;delete weight;}void HeapSort( int * WArray, int len ){int i;int t;for( i=0; i<len ; i++ ){t = WArray[0];WArray[0] = WArray[len - i -1];WArray[len - i - 1] = t;//当没有调整时,完成排序AdjHeap( WArray, 0, len - i - 2 );}}bool AdjHeap( int * WArray, int i, int len ){bool change = false;int j,t;for( j =i*2+1; j <= len; j = j*2+1 ){if( j +1 <= len && WArray[j] > WArray[ j +1 ] )j++;if( WArray[j] < WArray[(j-1)/2] ){change = true;t = WArray[(j-1)/2];WArray[(j-1)/2] = WArray[j];WArray[j] = t;}}return change;}void MinHeap( int * WArray, int len ){if( len <= 0 )return;//根据堆的性质: 左孩子为 2i +1 , 右孩为 2i + 2( 因为从0开始计数 )int i;//从最后一个有孩子的结点开始,向前调整len--;for( i = (len-1)/2; i >=0; i-- )AdjHeap( WArray, i, len );}//解法四: 如果加上限制条件(1) 所有数为整数 (2) 所有数的变化范围不大 这样就可以利用记数排序法的思想//遍历一次N, 找出最大值MAX//开一个数组 T[MAX]; //再遍历一次N, 对每个数计数 T[ A[i] ]++; ( 0<= i <= N ) //由于是求前K个最大的数,所以就可以从后面起取void Countsort( Elem * src, int k ){long i,j;int max;int wt;int * kArray = new int[k];long take = GetTickCount(); //遍历一次N, 找出最大值MAXmax = src[0].weight;for( i=0; i<N; i++){wt = src[i].weight;max < wt ? max = wt:max;}//开一个数组 T[MAX]; int * T = new int[ max + 1 ];memset( T, 0, sizeof(int)*(max + 1) );//再遍历一次N, 对每个数计数 T[ A[i] ]++; ( 0<= i <= N ) for( i=0; i<N; i++){wt = src[i].weight;T[ wt ]++;}//由于是求前K个最大的数,所以就可以从后面起取int n = k;int idx = 0;for( i = max; i>0 ; i-- ){//跳过没有的数if( !T[i] )continue;if( T[i] >= n ){//保存结果在另一个数组,以免影响计算时间for( j =0; j<n; j++ ){kArray[idx++] = i;//cout<<i<<" ";}break;}else{//输出这么多个计数for( j =0; j<T[i]; j++ ){kArray[idx++] = i;//cout<<i<<" ";}n -= T[i];}}//输出结果for( j =0; j<n; j++ )cout<<kArray[i]<<" ";cout<<endl;cout<<"tick="<< GetTickCount() - take <<endl;delete T;delete kArray;}//输出void PrintElem( Elem * src, int Len ){for( int i =0; i< Len; i++ )cout<<src[i].weight<<" ";cout<<endl;}
- 求N个数中最大的K个数的几种方法与实现
- 求N个数中最大的K个数的几种方法与实现
- 求N个数中最大的K个数的几种方法与实现
- 求N个数中最大的K个数的几种方法与实现
- 求N个数中最大的K个数的几种方法与实现
- N个数求最大的k个数
- 求n个数中最大的k个数
- 求数组中最大的k个数
- 求数组中最大的K个数
- N个数中找出最大的K个数
- 寻找N个数中最大的K个数整理
- 求n个数中最小的K个数。
- 求n个数中最大k个数之和
- n 个数中最小的 k 个数
- n个数 找到最小的k个数 几种解法 和java实现
- 求组合数: 求n个数(1....n)中k个数的组合
- 寻找第n个数 与前n个数的几种方法
- 找出N个整数中最大的K个数
- linux 下各种解压缩命令
- PHP+memcached使用实例
- Eclispe里面怎么进行文件的比较
- 什么是POP3、SMTP和IMAP?
- 对于中英文的处理,错误码的处理,还有其它处理的代码
- 求N个数中最大的K个数的几种方法与实现
- 软件设计模式
- Linux内存管理(3):内存探测与初始化
- userdb 问答录
- 炫酷ubantu桌面,compiz特效和配置
- JAVA汉子和拼音的转化
- POJ 3259(负权回路)
- 《Effective C++》读书笔记之item31:将文件间的编译依存关系降至最低
- ListView 实现点击侧边A-Z快速查找[中英文排序混排]