1. 程式人生 > >詳解堆排序 附程式碼 無序陣列中找到最小的k個數

詳解堆排序 附程式碼 無序陣列中找到最小的k個數

堆排序:
堆排序時間複雜度是O(NlogN)
空間複雜度如果不用遞迴的話可以達到O(1),在陣列上原地排序
這裡給出堆排序程式碼
注意此處在篩操作的時候sift(Object[] a, int n, int i),中間的引數n是代表這時候陣列的總大小。因為在建完堆後,陣列從後往前會一輪一輪的有序,n會漸漸減小。在無序陣列中找最小的k個數的程式碼中就不需要記錄這個值,在這程式碼中,需要建大根堆,用陣列中的其他數跟大根堆堆頂比較。
篩操作也就是sift()方法,它代表,在建好的二叉堆上如果堆頂換了一個值,通過篩操作使得該陣列又符合二叉堆的條件。那為什麼建堆的時候也是用這個方法呢,因為這裡是從底向上建堆,每次經過父節點時,都能保證它的左孩子和右孩子是二叉堆。
這裡建堆的複雜度就是O(N),而不是我們想象中的O(NlogN)。
建堆過程和時間複雜度證明如下
這裡寫圖片描述


但是後面排序,即把堆頂放到陣列後面的過程,在進行篩操作,時間複雜度就變成O(NlogN)了。

public class Solution {
    public static void main(String[] args) {
        Integer[] a = new Integer[]{3,4,2,6,5,7,9,1,8};
        heapSort(a, 9);
        System.out.println(Arrays.toString(a));
        //buildHeap(a);
        return;
    }

    public
static void heapSort(Object[] a, int n) { Object x; for (int i = n / 2 - 1; i >= 0; i--) { sift(a, n, i); } for (int i = 1; i < n; i++) { x = a[0]; a[0] = a[n-i]; a[n-i] = x; sift(a, n-i, 0); } return
; } public static void sift(Object[] a, int n, int i){ int j = 2*i+1; while (j <= n-1){ if (j<n-1 && ((Comparable)a[j]).compareTo((Comparable)a[j+1]) <0){ j++; } if (((Comparable)a[i]).compareTo((Comparable)a[j]) <0){ swap(a, i, j); i = j; j = 2*i+1; } else { break; } } } public static void swap(Object[] a, int i, int j){ Object tmp = a[i]; a[i] = a[j]; a[j] = tmp; } }

【無序陣列中找到最小的k個數】
假設陣列長度是N
下面程式碼的時間複雜度O(NlogK)
還有一種方法可以做到時間複雜度O(N),利用快速排序的原理。

public class Main {
    public static void main(String[] args) {
        int[] arr = { 6, 9, 1, 3, 1, 2, 2, 5, 6, 1, 3, 5, 9, 7, 2, 5, 6, 1, 9 };
        int k = 10;
        System.out.println(Arrays.toString(getMinKNumsByHeap(arr, k)));
    }

    //自己建立大根堆排序
    public static int[] getMinKNumsByHeap(int[] arr, int k){
        int[] heap = new int[k];
        for (int i = 0; i < k; i++) {
            heap[i] = arr[i];
        }
        for (int i = k/2 -1; i >= 0 ; i--) {
            seaf(heap, i);
        }
        //k+1..,N個值一一放進去比對
        for (int i = k; i < arr.length; i++) {
            if (arr[i] < heap[0]){
                heap[0] = arr[i];
                seaf(heap, 0);
            }
        }
        return heap;
    }

    //篩選堆
    public static void seaf(int[] arr, int i){
        int father = i;
        int index = 2 * i + 1;
        while (index < arr.length){
            if (index < arr.length -1){
                if (arr[index+1] > arr[index]){
                    index = index +1;
                }
            }
            if (arr[index] > arr[father]){
                int tmp = arr[index];
                arr[index] = arr[father];
                arr[father] = tmp;
                father = index;
                index = 2* index + 1;
            }
            else {
                break;
            }
        }
    }

}