第k大的数

问题描述:输入一组数,指定一个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;
}
原文地址:https://www.cnblogs.com/AKsnoopy/p/8550072.html