排序算法之計數排序

這裏是傳送門⇒總結:關於排序算法html



平均時間複雜度 最優時間複雜度 最差時間複雜度 空間複雜度 穩定性
計數排序 O(n+m) O(n+m) O(n+m) O(n+max) 穩定
優化後 O(n+m) O(n+m) O(n+m) O(n+m) 穩定

注:m爲待排序列取值範圍大小,max爲待排序列最大值

計數排序一種是「空間換時間」的排序,只能直接應用於非負整數的排序中(由於數組下標是非負整數,至關於用待排元素i做爲索引,數組元素的值count[i]是待排序列中小於或者等於該下標i的元素數量)。算法

優點在對於元素取值範圍m較小的待排序列的排序中,(優化後)時間複雜度是線性的Ο(n+m),快於任何鍵值比較排序算法。固然若是O(m)>O(nlogn),其效率反而不如基於鍵值比較的排序,若數據範圍m比排序數據的數量n大不少,就不適合用計數排序。數組

雖然算法中有比較,但並不是是鍵值間的比較,而是經過對元素值的計數和計數值的累加來肯定的。優化

  • 算法描述
    • 對於待排序列中的每個元素,肯定序列中小於等於該元素的元素個數。經過這個信息將每一個元素放在序列中正確的位置
    • 固然,若是有多個元素具備相同的值時,咱們不能將這些元素放在序列的同一個位置上
    • 過程舉例:初始化後count[0] = 1, count[1] = 2(此時意爲序列中有1個0和2個1),則count[1] = count[0] + count[1] = 3,即序列中小於等於「1」的元素個數count[1]爲3,則第一個值爲「1」的元素應該放在序列的第count[1]個位置,即第3個位置array[2];而後讓count[1]--爲2,即如今待排序列中小於等於「1」的元素只有2個,那麼第二個值爲「1」的元素放在序列的第count[1]個位置,即第2個位置array[1]。爲了維持其穩定性,讓填充操做方向爲序列末尾往前
  • JS實現
// 此處沒有改變array
function CountingSort(array) {
    var len = array.length;
    if (len <= 1) {
        return array;
    }
    var max = array[0];
    var count = [],
        res = [];
    for (var i = 1; i < len; i++) {
        if (array[i] > max) {
            max = array[i];
        }
    }
    var countLen = max + 1;
    for (var i = 0; i < countLen; i++) {
        count[i] = 0;
    }
    for (var i = 0; i < len; i++) {
        count[array[i]]++;
    }
    for (var i = 1; i < countLen; i++) {
        count[i] += count[i - 1];
    }
    for (var i = len - 1; i >= 0; i--) {
        res[count[array[i]] - 1] = array[i];
        count[array[i]]--;
    }
    return res;
}
  • 分析code

    • 設待排序列的長度爲n,取值範圍大小爲m,最大值max
    • 無論什麼狀況下,操做C(n) = O(3n + m) = O(n + m),即時間複雜度T(n) = O(n + m)
    • 空間複雜度主要看count數組和res數組佔用的內存,即CountingSort的S(n) = O(n + max)
    • 根據分析,計數排序的侷限性在於若是取值範圍m太大,複雜度就不夠優秀和元素必須是非負整數(下面的優化能夠兼容負整數,而在js中把count數組換成「對象」的話就能夠兼容小數了
    • 因爲在算法中重複元素在序列的位置是是先給靠近末尾的,填充方式是從末尾向前的,因此計數排序是穩定的
  • 優化htm

    • 當前的count數組的長度是由待排序列的最大值決定的,當待排序列中元素的取值範圍爲8-10時,count數組長度爲11,count數組中0-7位置會閒置,形成浪費
    • 優化爲count數組長度爲元素取值範圍,偏移量爲最小值。即當待排序列中元素的取值範圍爲8-10時,count數組長度爲3(即10-8+1),映射偏移量爲8,意爲待排序列中小於等於8的元素個數存放在count[8-偏移量8] = count[0]
    • 這樣作不只節省了空間,並且利用偏移量,可讓計數排序兼容負數(仍是隻能整數)的狀況,由於每一個元素減去偏移量(序列最小值)以後一定爲非負數,可做爲count的下標
    • 優化後的CountingSortPlus的S(n) = O(m + n)
  • 優化版的JS實現對象

// 此處沒有改變array
function CountingSortPlus(array) {
    var len = array.length;
    if (len <= 1) {
        return array;
    }
    var min = max = array[0];
    var count = [],
        res = [];
    for (var i = 1; i < len; i++) {
        if (array[i] > max) {
            max = array[i];
        }
        if (array[i] < min) {
            min = array[i];
        }
    }
    var countLen = max - min + 1;
    for (var i = 0; i < countLen; i++) {
        count[i] = 0;
    }
    for (var i = 0; i < len; i++) {
        count[array[i] - min]++;
    }
    for (var i = 1; i < countLen; i++) {
        count[i] += count[i - 1];
    }
    for (var i = len - 1; i >= 0; i--) {
        res[count[array[i] - min] - 1] = array[i];
        count[array[i] - min]--;
    }
    return res;
}
相關文章
相關標籤/搜索