線性時間排序


   各種排序算法總結已經介紹了幾種能在O(n*log(n))時間內培訓n個數的算法。歸並排序和堆排序達到了最壞情況下的上界;快速排序在平均情況下達到該上界。這些算法都有一個有趣的性質:在排序的最終結果中,各元素的次序依賴於它們之間的比較。這類算法為比較算法,還有一類算法是線性時間復雜度的排序算法,有計數排序、基數排序和桶排序,當然,這些算法使用運算而不是比較來確定排序順序的。

1 計數排序

  計數排序假設n個輸入元素中的每一個都是0到n區間的一個整數,其中n是某個整數。計數排序的思想是:對每一個輸入元素x,確定小於x的元素個數,利用這里信息可以直接把x放到它在輸出數組中的位置了。例如,如果有5個元素小於x,則x最后應該放在第6個輸出位置上(也就是下標為5)。當幾個元素相同時,這一方案要修改一下,因為不能將相同的元素放到一個輸出位置上。

  計數排序是穩定的,即具有相同元素值的元素在數組中的先后位置在排序前后不發生改變。計數排序通常被用作基數排序的一個子過程。以下代碼是計數排序的Java實現。

// 排序區間范圍是[0, MAX)
private final static int MAX = 100;

public void countSort(int[] arr) {
    // 臨時存放排序的輸出
    int[] aux = new int[arr.length];
    // 提供臨時存儲空間
    int[] count = new int[MAX + 1];

    // 1.頻率統計
    for (int i = 0; i < arr.length; i++) {
        count[arr[i] + 1]++;
    }
    //2.頻率轉換為索引
    for (int i = 1; i < count.length; i++) {
        count[i] += count[i - 1];
    }
    // 3.將元素分類
    for (int i = 0; i < arr.length; i++) {
        aux[count[arr[i]]++] = arr[i];
    }
    // 4.回寫
    for (int i = 0; i < arr.length; i++) {
        arr[i] = aux[i];
    }
}

 

2 基數排序

  基數排序(radix sorting)將所有待比較數值(正整數)統一為同樣的數位長度,數位較短的數前面補零。 然后從最低位開始,依次進行一次排序。這樣從最低位排序一直到最高位排序完成以后,數列就變成一個有序序列。

  基數排序的方式可以采用LSD(Least sgnificant digital)或MSD(Most sgnificant digital),低位優先的字符串排序(LSD)依賴於鍵索引計數法,相當於從右到左對字符串中每一個字符進行鍵索引排序,最后整個字符串數組也就排好序了。而MSD則相反,由鍵值的最左邊開始。以下代碼是基數排序的Java實現。

public void radixSortInternal(String[] arr, int index) {
    String[] aux = new String[arr.length];
    int[] count = new int[26 + 1];

    // 1.頻率統計
    for (int i = 0; i < arr.length; i++) {
        count[arr[i].charAt(index) - 'a' + 1]++;
    }
    //2.頻率轉換為索引
    for (int i = 1; i < count.length; i++) {
        count[i] += count[i - 1];
    }
    // 3.將元素分類
    for (int i = 0; i < arr.length; i++) {
        aux[count[arr[i].charAt(index) - 'a']++] = arr[i];
    }
    // 4.回寫
    for (int i = 0; i < arr.length; i++) {
        arr[i] = aux[i];
    }
}

public void radixSort(String[] arr) {
    for (int i = arr[0].length() - 1; i >= 0; i--) {
        radixSortInternal(arr, i);
    }
}

 

3 桶排序

  桶排序假設輸入數據服從平均分配,平均情況下代價為O(n)。與計數排序類似,因為對輸入數據做了假設,所以其速度也很快。具體來說,計數排序假設輸入數據都屬於一個小區間內的整數,而桶排序則假設輸入數據是由一個隨機過程產生,該過程將元素均勻獨立分布在[0, 1)(假設的)區間上。桶排序將[0, 1)區間划分為幾個相同大小的子區間,或稱為桶。因為數據量是隨機獨立分布在[0, 1)上的,所以一般不會出現一個桶內元素過多情況。為了得出排序結果,對每個桶中元素排序,然后遍歷整每個桶就得到了排序后的元素。下圖是排序過程圖,以下代碼是Java實現。

// 排序區間范圍是[0, MAX)
private final static int MAX = 100;

public void bucketSort(int[] arr) {
    // 桶大小為10
    TreeSet<Integer>[] bucket = new TreeSet[10];
    for (int i = 0; i < 10; i++) {
        bucket[i] = new TreeSet();
    }

    for (int i = 0; i < arr.length; i++) {
        bucket[arr[i] / 10].add(arr[i]);
    }

    for (int i = 0, k = 0; i < 10; i++) {
        for (Integer x : bucket[i]) {
            arr[k++] = x;
        }
    }
}

 

參考資料:

  1、《算法導論》8章-線性時間排序

  2、luoxn28/algorithm_data_structure

  3、各種排序算法總結


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



線性時間排序 線性時間排序 線性時間排序 線性時間排序算法 幾種線性時間排序 線性時間的排序算法 線性時間排序 線性時間排序 線性時間排序 線性時間排序
 
粤ICP备14056181号  © 2014-2021 ITdaan.com