寻找n个数中的最大前K个数,一般可以想到选择排序或者堆排序,这里介绍一种利用快排思想的方法。
快排每一轮是把一组数据分成三部分,小于基准数的数,基准数,大于等于基准数的数。可以想到当大于等于基准数的数量等于K时这一部分就是所求答案。我们可以使用快排降序排序思想,因为快排每次会确定一个基准数的最终位置,每次得到基准数的下标(下标从0开始)后我们将之与k-1比较,当等于时,说明基准数和基准数左边的数是前K大的数(注意这些数并不是降序序列)。当小于时,说明此时基准以及左侧的数不够K个,但可以确定基准数以及基准数左侧的数肯定在这K个数中,所以不必管基准数以及他左侧的数,对右侧的数再进行上述操作,直到得到答案。当大于时,说明基准数和基准数左侧的数多于k个,对左侧的数进行上述操作,直到得到答案。平均时间复杂度比快排快一倍O(nlogn),最坏时间复杂度为O(n^2).
代码
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
void Qs(int low,int high,vector<int>&nums,int k)
{
int i=low,j=high,temp=nums[low];
while(i<j){
while(i<j&&nums[j]<temp){
j--;
}
nums[i]=nums[j];
while(i<j&&nums[i]>=temp){
i++;
}
nums[j]=nums[i];
}
nums[i]=temp;
if(j==k-1){
return ;
}else{
if(j>=k){
Qs(low,j-1,nums,k);
}else{
Qs(i+1,high,nums,k);
}
}
}
int main()
{
int n,k,x;
vector<int>nums;
nums.clear();
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++){
scanf("%d",&x);
nums.push_back(x);
}
Qs(0,n-1,nums,k);
for(int i=0;i<k;i++){
if(i!=0){
printf(" ");
}
printf("%d",nums[i]);
}
return 0;
}