求数组第K大的数

问题:有一个大小为n的数组A[0,1,2,…,n-1],求其中第k大的数。
我们先分析原问题:有一个大小为 n的数组A[0,1,2,…,n-1],求其中第k大的数。

我们先取特例,令k=1,那么就是取最大的数,只要扫描一遍数组就可以确定该值,如果k=2,则扫描两边数组就可以确定第二大的数,依此类推下去,时间复杂度是O(k*n),如果k跟n是一个数量级,那么时间复杂度就是O(n*n)了,显然不是最优的解法。

考虑分治法,难点在于如何将该问题分解为两个子问题。

快速排序最基础的一步:

   随机取某一个数x,将其与数组末尾元素交换,然后将比其小的数交换至前,比其大的数交换至后。

这一步使某一数组的快速排序问题分解成两个子数组的排序问题,现在我们就依此来解决取第k大的数这个问题。

设数组下表从0开始,至n-1结束。

1、 随机取某个数,将其与数组末尾元素交换。

a) idx=rand(0,n-1);生成[0,n-1]间的随机数。

b) Swap(array[idx], array[n-1]);

2、 用末尾元素x,将比x小的数交换至前,比x大的数交换至后,并返回此时x在数组中的位置mid。

3、 如果mid==n-k,那么返回该值,这就是第k大的数。

如果mid>n-k,那么第k大的数在左半数组,且在左半数组中是第k-(n-mid)大的数。

如果mid

#include "iostream"  
using namespace std;  

int random_partion(int *p, int n)  
{  
     int idx=rand()%n;  
     swap(p[idx], p[n-1]);  
     int i=-1;    //i表示最后一个小于p[n-1]的元素的位置  
     int j=0;     //j用来扫描数组  
     for(j=0; j<n; j++)  
     {  
            //将小于p[n-1]的数交换到前半部分  
            if(p[j]<p[n-1])  
            {  
                swap(p[++i], p[j]);  
            }  
     }  
     swap(p[++i], p[n-1]);  
     return i;   
}  

int getMaxK(int *p, int n, int k)  
{  
    int mid;  
     if(k<=0)  
            return -1;  
     if(n<k)  
            return -1;  
     mid=random_partion(p, n);   //对原数组进行一次划分  
     if(mid == n-k)      //如果mid==n-k,那么返回该值,这就是第k大的数  
         return p[mid];  
     else if(mid<n-k)  
         return getMaxK(p+mid+1, n-mid-1, k);  //如果mid<n-k,那么第k大的数在右半数组,而且仍然是第k大数  
     else  
         return getMaxK(p, mid, k-(n-mid));   //如果mid>n-k,那么第k大的数在左半数组,且在左半数组中是第k-(n-mid)大的数  
}  

int main(void)  
{  
    int num,a[] = {12012, 3, 945, 965, 66, 232, 65, 7, 8, 898, 56, 878, 170, 13, 5};  
    num=getMaxK(a, 15, 4);  
    printf("%d\n",num);  
    system("pause");  
    return 0;  
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值