分治策略 - 選擇第k大數 - Java實現

題目要求:

編寫程序,對任意輸入的若干個不相同的整數,輸出其第k大的數html

解析:

咱們採用分治法解決這道題。 把這些數放在一個數組中,用分治法的話,咱們能夠想到,怎樣分治? 把一個數組分紅若干個大小相等的子數組,而後在這些子數組中取中位數,再取這些中位數的中位數,用這個數就能夠把數組劃分爲一個比它大的和比它小的數組。經過用這個數和咱們要求的數進行比較,若等於它,則直接返回這個數,若小於,則遞歸的對這個數前面的數組的這些數進行分治策略,若大於,則遞歸的對這個數後面的數組的這些數進行分治策略。java

$main()$裏只有一個$SelectK()$方法,中包含有兩個主要的方法,分別爲取中位數$Median()$和劃分$Divide()$方法。 \(Median()\): 首先,咱們把數組分爲5個一組(據說通過證實,5個一組劃分最科學),而後取每組的中位數,這時用的是$Median()$方法。具體的對每5個連續的數進行排序,而後把每組中的中位數即第3個數交換到數組的最左邊,若是這些轉移的數的個數多於5個,就再次調用$Median()$方法,直到最左邊的數是這個數組的中位數的中位數。 \(Divide()\): 介紹劃分方法,當求得中位數的中位數後,咱們就以這個數爲基準,把當前進行排序的數組的段落進行劃分,小於基準數的交換到基準數的左邊,大於的交換至右邊,而後比較要求的那個數和基準數是否相等,若是相等,則返回;若小於基準數,則遞歸左邊的子數組;若大於基準數,則遞歸右邊的子數組。算法

到這裏,就是簡單介紹一下這道題,這道題的主要算法在網上叫BFPRT算法,有興趣的同窗能夠去搜一下,若是不想搜的話,能夠直接看我以前寫的具體講這道題分治算法背後的算法思想的文章分治策略-選擇問題數組

Java代碼:

static void swap(int[]arr,int i,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    static void sortArr(int[] arr,int a,int b){
        for(int i=a;i<b;i++){
            for(int j=i+1;j<=b;j++){
                if(arr[i]<arr[j])
                    swap(arr,i,j);
            }
        }
    }
    //找中位數的中位數
    static int Median(int[] arr,int a,int b){
        if(a==b)
            return a;
        int i=0;
        int n=0;
        for(i=a;i<b-5;i+=5){
            sortArr(arr,i,i+4);
            n = i - a;
            swap(arr,a+n/5,i+2);
        }

        //下面是剩餘的數
        int last = b-i+1;
        if(last>0){
            sortArr(arr,i,i+last-1);
            n = i - a;
            swap(arr,a+n/5,i+last/2);
        }

        n/=5;
        if(n==a)
            return a;
        return Median(arr,a,a+n);
    }
    //劃分
    static int Divide(int[]arr,int a,int b,int m){
        swap(arr,m,a);
        int i = a;
        int j = b;
        int flag = arr[a];
        while (i<j){
            while (arr[j]<=flag && i<j)
                j--;
            arr[i] = arr[j];
            while (arr[i]>=flag && i<j)
                i++;
            arr[j] = arr[i];
        }
        arr[i] = flag;
        return i;
    }

    static int SelectK(int[] arr,int a,int b,int k){
        int m = Median(arr,a,b);
        int i = Divide(arr,a,b,m);

        int x = i-a+1;
        if(x==k)
            return arr[i];
        if(x>k)
            return SelectK(arr,a,i-1,k);
        return SelectK(arr,i+1,b,k-x);
    }



    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.println("請輸入要求的第k大的k:");
        int k = in.nextInt();
        int[] arr = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,100,99,98,97,96,95,94,93,92,91,
        90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,
        53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26};
//        System.out.println(arr.length);
        System.out.println("第"+k+"大爲:"+SelectK(arr,0,arr.length-1,k));
    }
相關文章
相關標籤/搜索