持續輸出面試題之算法--分配排序

開篇介紹

你們好,我是Java最全面試題庫的提褲姐,今天這篇是數據結構與算法的第五篇,主要介紹分配排序;在後續,會沿着第一篇開篇的知識線路一直總結下去,作到日更!若是我能作到百日百更,但願你也能夠跟着百日百刷,一百天養成一個好習慣。java

分配排序

前面所討論的排序算法均是基於關鍵字之間的比較來實現的,而理論上已證實:
對於這樣的排序,不管用何方法都至少要進行[lgn]次關鍵字的比較。由 Stirling公式可知lgn≈nlgn-1.44n+0(lgn),因此基於關鍵字比較的排序時間下界是O(nlgn)。可是,若不經過比較關鍵字來排序,則可能突破此下界。分配排序正是如此,排序過程無須比較關鍵字,而是經過「分配」和「收集」過程來實現排序,它們的時間複雜度可達到線性階:O(n)
分配排序包括 桶排序基數排序git

桶排序

桶排序(箱排序 (Bucket sort)),工做的原理是將數組分到有限數量的桶子裏。每一個桶子再個別排序(有可能再使用別的排序算法或是以遞歸方式繼續使用桶排序進行排序。面試

算法步驟:
假設有一組長度爲N的待排關鍵字序列K[1....n]
一、首先將這個序列劃分紅M個的子區間(桶)。
二、而後基於某種映射函數 ,將待排序列的關鍵字k映射到第i個桶中(即桶數組B的下標 i) ,那麼該關鍵字k就做爲B[i]中的元素(每一個桶B[i]都是一組大小爲N/M的序列)。
三、對每一個桶B[i]中的全部元素進行比較排序(可使用快排)。
四、而後依次枚舉輸出B[0]....B[M]中的所有內容便是一個有序序列算法

桶排序.png

特性:數組

  • 時間複雜度:O(n+k)
  • 空間複雜度:O(n+k)
  • 穩定性:穩定

代碼實現:數據結構

public class BucketSort {

    private static final InsertSort insertSort = new InsertSort();

    public int[] sort(int[] sourceArray) throws Exception {
        // 對 arr 進行拷貝,不改變參數內容
        int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);

        return bucketSort(arr, 5);
    }

    private int[] bucketSort(int[] arr, int bucketSize) throws Exception {
        if (arr.length == 0) {
            return arr;
        }

        int minValue = arr[0];
        int maxValue = arr[0];
        for (int value : arr) {
            if (value < minValue) {
                minValue = value;
            } else if (value > maxValue) {
                maxValue = value;
            }
        }

        int bucketCount = (int) Math.floor((maxValue - minValue) / bucketSize) + 1;
        int[][] buckets = new int[bucketCount][0];

        // 利用映射函數將數據分配到各個桶中
        for (int i = 0; i < arr.length; i++) {
            int index = (int) Math.floor((arr[i] - minValue) / bucketSize);
            buckets[index] = arrAppend(buckets[index], arr[i]);
        }

        int arrIndex = 0;
        for (int[] bucket : buckets) {
            if (bucket.length <= 0) {
                continue;
            }
            // 對每一個桶進行排序,這裏使用了插入排序
            bucket = insertSort.sort(bucket);
            for (int value : bucket) {
                arr[arrIndex++] = value;
            }
        }

        return arr;
    }

    /**
     * 自動擴容,並保存數據
     *
     * @param arr
     * @param value
     */
    private int[] arrAppend(int[] arr, int value) {
        arr = Arrays.copyOf(arr, arr.length + 1);
        arr[arr.length - 1] = value;
        return arr;
    }

}

基數排序

基數排序(Radix Sort)是桶排序的擴展,它的基本思想是:
將整數按位數切割成不一樣的數字,而後按每一個位數分別比較。 函數

具體作法:將全部待比較數值統一爲一樣的數位長度,數位較短的數前面補零。而後,從最低位開始,依次進行一次排序。這樣從最低位排序一直到最高位排序完成之後, 數列就變成一個有序序列。spa

算法步驟
一、將全部待比較數值(正整數)統一爲一樣的數位長度,數位較短的數前面補零。
二、從最低位開始,依次進行一次排序。
三、這樣從最低位排序一直到最高位排序完成之後, 數列就變成一個有序序列。code

基數排序.png

特性:blog

  • 時間複雜度:O(n*k)
  • 空間複雜度:O(n+k)
  • 穩定性:穩定

代碼實現:

public class RadixSort {

    public int[] sort(int[] sourceArray) throws Exception {
        // 對 arr 進行拷貝,不改變參數內容
        int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);

        int maxDigit = getMaxDigit(arr);
        return radixSort(arr, maxDigit);
    }

    /**
     * 獲取最高位數
     */
    private int getMaxDigit(int[] arr) {
        int maxValue = getMaxValue(arr);
        return getNumLenght(maxValue);
    }

    private int getMaxValue(int[] arr) {
        int maxValue = arr[0];
        for (int value : arr) {
            if (maxValue < value) {
                maxValue = value;
            }
        }
        return maxValue;
    }

    protected int getNumLenght(long num) {
        if (num == 0) {
            return 1;
        }
        int lenght = 0;
        for (long temp = num; temp != 0; temp /= 10) {
            lenght++;
        }
        return lenght;
    }

    private int[] radixSort(int[] arr, int maxDigit) {
        int mod = 10;
        int dev = 1;

        for (int i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
            // 考慮負數的狀況,這裏擴展一倍隊列數,其中 [0-9]對應負數,[10-19]對應正數 (bucket + 10)
            int[][] counter = new int[mod * 2][0];

            for (int j = 0; j < arr.length; j++) {
                int bucket = ((arr[j] % mod) / dev) + mod;
                counter[bucket] = arrayAppend(counter[bucket], arr[j]);
            }

            int pos = 0;
            for (int[] bucket : counter) {
                for (int value : bucket) {
                    arr[pos++] = value;
                }
            }
        }

        return arr;
    }

    /**
     * 自動擴容,並保存數據
     *
     * @param arr
     * @param value
     */
    private int[] arrayAppend(int[] arr, int value) {
        arr = Arrays.copyOf(arr, arr.length + 1);
        arr[arr.length - 1] = value;
        return arr;
    }
}
相關文章
相關標籤/搜索