排序算法之计数排序

这里是传送门⇒总结:关于排序算法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;
}
相关文章
相关标签/搜索