查找最小的k个元素
题目:
输入n 个整数,输出其中最小的 k 个。
例如输入 1 , 2 , 3 , 4 , 5 , 6 , 7 ,8 这 8 个数字,则最小的 4 个数字为 1 , 2 , 3 和 4 。
分析:
本题最简单也最容易想到的解决方法就是把输入的n个整数排序了。当然,排序也有好多种方法,是选择排序、插入排序、快速排序还是堆排序?如果是堆排序还要分为是用大根堆还是小根堆?首先,我们当然会选择时间复杂度较低(nlogn)的排序算法了。
再仔细看下题目,题中好像没有要求我们按大小顺序输出其中的最小的k个数!仅仅要求输入这个k个数而已。这就提示我们不必对所有数据进行排序,只需找出这k个最小数而已。是不是选择排序比较合适?只需要O(n*k)就可以找到最小的k个数据。在具体化些,我们只需申请k个大小的数组存储最后的结果,如果数组未填满,我们就直接将输入的元素放入到数组中;如果数组中放满了k个元素,那么我们就需要找到当前数组中最大的元素值与刚输入的整数值比较,如果刚输入的整数值较小,则进行替换,否则继续输入……
查找k个元素数组的最大值时间复杂度为O(k),需要进行n-k次,所以时间复杂度是O(k(n-k)),最后的平均复杂度应该是O(kn)。至于更多的思路当然还有采用具有k个元素的大根堆来实现,具体可以查看July的详细讲解http://blog.csdn.net/v_JULY_v/article/details/6370650。
代码如下:
#include<stdlib.h>
#include<stdio.h>
#define SIZE 10 //k=20
void replace(int datas[],int newdata)
{
int i,pos=-1,max=-(2<<31);
for(i=0;i<SIZE;i++)
{
if(max<datas[i])
{
max=datas[i];
pos=i;
}
}
if(newdata<datas[pos])
datas[pos]=newdata;
}
int main()
{
int datas[SIZE]={0};
int k=0,input;freopen("input.txt","r",stdin);
while(EOF!=scanf("%d",&input))
{
if(k<SIZE)
{
datas[k++]=input;
}
else
replace(datas,input);
}
for(k=0;k<SIZE;k++)
printf("%d ",datas[k]);
printf("\n");getchar();
return 0;
}下面的方法则是采用STL中multiset来实现的。来自于http://zhedahht.blog.163.com/blog/static/2541117420072432136859/:
typedef multiset<int, greater<int> > IntHeap;
///////////////////////////////////////////////////////////////////////
// find k least numbers in a vector
///////////////////////////////////////////////////////////////////////
void FindKLeastNumbers(const vector<int>& data,IntHeap&leastNumbers,unsigned k)
{
leastNumbers.clear();
if(k == 0 || data.size() < k)
return;
vector<int>::const_iterator iter = data.begin();
for(; iter != data.end(); ++ iter)
{
// if less than k numbers was inserted into leastNumbers
if((leastNumbers.size()) < k)
leastNumbers.insert(*iter);
// leastNumbers contains k numbers and it's full now
else
{
// first number in leastNumbers is the greatest one
IntHeap::iterator iterFirst = leastNumbers.begin();
// if is less than the previous greatest number
if(*iter < *(leastNumbers.begin()))
{
// replace the previous greatest number
leastNumbers.erase(iterFirst);
leastNumbers.insert(*iter);
}
}
}
}