排序算法之桶排序

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



平均时间复杂度 最优时间复杂度 最差时间复杂度 空间复杂度 稳定性
桶排序 O(n + n(logn - logk)) O(n) O(n2) O(n+k) 稳定

注:k为桶数量

桶排序中的“桶”代表一个取值区间,里面可以放若干个元素

桶排序是计数排序的改进版本:计数排序可以看成每个“桶”只放相同元素,而桶排序每个“桶”放的是一定范围的元素。计数排序申请的空间跨度从最小元素值到最大元素值,若待排序集合中元素不是依次递增的,则必然有空间浪费情况;桶排序则是弱化了这种浪费情况,尽量减少了元素值大小不连续情况下的空间浪费情况

桶排序需要尽量保证元素分散均匀,否则当所有数据集中在同一个桶中时,桶排序失效

  • 算法描述
    • 首先应该创建“桶”,即确定若干个取值区间,而如何确定这些区间的方式有多种
    • 其中一种划分区间的方式:创建的“桶”数量为待排序列长度,最后一个“桶”只包含待排序列的最大值,其他“桶”的区间范围跨度为“最大值与最小值之差均分”。比如,待排序列为[4.5,0,84,3.25,2.18,0.5],那么“桶”数量为5,区间跨度为(4.5-0.5)/(5-1) = 1,也就是各个“桶”的取值范围为[0.5,1.5)、[1.5,2.5)、[2.5,3.5)、[3.5,4.5)、[4.5,4.5]
    • 然后遍历待排序列,把元素按区间取值分到对于的“桶”里
    • 而对于分在(包含1个以上元素的)桶里的元素可以用其他排序算法(比如适合一定取值范围的计数排序)或者以递归方式继续使用桶排序进行排序
  • JS实现
// 此处传入的array会被直接改变
function BucketSort(array) {
    var len = array.length;
    if (len <= 1) {
        return;
    }
    var max = min = array[0];
    for (var i = 0; i < len; i++) {
        if (array[i] > max) {
            max = array[i];
        }
        if (array[i] < min) {
            min = array[i];
        }
    }
    var bucketLen = len;
    var gap = Math.floor((max - min) / bucketLen) + 1;
    var bucket = new Array(bucketLen);
    for (var i = 0; i < bucketLen; i++) {
        bucket[i] = [];
    }
    for (var i = 0; i < len; i++) {
        var index = Math.floor((array[i] - min) / gap);
        bucket[index].push(array[i]);
    }
    array.length = 0;
    for (var i = 0; i < bucketLen; i++) {
        var sBucketLen = bucket[i].length;
        if (sBucketLen > 1) {
            QuickSort(bucket[i], 0, sBucketLen - 1);
            for (var j = 0; j < sBucketLen; j++) {
                array.push(bucket[i][j]);
            }

        }
    }
}
  • 分析
    • 桶排序的复杂度分两部分:分配元素到对应“桶”的复杂度和进行“桶”内排序时使用的排序算法复杂度
    • 前者的时间复杂度为O(n),后者则由使用的排序算法决定
    • 若后者使用的排序算法是基于键值比较的算法(比如快排),基于键值比较的算法的时间复杂度下限为O(nlogn),设待排序列长度为n,前者中创建了m个“桶”,且分配均匀,即每个“桶”内的元素有k = $\frac{n}{m}$,那么后者的平均时间复杂度T(n) = $m \times O(k\log k)$ = $m \times O(\frac{n}{m}\log \frac{n}{m}$) = O($n\log \frac{n}{m}$),当“桶”数量接近待排序列元素数量n时,$\log \frac{n}{m}$就会是一个较小的常数,这时时间复杂度接近O(n),所以桶排序的最优时间复杂度T(n) = O(n)
    • 若“桶”内排序使用的是其他排序,而且后者使用的是原地排序,即后者的空间复杂度为O(1)时,桶排序的空间复杂度仅由前者的空间复杂度决定,而前者主要是看bucket使用的空间,即“桶”数量 + 桶内使用的空间 = m + n,则桶数量的时间复杂度为O(n + m)
    • 很显然,“桶”划分的区间越小,各个“桶”内的数据越少,“桶”内排序所用的时间也会越少。但相应的空间消耗就会增大,因为要多创建“桶”
    • 上文表格桶排序的复杂度数据为对“桶”内元素使用直接插入排序的桶排序的复杂度(除了平均复杂度。平均复杂度是用基于键值比较的排序算法整体来算的)
posted @ 2021-02-23 22:34  有机物与鱼  阅读(101)  评论(0编辑  收藏  举报