BFPRT算法及其C++代码实现

BFPRT算法的应用场景:

在一个数组中求第k个大的值或第k个小的值

BFPRT可以使用O(N)的时间复杂度解决该问题。

 

BFPRT算法是在随机快速排序算法进行优化的,随机快速排序的思路如下:

1)随机的选取一个元素与最后一个元素进行交换位置,随机选取的数成为最后一个元素

2)遍历数组  小于最后一个元素的放在左边  大于最后一个元素的放在右边

3)将最后一个元素放到中间位置

经过上面的过程后数组分为三部分  小于随机选取的数  等于随机选取的数  大于随机选取的数

 

BFPRT算法是在以上算法进行的优化,算法的时间复杂度严格的O(N)

随机选取一个元素变为选取中位数

步骤如下:

1)将数组分为5个一组的多个数组 不足五个的形成一组O(N)

2)组内进行排序O(N)

3)每个数组中位数取出构成新的数组O(N)

4)递归的调用BFPRT 直到得到一个数组只剩一个数 返回T(N/5)

以上均为选取元素的部分

5)小于中位数左边 等于中位数中间 大于中位数右边O(N)

6)如果第K个值在左边 递归左边  在右边 递归右边  中间  返回

当数组的个数是N个时  排序之后得到中位数数组N/5 而求这N/5的中位数   这N/5个中位数中有N/10个元素比中位数大,所以所有的元素中至少有3N/10个元素比选出的中位数大,所以至少有7N/10个元素比中位数小

所以在步骤6中最坏情况是T(7N/10)

T(N)=T(N/5)+T(7N/10)+O(N)

例子如下:

数组:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 第10小的数

分组:1 2 3 4 5

            6 7 8 9 10

            11 12 13 14 15

得到中位数数组 3 8 13

最终得到中位数是8   在中位数数组中 至少13是比8大的,而13是它所在数组中位数 所以13所在的数组中至少还有2个数比8大 所以至少3个数比8大

得到中位数是8 8的下标为7

重新得到数组:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

递归9 10 11 12 13 14 15中找第10-7-1小的数

 

/*
 * 求一个数组的第k个大的数 O(N)
 *
 * 荷兰国旗问题可以实现O(N)求出数组的第k大的数(基于概率得到)
 *      类似于排序  然后找打第k个位置上的值
 *      随机的选取一个值 将大于这个数的值放右边 小于这个数的值放左边  等于这个数的值放右边
 *      如果第k大的值在等于k的范围内  可以直接得到结果
 *      如果第k大的值在左边  递归的做左边   在右边 递归的做右边
 *
 * BFPRT算法
 *      1.五个一组 O(1)
 *      2.组内排序  O(N)
 *      3.每个组中位数取出组成新的数组 O(N)
 *      4.递归调用BFPRT找到中位数 T(N/5)
 *      以上均为取划分值
 *      5.大于右边  小于左边  等于中间O(N)
 *      6.如果第k大的值在左边  递归的做左边   在右边 递归的做右边
 *
 *      中位数的个数是N/5   中位数数组的中位数假设为c
 *      至少比c的大的中位数个数N/10  至少比c大的中位数个数3N/10
 *
 *      如果k在左边  左边的最坏情况是最多有7N/10个人比中位数小T(7N/10)
 *      同理如果k在右边 右边的最坏情况是最多有7N/10个人比中位数大
 *
 *      T(N)=T(N/5)+T(7N/10)+O(N)
 *
 *      时间复杂度O(N)
 * */

#include
#include
#include
#include

class CSolution{
public:
    int BFPRT(std::vector vData,int iL,int iR){
        if(iR-iL==0)
            return vData[iR];

        std::vector> vDat;
        std::vector vD;

        //五个一组分组
        for(int i=iL;i<=iR;i=i+5){
            vD.clear();
            for(int j=i;j vMedium;
        //组内排序提取中位数组成新数组
        for(int i=0;i &vData,int iK,int iL,int iR){
        int iMedium=BFPRT(vData,iL,iR);

        //将目标与最后一个元素交换
        int iIndexTarget=getIndex(vData,iMedium);
        swap(vData,iIndexTarget,iR);

        int iLess=iL-1;
        int iMore=iR+1;
        int num=vData[iR];

        int l=iL;
        while(lnum){
                swap(vData,l,--iMore);
            }
            else
                l++;
        }


        int iCountLess=iLess+1-iL;//比中位数小的个数
        int iCountMore=iR-(iMore-1);//等于中位数的个数
        int iCountEqual=iMore-iLess-1;//大于中位数的个数

        if(iK<=iCountLess){
            return getBiggerK(vData,iK,iL,iL+iCountLess-1);//当第K个值在小于中位的的一边时 递归求左边
        }else if(iK>iCountLess+iCountEqual){
            return getBiggerK(vData,iK-iCountLess-iCountEqual,iL+iCountLess+iCountEqual,iR);//在右边 递归求右边
        }
        else
            return iMedium;//当等于中位数的值时返回中位数的值即可
    }

    //得到中位数所在的下标
    int getIndex(std::vector &vData,int target){
        for(int i=0;i &vData,int iL,int iR){
        int tmp=vData[iL];
        vData[iL]=vData[iR];
        vData[iR]=tmp;
    }

};

int main()
{
    std::vector vData={2,344,1,123,23,3,4,354,45,6,7,8,123,12,7};
    //std::vector vData={2,1,3,4,6,7,7};
    CSolution cS1;
    //std::cout<

 

 

你可能感兴趣的:(常见算法)