首先是跟快排一样的分区函数
//--------------------分区函数--------------------
int Partition(int a[],int l,int r){
int pivot=a[l]; //取开头元素为枢轴
while(l<r){
while(l<r&&a[r]>=pivot) //如果a[r]大于等于pivot的话r就一直向前走
r--;
a[l]=a[r]; //直到小于pivot就让a[l]等于a[r],然后移动l指针
while(l<r&&a[l]<pivot) //如果a[l]小于pivot的话l就一直向后走
l++;
a[r]=a[l]; //直到大于pivot就让a[l]等于a[r]
}
a[l]=pivot; //循环结束后l的位置就是pivot的位置
return l; //返回pivot的最终位置
}
找第k大元素实现
int Find_kmin(int a[],int l,int r,int k){
if(l<r){
int i=Partition(a,l,r);
if(i==k) //如果分区函数返回的位置刚好是k,因为是升序排序,说明a[i]就是第k小的元素
return a[i];
else if (i<k) //如果分区函数返回的位置小于k,说明第k小的数在a[i]的右边
return Find_kmin(a,i+1,r,k); //舍弃左边,继续搜索右边
else
return Find_kmin(a,l,i-1,k); //否则舍弃右边,继续搜索左边
}
return a[l];//当l=r时还没有返回值的话表示当前只有一个元素,无须再分区,直接返回a[l]
}
如果先对整个序列进行快排然后输出a[k]时间复杂度为O(nlogn)
但是我们只需要找第k小的元素,所以没必要对所有元素进行排序,跟快排不同的是,上述算法每次只需要对左、右分区中的一个进行分区,即n+n/2+n/4+....1,所以时间复杂度为O(n)
同理我们可以写出找第k大元素的代码
int Find_kmax(int a[],int l,int r,int k,int len){ //len是序列长度
if(l<r){
int i=Partition(a,l,r);
if(i==len-k)
return a[i];
else if (i<len-k)
return Find_kmax(a,i+1,r,k);
else
return Find_kmax(a,l,i-1,k);
}
return a[l];
}