问题描述:输入一组数,指定一个k,输出这组数里第k大的数。
一般这种题目,第一想法是把整个数组先排序后,再选取第k位的数。
但是这样做实际上浪费了大量的时间在排序上,我们只是要求第k大的数,并非要把整个数组排序完。
利用快速排序算法的性质:每一趟排序,必有一个元素位于最终的位置,而且于此同时这个元素左边部分的元素都比它小,右边部分的元素都比它大,在这个算法的基础上加以修改:
我们直接将每次选取的元素最终所在位置m与我们想要比较的位置号k相比较。
若m比k大,说明第k大元素必然在m的左方,此时缩小下一趟排序的上界:high=middle-1;
反之(k比m大),说明第k大元素必然在m的右方,此时放大下一趟排序的下界:low=middle+1;
这样就可以在不需要把整个数组元素都排序完的情况下求出第k大的数。
#include<iostream> #include<cstdio> #define maxn 10001 using namespace std; int arr[maxn]; int quicksort(int a[],int low,int high) { int pivot=a[low];//选取最低位置上的元素作为枢纽元素 for(;;) { while(low<high&&pivot<=a[high]) high--; if(low>=high)break; a[low++]=a[high]; while(low<high&&a[low]<=pivot) low++; if(low>=high)break; a[high--]=a[low]; } a[high]=pivot; return high;//返回最后元素所在位置 } int selectk(int a[],int low,int high,int k) { int index; for(;;) { index=quicksort(a,low,high); if(index==k) return a[k]; else if(index<k) low=index+1; else high=index-1; } } int main() { int n,x,ans; while(scanf("%d%d",&n,&x)!=EOF) { for(int i=0;i<n;i++) scanf("%d",&arr[i]); ans=selectk(arr,0,n-1,x-1); cout<<ans<<endl; } return 0; }