排序算法之基數排序

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



平均時間複雜度 最優時間複雜度 最差時間複雜度 空間複雜度 穩定性
基數排序 O(d(n+r)) O(d(n+r)) O(d(n+r)) O(n+r) 穩定

注:d爲數組最高位數,r爲基數
  • 算法描述
    • 將每一個元素按位數切割,收集元素的各個位數,而後按元素各個位數分配到對應的位置,順序能夠從高位到低位(MSD:最高優先法Most significant digital)或者低位到高位(LSD:最低優先法Least significant digital)
    • LSD:適用於位數較少的序列。先按照各個元素的最低位大小進行分配排序,再按照元素次低位大小進行分配排序...直到按照元素最高位分配排序。其中採用了計數排序的思想,只不過count的值不是元素自己,而是元素的各個位數上的值
    • MSD:適用於位數較多的序列採用了桶排序的遞歸思想:先把元素分到對應區間,再逐漸排好各個區間的。先按照各個元素的最高位大小進行分配排序,再對分配了不僅1個元素的「桶」內元素按次高位大小進行子分配排序...循環直到元素最低位
    • 這裏只考慮非負整數的排序
  • JS實現
// 使用公用函數GetHighDigitTemp
// 返回數組元素中的最高位數
function GetHighDigitTemp(array, radix) {
    var len = array.length;
    var max = array[0];
    for (var i = 1; i < len; i++) {
        if (array[i] > max) {
            max = array[i];
        }
    }
    var digit = 1;
    for (; max >= radix; digit++) {
        max /= radix;
    }
    return digit;
}
// 這裏是採用LSD的基數排序
// 此處傳入的array會被直接改變
function RadixSort_LSD(array, radix) {
    var len = array.length;
    if (len <= 1) {
        return;
    }
    var digit = GetHighDigitTemp(array, radix);
    var count = new Array(radix),
        bucket = new Array(len);
    for (var i = 0, digitTemp = 1; i < digit; i++, digitTemp *= radix) {
        for (var j = 0; j < radix; j++) {
            count[j] = 0;
        }
        for (var j = 0; j < len; j++) {
            var temp = Math.floor(array[j] / digitTemp) % radix;
            count[temp]++;
        }
        for (var j = 1; j < radix; j++) {
            count[j] += count[j - 1];
        }
        for (var j = len - 1; j >= 0; j--) {
            var temp = Math.floor(array[j] / digitTemp) % radix;
            bucket[count[temp] - 1] = array[j];
            count[temp]--;
        }
        for (var j = 0; j < len; j++) {
            array[j] = bucket[j];
        }
    }
}

// 這裏是採用MSD的基數排序
// 此處傳入的array會被直接改變
function RadixSort_MSD(array, radix, digit) {
    var len = array.length;
    if (len <= 1 || digit <= 0) {
        return;
    }
    var digitTemp = 1;
    var bucket = new Array(radix);
    for (var i = 0; i < radix; i++) {
        bucket[i] = [];
    }
    for (var i = 1; i < digit; i++) {
        digitTemp *= radix;
    }
    for (var i = 0; i < len; i++) {
        var temp = Math.floor(array[i] / digitTemp) % radix;
        bucket[temp].push(array[i]);
    }
    array.length = 0;
    for (var i = 0; i < radix; i++) {
        var sBucketILen = bucket[i].length;
        if (sBucketILen > 1) {
            RadixSort_MSD(bucket[i], radix, digit - 1);
        }
        for (var j = 0; j < sBucketILen; j++) {
            array.push(bucket[i][j]);
        }
    }
}

// 執行RadixSort_MSD必須先算出digit,digit爲數組元素中的最高位數
var digit = GetHighDigitTemp(array,radix);
  • 分析
    • 設待排序列長度爲n,序列中最高位數爲d,基數爲r,b爲每層遞歸的子桶數量
    • 其中使用的公共函數GetHighDigitTemp的時間複雜度爲O(n)
    • 對於採用了LSD方式的RadixSort_LSD,其時間複雜度T(n) = O(n + d * (2r + 3n)) = O(d(n + r)),其空間複雜度爲count數組和bucket數組所佔用的內存,S(n) = O(n + r)
    • 對於採用了MSD方式的RadixSort_MSD,其時間複雜度T(n) = O(d * (br + 2n)) = O(d(r + n)),(這裏的每一層遞歸的b不知道怎麼算,暫時把它當作常數),其空間複雜度爲壓棧最深的時候總的bucket數組所佔內存,棧最大深度爲d,每層遞歸的bucket所佔...而後,這個我算不明白了,但願以後能夠解答
    • 上述複雜度表格的數據是採用LSD的基數排序的複雜度
    • 兩種方法分別採用了計數排序桶排序的思想,而基於這兩種思想的排序都是穩定的,所以基數排序是穩定的
相關文章
相關標籤/搜索