排序算法之基数排序

这里是传送门⇒总结:关于排序算法



平均时间复杂度 最优时间复杂度 最差时间复杂度 空间复杂度 稳定性
基数排序 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的基数排序的复杂度
    • 两种方法分别采用了计数排序桶排序的思想,而基于这两种思想的排序都是稳定的,因此基数排序是稳定的
posted @ 2021-02-23 22:40  有机物与鱼  阅读(31)  评论(0编辑  收藏  举报