排序算法入门(九)——计数排序

93 阅读1分钟

算法简介

计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。

算法描述

  1. 找出待排序的数组中最大和最小的元素;
  2. 统计数组中每个值为 i 的元素出现的次数,存入数组 C 的第 i 项;
  3. 对所有的计数累加(从 C 中的第一个元素开始,每一项和前一项相加);
  4. 反向填充目标数组:将每个元素 i 放在新数组的第 CiC_i 项,每放一个元素就将 CiC_i 减去 1。

动图演示

849589-20171015231740840-6968181.gif

代码实现

public class Counting {
    public static int[] countSort(int[] arr) {
        if(arr == null || arr.length < 2) return arr;

        int n = arr.length;
        int max = arr[0];
        // 寻找数组的最大值
        for (int i = 1; i < n; i++) {
            if(max < arr[i])
                max = arr[i];
        }
        //创建大小为max的临时数组
        int[] temp = new int[max + 1];
        //统计元素i出现的次数
        for (int i = 0; i < n; i++) {
            temp[arr[i]]++;
        }
        int k = 0;
        //把临时数组统计好的数据汇总到原数组
        for (int i = 0; i <= max; i++) {
            for (int j = temp[i]; j > 0; j--) {
                arr[k++] = i;
            }
        }
        return arr;
    }
}

复杂度分析

计数排序是一个稳定的排序算法。当输入的元素是 nn 个 0 到 kk 之间的整数时,时间复杂度是 O(n+k)O(n+k),空间复杂度也是 O(n+k)O(n+k),其排序速度快于任何比较排序算法。当 kk 不是很大并且序列比较集中时,计数排序是一个很有效的排序算法。但这是一种牺牲空间换取时间的算法,而且当 O(k)>O(nlogn)O(k)>O(nlogn) 的时候其效率反而不如基于比较的排序。