BFPRT算法过程分析和实现

过程分析

参考自王晓东 《计算机算法设计与分析(第三版)》

  • BFPRT算法是一个最坏情况下用O(n)时间就可以找到TopK元素的算法。
    过程分析如下:
    (1)将n个元素分成n/5个组,除了可能最后一组不是5个元素外,每组5个元素。用任意一种排序算法,将每组元素排好序,并取每组的中位数共n/5个.
    (2)找出这n/5个元素中的中位数。然后以这个元素作为划分基准。
    可以分析出,在这种情况下,找出的基准x至少比1/2*(n/5 - 1)* 3个元素要大,也即至少比3*((n-5)/10)个元素要大,同理x也至少比3*((n-5)/10)个元素要小。而当n >= 75时,3((n-5)/10) >= n/4。所以按此基准划分所得的两个子数组的长度都至少缩短1/4.
    伪码如下:
Type Select(Type[] a, int p, int r, int k)
{
    if((r-p) < 75)
    {
        对数组a[p:r]排序;
        return a[p+k-1];
    }
    for(int i = 0; i <= (r-p+1-5)/5)
    {
        将a[p+5*i]至a[p+5*i+4]的第三小元素与a[p+i]交换位置;//思考这步是干嘛的
    }
    //找中位数的中位数,r-p-4就是n-5
    Type x = Select(a, p, p + (r - p - 4) / 5, (r - p - 4) / 10);
    int i = Patition(a, p, r, x),j = i - p + 1;
    if(k <= j)
        return Select(a, p, i, k);
    else
        return Select(a, i + 1, r, k - j);
}

代码实现如下:


import java.util.Arrays;
import java.util.Scanner;

/* @author  作者 E-mail: * @date 创建时间:2017年8月1日 上午11:40:56 * @version 1.0 * @parameter  * @since  * @return  */
public class BFPRT {

    public static int Select(int[] a, int p, int r, int k) {
        if (r - p < 75) {
            Arrays.sort(a);
            return a[p + k - 1];
        }
        for (int i = 0; i <= (r - p + 1 - 5) / 5; i++) {
            int temp = a[i];
            swap(5 * i, 5 * i + 4, 3, a);
        }
        int x = Select(a, p, p + (r - p + 1 - 5) / 5, (r - p + 1 - 5) / 10);// 中位数的中位数
        int i = Partition(a, p, r, x), j = i - p + 1;
        if (k <= j)
            return Select(a, p, i, k);
        else
            return Select(a, i + 1, r, k - j);
    }

    public static void swap(int begin, int end, int minThird, int[] a) {
        Arrays.sort(a, begin, end);
        int temp = a[begin];
        a[begin] = a[begin + minThird];
        a[begin + minThird] = temp;

    }

    public static int Partition(int[] a, int p, int r, int partValue) {
        // 相当于快速排序的中的一趟
        int pivot = partValue;
        int partValueId = FindpartValueId(a, partValue);
        a[partValueId] = a[0];
        a[0] = pivot;
        int left = p;
        int right = a.length - 1;
        while (left < right) {
            while (a[right] > pivot)
                right--;
            a[left] = a[right];
            while (a[left] < pivot)
                left++;
            a[right] = a[left];
        }
        a[left] = a[0];
        return left;
    }

    public static int FindpartValueId(int[] a, int partValue) {
        int i;
        for (i = 0; i < a.length; i++) {
            if (a[i] != partValue)
                continue;
            else
                break;
        }
        return i;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        int[] a = { 12, 76, 29, 22, 15, 62, 29, 58, 35, 67, 58, 33, 28, 89, 90, 28, 64, 48, 20, 77 };
        Scanner sc = new Scanner(System.in);
        int k = sc.nextInt();
        int minKth = Select(a, 0, a.length - 1, k);
        System.out.println(minKth);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值