美文网首页
随机选择算法-选择第K大

随机选择算法-选择第K大

作者: crishawy | 来源:发表于2019-03-16 16:19 被阅读0次

    问题描述

    从一个无序数组中求出第K大的数,如{5,12,7,2,9,3},第三大的数是5,第五大的数是9.
    一种思路直接先排序,取出第K个元素即可,但时间复杂度最少也是O(nlogn),而使用快速排序的思想,时间复杂度可以降低为O(n)

    思路

    当对A[left,right]执行一次randPartiton之后,主元左侧的个数是确定的且都小于主元,右侧的元素均大于主元,不妨令主元是A[p],此时A[p]是A[left,right]中第p-left+1大的数

    • 若k == p - left + 1 ,那么返回该数即可
    • 若k < p - left + 1,那么第k大的数在区间[left,p-1]中,即在A[left,p-1]的第K大,往左侧递归即可
    • 若k > p -left + 1,那么第k大的数在区间[p+1,right]中,即在A[p+1,right]中的第K - (p-left +1)大

    程序代码

    int randPatition(int A[],int left,int right)
    {
    
        //生成[left,right]的随机数
        int p =  round((1.0*rand()/RAND_MAX)* (right - left) + left);
        swap(A[left],A[p]);
        int temp = A[left];
        //只要left与right不相遇
        while(left <right)
        {
            //右边
            while(left < right && A[right] > temp) right --;
            A[left] = A[right];
            //左边
            while(left < right && A[left] <= temp) left ++ ;
            A[right] = A[left];
        }
        //left与right相遇的地方放置temp
        A[left] = temp;
        //返回相遇的下标
        return left;
    }
    
    void randSelect(int A[],int left,int right,int k)
    { //划分序列,形成以A[p]为主元第k大的数,使其左边小于它,右边大于它
        //随机选择划分,那么A[p]是该序列中第p-left+1大的
    
        if(left == right) //边界
            return ;
        int p = randPatition(A,left,right);
        int M = p - left + 1;
        if(k == M)
            return;
        else if(k < M) randSelect(A,left,p-1,k);
        else randSelect(A,p+1,right,k-M); //这里注意寻找第K-M大!
    }
    

    相关文章

      网友评论

          本文标题:随机选择算法-选择第K大

          本文链接:https://www.haomeiwen.com/subject/llesmqtx.html