几种查找数组的前K个最小值的算法.docx
- 文档编号:30274921
- 上传时间:2023-08-13
- 格式:DOCX
- 页数:11
- 大小:16.89KB
几种查找数组的前K个最小值的算法.docx
《几种查找数组的前K个最小值的算法.docx》由会员分享,可在线阅读,更多相关《几种查找数组的前K个最小值的算法.docx(11页珍藏版)》请在冰豆网上搜索。
几种查找数组的前K个最小值的算法
几种查找数组的前K个最小值的算法
好久没有写博客了,这一段时间主要在准备为将来找工作复习,今天我就总结一下关于如何查找数组的前K个最小值实现方法,查找前K个最小值实现方法很多,主要的思想包括如下的几种:
1、对数组进行排序,然后前K个元素就是需要查找的元素,排序的方法可以采用快速排序,但是我们知道在快速排序中如果已经是有序的数组,采用快速排序的时间复杂度是O(N^2),为了解决这种问题,通常选择随机选择一个数组值pivot作为基准,将数组分为S1=;pivot,这样就能避免快速排序中存在的问题,或者采用随机选择三个元素,然后取中间值作为基准就能避免快速算法的最差时间复杂度,这种方法的前K个数字是有序的。
2、既然是选择前K个对象,那么就没必要对所有的对象进行排序,可以采用快速选择的思想获得前K个对象,比如首先采用快速排序的集合划分方法划分集合:
S1,pivot,S2,然后比较K是否小于S1的个数,如何小于,则直接对S1进行快速排序,如果K的个数超过S1,那么对S2进行快速排序,排序完成之后,取数组的前K个元素就是数组的前K个最小值。
这种实现方法肯定比第一种的全快速排序要更快速。
3、将数组转换为最小堆的情况,根据最小堆的特性,第一个元素肯定就是数组中的最小值,这时候我们可以将元素保存起来,然后将最后一个元素提升到第一个元素,重新构建最小堆,这样进行K次的最小堆创建,就找到了前K个最小值,这是运用了最小堆的特性,实质上是最小堆的删除实现方法。
这种算法的好处是实现了数组的原地排序,并不需要额外的内存空间。
4、接下来的这种思想有点类似桶排序,首先给定一个K个大小的数组b,然后复制数组a中的前K个数到数组b中,将这K个数当成数组a的前K个最小值,对数组b创建最大堆,这时候再次比较数组a中的其他元素,如果其他元素小于数组b的最大值(堆顶),则将堆顶的值进行替换,并重新创建最大堆。
这样遍历一次数组就找到了前K个最小元素。
这种方法运用了额外的内存空间,特别当选择的K值比较大时,这种方法有待于权衡一下。
这种方法对于海量数据来说是有较好的作用,对于海量数据不能全部存放在内存中,这时候创建一个较小的数组空间,然后创建最大堆,从硬盘中读取其他的数据,进而实现前K个数据的查找。
这是比较传统的几种方法,当然还存在其他的选择方式,我在这边就不阐述了,从上面几种方法的可知,查找方法都充分运用了运用了数据结构和算法的特性。
因此数据结构的灵活运用对算法的实现有很多的好处。
下面是我的实现代码,数组中前K个元素我通过打印的方式实现,并没有保存到新的数组中:
#include;
#include;
#include;
#include;
#include;
#defineLEN500000
#defineK100
/*堆的性质*/
#defineLEFTSON(i)(2*(i)+1)
#defineRIGHTSON(i)(2*((i)+1))
#definePARENT(i)(((i)-1)/2)
voidswap(int*a,int*b)
{
assert(a!
=NULL&&b!
=NULL);
if(a!
=b)
{
*a=*a^*b;
*b=*a^*b;
*a=*a^*b;
}
}
intpartition(int*a,intleft,intright)
{
intpivot=a[right];
inti=left;
intj=left-1;
assert(a!
=NULL);
for(i=left;i;k)
quickselect(a,left,i-1,k);
}
}
voidQuickSelect(int*a,intsize,intk)
{
assert(a!
=NULL);
quickselect(a,0,size-1,k);
}
/*最大堆*/
voidmax_heapify(int*a,intleft,intright)
{
inttmp=0;
intchild=left;
intparent=left;
assert(a!
=NULL);
for(tmp=a[parent];LEFTSON(parent);=0;--i)
max_heapify(a,i,size-1);
}
/*最小堆的实现*/
voidmin_heapify(int*a,intleft,intright)
{
intchild=0;
inttmp=0;
intparent=left;
assert(a!
=NULL);
for(tmp=a[parent];LEFTSON(parent);a[child+1])
child++;
if(a[child];=0;--i)
min_heapify(a,i,size-1);
}
/*采用快速排序查找*/
voidfind_Kmin_num_1(int*a,intsize,intk)
{
inti=0;
assert(a!
=NULL);
QuickSort(a,size);
#if0
for(i=0;i printf("%d\t",a[i]); printf("\n"); #endif } /*采用快速选择实现*/ voidfind_Kmin_num_2(int*a,intsize,intk) { inti=0; assert(a! =NULL); QuickSelect(a,size,k); #if0 for(i=0;i printf("%d\t",a[i]); printf("\n"); #endif } /*采用最大堆实现*/ voidfind_Kmin_num_3(int*a,intsize,intk) { inti=0; int*b=malloc(sizeof(int)*k); assert(a! =NULL&&b! =NULL); for(i=0;i b[i]=a[i]; build_maxheap(b,k); for(;i { if(a[i] { b[0]=a[i]; //build_maxheap(b,k); max_heapify(b,0,k-1); } } #if0 for(i=0;i printf("%d\t",b[i]); printf("\n"); #endif } /*采用最小堆删除元素的方式实现*/ voidfind_Kmin_num_4(int*a,intsize,intk) { inti=0; assert(a! =NULL); build_minheap(a,size-1); for(i=0;i { //printf("%d\t",a[0]); /*删除a[0],释放a[size-1-i]*/ a[0]=a[size-1-i]; min_heapify(a,0,size-2-i); } //printf("\n"); } intmain() { inta[LEN]; intb[LEN]; intc[LEN]; intd[LEN]; inti=0,j=0; clock_t_start; doubletimes=0; srand((int)time(NULL)); for(i=0;i { a[i]=rand()%(LEN); b[i]=a[i]; c[i]=a[i]; d[i]=a[i]; //printf("%d\t",a[i]); } //printf("\n"); _start=clock(); find_Kmin_num_1(a,LEN,K); times=(double)(clock()-_start)/CLOCKS_PER_SEC; printf("快速排序的查找需要: %f\n",times); _start=clock(); find_Kmin_num_2(b,LEN,K); times=(double)(clock()-_start)/CLOCKS_PER_SEC; printf("快速选择的查找需要: %f\n",times); _start=clock(); find_Kmin_num_3(c,LEN,K); times=(double)(clock()-_start)/CLOCKS_PER_SEC; printf("最大堆的查找需要: %f\n",times); _start=clock(); find_Kmin_num_4(d,LEN,K); times=(double)(clock()-_start)/CLOCKS_PER_SEC; printf("最小堆的查找需要: %f\n",times); return0; } 检测算法的性能: [gong@Gong-Computerinterview]$gcc-gminKnum.c-ominKnum [gong@Gong-Computerinterview]$./minKnum 快速排序的查找需要: 0.130000 快速选择的查找需要: 0.020000 最大堆的查找需要: 0.000000 最小堆的查找需要: 0.010000 从结果可知,快速排序的算法效果最差,而最大堆的效果最好,最小堆的效果其次,但是最大堆运用了额外的内存空间。 因此在内存空间限制的情况下,考虑最小堆是比较合适的。 但是最大堆的思想确实很精妙的,运用了类似桶排序的性质。 为了说明算法能否实现前K个最小值的查找,改变数组大小为50,并打印各个方法完成的情况,查找前10个数据,实验结果如下所示: [gong@Gong-Computerinterview]$./minKnum 15 38 14 43 31 45 42 1 32 23 43 34 9 4 45 31 25 48 8 42 40 27 36 30 32 4 11 23 47 12 24 14 1 40 8 32 36 0 35 18 26 28 2 35 35 49 17 12 48 27 0 1 1 2 4 4 8 8 9 11 快速排序的查找需要: 0.000000 1 9 4 8 4 11 1 8 0 2 快速选择的查找需要: 0.000000 11 8 9 4 2 1 8 1 4 0 最大堆的查找需要: 0.000000 0 1 1 2 4 4 8 8 9 11 最小堆的查找需要: 0.000000 从上面的实验结果可知,四种方法都是实现了获得前K个最小元素。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 查找 数组 最小值 算法
