题目:
输入n个整数,找出其中最小的k个数。例如输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
最简单的思路:将输入的n个整数排序,排序之后位于最前面的k个数就是最小的k个数。时间复杂度O(nlogn)。
另一种思路:基于快速排序Partition函数。
基于数组的第k个数字来调整,使得比第k个数字小的所有数字都位于数组左边,比第k个数字大的所有数字都位于数组右边。这样调整之后,位于数组中左边的k个数字就是最小的k个数字。
void GetLeastNumbers(int* input,int n,int* output,int k)
{
if(input==NULL||output==NULL||k>n||n<=0||k<=0)
return;
int start=0;
int end=n-1;
//Partiton函数返回比较标准值的下标
int index=Partition(input,n,start,end);
while(index!=k-1)
{
if(index>k-1)
{
end=index-1;
index=Partition(input,n,start,end);
}
else
{
start=index+1;
index=Partition(input,n,start,end);
}
}
for(int i=0;i<k;++i)
output[i]=input[i];
}
另一种适合于处理海量数据的方法:基于数据容器
先创建一个大小为k的数据容器来存储最小的k个数字,接下来我们每次从输入的n个整数中读入一个数。
如果容器内已有数字少于k,则直接把这次读入的整数放入容器;
如果容器中已有k个数字,即容器已满,需要找出已有的k个数中的最大值,然后将待插入的整数与之相较,如果待插入的值比当前已有的最大值小,则用这个数替换当前已有的最大值;否则抛弃。
//multiset是关联容器的一种,是排序好的集合,并且允许有相同的元素
typedef multiset<int,greater<int>> intSet;
typedef multiset<int,greater<int>>::iterator setIterator;
void GetLeastNumbers(const vector<int>& data,intSet& leastNumbers,int k)
{
leastNumbers.clear();
if(k<1 || data.size()<k)
return;
vector<int>::const_iterator iter=data.begin();
for(;iter!=data.end();++iter)
{
if((leastNumbers.size())<k)
leastNumbers.insert(*iter);
else
{
setIterator iterGreatest=leastNumbers.begin();
if(*iter<*(leastNumbers.begin())
{
leastNumbers.erase(iterGreatest);
leastNumbers.insert(*iter);
}
}
}
}