求区间第k大的值

#include <iostream>
using namespace std;
int a[100], n;

int part(int l, int r)
{
    if(l > r) return -1;

    int i=l,j=r;
    int tmp=a[l];

    while(i<j)
    {
        while(a[j]>=tmp && i<j)
            j--;
        while(a[i]<=tmp && i<j)
            i++;
        if(i<j)
        {
            int tmp1 = a[i];
            a[i] = a[j];
            a[j] = tmp1;
        }
    }
    a[l] = a[i];
    a[i] = tmp;

    return i;
}

int check(int l, int r, int k)
{
    int idx = part(l, r);
    if(idx == k)
        return a[idx];
    else if(idx < k)
        check(idx+1, r, k);
    else
        check(l, idx-1, k);
}

int main()
{
    cin >>  n;

    for(int i=0;i<n;++i) cin>>a[i];
    int k; cin>>k;
    int result = check(0,n-1,k);
    cout << result;

    return 0;
}

  

只需找到第k大的数,不必把所有的数排好序。我们借助快排中partition过程,一般情况下,在把所有数都排好序前,就可以找到第k大的数。我们依据的逻辑是,经过一次partition后,数组被pivot分成左右两部分:S左、S右。当S左的元素个数|S左|等于k-1时,pivot即是所找的数;当|S左|小于k-1,所找的数位于S右中;当|S左|>k-1,所找的数位于S左中。显然,后两种情况都会使搜索空间缩小。

算法的时间复杂度为:O(N),计算公式,假设我们的数据足够的随机,每次划分都在数据序列的中间位置,根据条件1,那么第一次划分我们需要遍历约n个数,第二次需要遍历约n/2个数,...,这样递归下去,最后:

 

 

快排

#include<iostream>
using namespace std;

int a[100], n;

void quick_sort(int l, int r)
{
    if(l > r) return;

    int i=l, j=r;

    int tmp=a[l];
    while(i<j)
    {
        while(a[j]>=tmp && i<j)
            j--;
        while(a[i]<=tmp && i<j)
            i++;
        if(i<j)
        {
            int tmp1 = a[i];
            a[i] = a[j];
            a[j] = tmp1;
        }
    }
    a[l]=a[i];
    a[i]=tmp;

    quick_sort(l,i-1);
    quick_sort(i+1,r);
}

int main()
{
    cin >> n;
    for(int i = 0; i<n; ++i) cin>>a[i];

    quick_sort(0,n-1);

    for(int i=0; i<n; ++i) cout << a[i] << " ";
    return 0;
}

  

posted @ 2018-06-29 19:31  unicoe  阅读(498)  评论(0编辑  收藏  举报