BFPTR算法——求第k小元素

1.问题描述

输入一个规模为n的数组,求数组中的第k小元素,其中1<=k<=n。

2.BFPTR算法描述

之所以介绍BFPTR算法,是因为这个算法求第k小元素的时间复杂度为O(n),时间复杂度分析见文末。

(1)文字描述
第一步:对数组中元素连续5个为一组进行分组,每一组都进行排序。
第二步:选取每组中的中间元素进入数组MID。
第三步:利用BFPTR算法求出MID数组中的中间元素mid。
第四步:遍历整个原始数组,比mid小的数放入数组small,比mid大的数放入数组big。
第五步:如果k=| small |+1,则返回mid;如果k<| small |+1,则递归处理small数组,求第k小元素;否则,递归处理big元素,求第k-1-| small |元素。
(2)伪码描述

BFPTR(a[],k)
if size of a[] is less than 5,sort a[] using any sorting algorithm;
Divide a[] into M=n/2 groups,each of which has size 5;
Find the median of each group and denote the set of medians by M;
mid=BFPTR(M,(|M|+1)/2);
Compare the elements of a[] with x;
Let small be the set of the elements less than x;
Let big be the set of the elements larger than x;
if k=|small|+1 than return mid;
else if k<|small|+1 than BFPTR(small,k);
else return BFPTR(big,k-1-|small|;

3.代码实现

template<class T>
int split(vector<T>& a,int start,int end)
{
    T temp=a[start];
    int low=start,high=end;

    for(;;)
    {
        while(low<high&&a[high]>=temp)
            high--;
        if(low==high)
            break;
        a[low++]=a[high];
    
        while(low<high&&a[low]<=temp)
            low++;
        if(low==high)
            break;
        a[high--]=a[low];
    }
    a[high]=temp;
    return high;
}

template<class T>
void QuickSort(vector<T>& a,int start,int end)
{
    int mid;
    if(start>=end)
        return ;
    mid=split(a,start,end);
    QuickSort(a,start,mid-1);
    QuickSort(a,mid+1,end);
}

template<class T>
T BFPTR(vector<int>& a,int k,int n)
{
    if(n<=5)
    {
        QuickSort(a,0,n-1);
        return a[k-1];
    }
        vector<T> MID;//存放各小组中的中位数
        vector<T>small;//存放比中位数小的数
        vector<T>big;//存放比中位数大的数
        int len_MID;
        int len_s;
        int len_b;
        T mid;//中位数
        int i;//循环计数
        bool flag=false;

        for(i=0;i+4<n;i+=5)
            QuickSort(a,i,i+4)//5个一组使用快速排序进行排序
        if(n%5==0)//输入规模刚好是5的倍数else//最后一个小组元素个数不够5个
        {
            int more=n%5;
            QuickSort(a,n-more,n-1);//对最后一个小组进行快速排序
        }

        for(i=2;i<n;i+=5)
            MID.push_back(a[i])//将每个小组中的中间元素加入MID
        len_MID=MID.size();
  
        mid=BFPTR(MID,(len_MID+1)/2,len_MID);//使用同样的算法找出中位数

        for(i=0;i<n;i++)//遍历所有元素
        {
            if(a[i]<=mid)
            {
                //以下if-else语句是使类似于1 2 3 3 4 5,k=4这种情况正常输出3
                //即len_s+len_b=n-1
                if(a[i]==mid&&flag==false)//flag=false表示第一次遇到和中位数元素相同的元素,应该跳过该元素
                    //置flag=true,表示下次遇到时不需要再次跳过
                    flag==true;
                else
                    small.push_back(a[i]);
            }
            else
                big.push_back(a[i]);
        }
        len_s=small.size();
        len_b=big.size();

        if(k==len_s+1)
            return mid;
        else if(k<len_s+1)
            return BFPTR(small,k,len_s);
        else
            return BFPTR(big,k-len_s-1,len_b);
}

4.时间复杂度分析

在这里插入图片描述
将各个组的中位数由大到小排好序后,黄色部分元素一定小于等于m,红色部分元素一定大于m,而紫色部分不确定。考虑最坏情况,即紫色部分元素全部小于m,则需要递归处理small数组求第k小。

设一共有2r+1列,最坏情况下 len_s =7r+2,总元素数n=10r+4,r=(n-4)/10,代入7r+2可知 len_s <7n/10,因此子问题规模最大为7n/10。

设算法时间复杂度为T(n)
(1)子问题规模最大7n/10,因此使用BFPTR处理子问题的时间复杂度为 T(7n/10)
(2)5个元素一组进行排序时,时间复杂度为常数级
(3)选取每组的中位数进入MID的时间复杂度为O(n/5)
(4)使用BFPTR算法从MID中找到中位数的时间复杂度为T(n/5)
(5)遍历数组的时间复杂度为O(n)

因此T(n)=T(7n/10)+T(n/5)+O(n)
可以解出,BFPTR算法的时间复杂度为O(n)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值