常考数据结构与算法-找到第k小的数(迭代,递归,bfprt)

本文介绍了一个名为'Code01_FindMinKth'的Java程序,通过三种不同的方法(minKth1, minKth2, minKth3)实现查找数组中第k小的元素。方法一使用迭代和分区,方法二递归,方法三是快速选择(BFPRT)。通过测试比较它们的性能,确保结果一致性。
摘要由CSDN通过智能技术生成
public class Code01_FindMinKth {

    public static void main(String[] args) {
        int testTime = 5000;
        int length = 200;
        int max = 5000;
        for (int i = 0; i < testTime; i++) {
            int[] arr = generateArray(length,max);
            int k = (int)(Math.random()*arr.length+1);
//            for (int j = 0; j < arr.length; j++) {
//                System.out.print(arr[j]+" ");
//            }
//            System.out.println("k="+k);

            int ans1 = minKth1(arr,k);
            int ans2 = minKth2(arr,k);
            int ans3 = minKth3(arr,k);

            if(ans1 != ans2 || ans1 != ans3){
                System.out.println("no oops!");
            }
        }


        System.out.println("yes");
    }

    // 方法一: 迭代调用
    public static int minKth1(int[]arr, int k){

        int[] copy= arrayCopy(arr);

        int L = 0;
        int R = copy.length-1;
        while(L<R){
            int pivot = copy[L+(int)Math.random()*(R-L+1)];
            int[] ragne = partition(copy,L,R,pivot);
            if(k-1<ragne[0]){
                R = ragne[0]-1;
            }else if(k-1 > ragne[1]){
                L = ragne[1]+1;
            }else{
                return copy[k-1];
            }
        }

        return copy[L];
    }

    // 方法二: 递归调用
    public static int minKth2(int[]arr, int k){

        int[] copy= arrayCopy(arr);
        return process2(copy, 0, copy.length-1,k-1);
    }

    // 方法三: bfprt方法调用
    public static int minKth3(int[]arr, int k){

        int[] copy= arrayCopy(arr);
        return bfprt(copy, 0, copy.length-1,k-1);
    }

    public static int bfprt(int[] arr, int L, int R, int index){
        if(L == R){
            return arr[L];
        }

        int pivot = medianOfMedians(arr,L,R);

        int[] range = partition(arr,L,R,pivot);

        if(index>=range[0] && index<=range[1]){
            return arr[index];
        }else if(index<range[0]){
            return bfprt(arr, L, range[0]-1,index);
        }else{
            return bfprt(arr,range[1]+1,R,index);
        }
    }

    /*
    * arr[L...R] 五个数一组
    * 每个小组内部排序
    * 每个小组中位数领出来,组成marr
    * marr中的中位数,返回
    */
    public static int medianOfMedians(int[] arr, int L, int R){
        int size = R - L + 1;
        int offset = size%5 == 0 ? 0 : 1;
        int[] mArr = new int[size/5+offset];
        for (int team = 0; team<mArr.length; team++){
            int teamFirst = L+team*5;
            mArr[team] = getMedian(arr,teamFirst,Math.min(R, teamFirst+4));
        }

        // marr中找到中位数
        return bfprt(mArr,0,mArr.length-1,mArr.length/2);
    }

    public static int getMedian(int[]arr, int L, int R){
        insertionSort(arr,L,R);
        return arr[(L+R)/2]; // 返回中位数
    }

    // 插入排序
    public static void insertionSort(int[]arr, int L, int R){
        for (int i = L+1; i <= R; i++) {

            for (int j = i-1; j >=L && arr[j]>arr[j+1]; j--) {
                swap(arr,j,j+1);
            }
        }
    }

    public static int[] generateArray(int lenght, int max){
        int[] arr = new int[(int)(Math.random()*lenght)+1];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int)(Math.random()*max+1);
        }

        //System.out.println(arr.length);
        return arr;
    }

    public static int[] arrayCopy(int [] arr){
        int[] copy= new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            copy[i] = arr[i];
        }

        return copy;
    }

    public static int process2(int[] arr, int L, int R, int index){
        if(L == R){
            return arr[L];
        }

        //System.out.println(R+" "+L);
        //int pivot = arr[L+(int)(Math.random()*(R-L+1))];
        int pivot = arr[L];
        int[] range = partition(arr,L,R, pivot);
        if(index>=range[0] && index<=range[1]){
            return arr[index];
        }else if(index<range[0]){
            return process2(arr, L, range[0]-1,index);
        }else{
            return process2(arr,  range[1]+1,R, index);
        }
    }

    public static int[] partition(int[]arr, int L, int R, int pivot){
        int less = L-1;
        int more = R+1;
        int cur = L;
        while(cur < more){
            if(arr[cur] < pivot){
                //1 2 3 4 5 6 6 6 6 7,2,9
                swap(arr,++less,cur++);
            }else if(arr[cur] == pivot){
                cur++;
            }else{
                swap(arr, --more,cur);
            }
        }

        return new int[]{less+1,more-1};
    }

    public static void swap(int[]arr, int l, int r){
        int t = arr[l];
        arr[l] = arr[r];
        arr[r] = t;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值