在排序的最终结果中,各元素的次序依赖于它们之间的比较。这类排序算法被称为比较排序。对于包含 nnn 个元素的输入序列来说,任何比较排序算法在最坏情况下都要经过至少 O(nlogn)O(n\ log\ n)O(n log n) 次比较。

而一些排序算法是用运算而不是比较来确定排序顺序的,如计数排序、基数排序以及桶排序。因此,比较次数的下界 O(nlogn)O(n\ log\ n)O(n log n) 对它们是不适用的。

下面介绍计数排序。

计数排序

计数排序假设 nnn 个输入元素中的每一个都是在 000 到 kkk 区间内的一个整数,其中 kkk 为某个整数。计数排序的时间复杂度为 O(n+k)O(n+k)O(n+k),当 k=O(n)k=O(n)k=O(n) 时,排序的时间复杂度为 O(n)O(n)O(n)。

计数排序要求输入数据必须是整数,在实际工作中,当 k=O(n)k=O(n)k=O(n) 时,一般会采用计数排序。如果输入元素的范围不在 000 到 kkk 之内,那么可以根据元素的最大值和最小值将其映射到 000 到 kkk 之内。

计数排序的基本思想:对于每一个输入元素 xxx,确定小于 xxx 的元素个数。利用这一信息,就可以直接把 xxx 放到它在输出数组中的位置上了。例如,如果有 17 个元素小于 xxx, 则 xxx 就应该在第 18 个输出位置上。当有几个元素相同时,这一方案要略做修改,因为不能把他们放在同一个输出位置上。

算法执行过程中需要三个数组:
(1)数组 AAA,为要排序的输入数组,数组大小为 nnn。
(2)数组 BBB,提供临时存储空间,用于存储小于该下标值的元素个数,数组大小为 k+1k+1k+1。
(3)数组 CCC,存放排序的输出,数组大小为 nnn。
因此该算法的空间复杂度为 O(n+k)O(n + k)O(n+k),当 k=O(n)k=O(n)k=O(n) 时,空间复杂度为 O(n)O(n)O(n)。

算法执行过程如下:
(1)根据待排序数组 AAA 中元素的最大值 maxmaxmax 和最小值 minminmin,申请大小为 max−min+1max-min+1max−min+1 的数组 CCC。
(2)扫描数组 AAA,记录每个不同的元素出现的次数,将其记录在数组 CCC 中。数组 CCC 的每一位 C[i]C[i]C[i] 就代表数组 AAA 中元素 i+mini+mini+min 出现的次数。可以发现,计数排序的该过程,其实就是将待排序集合 AAA 中的每个元素值本身大小作为下标,依次进行了存放。而此时的数组 CCC 就是为了确定每个元素值出现了几次。
(3)对数组 CCC 中的每个值从前向后进行累加,每个位置的值更新为加上前一个位置的值,此时数组 CCC 中每个元素 C[i]C[i]C[i] 表示待排序数组 AAA 中 小于等于该下标值 iii 的元素个数。
(4)反向遍历待排序数组 AAA 来填充目标数组 BBB:将 AAA 中每个元素值 A[j]A[j]A[j] 放在新数组的第 C[A[j]−min]C[A[j]-min]C[A[j]−min] 位,然后将 C[A[j]−min]C[A[j]-min]C[A[j]−min] 减一。

用上图举例在输入数组 AAA 上的处理过程。其中 AAA 中的每一个元素都是在 000 到 555 范围内:
(a)首先扫描一遍数组 AAA,记录 AAA 中每个元素出现的次数,将该信息存储在数组 CCC 中, CCC 中每个下标就表示 AAA 中不同的元素值。如当前图中数组 CCC 所示;
(b)从前向后对计数进行累加,当前数组 CCC 中每个元素代表小于等于该下标的元素出现的次数;
(c~e)反向遍历输入数组 AAA,将其每个元素 A[j]A[j]A[j] 放在输出数组 BBB 的第 C[A[j]]C[A[j]]C[A[j]] 项,然后将 C[A[j]]C[A[j]]C[A[j]] 减一。图中表示该过程迭代了一次、两次和三次之后,输出数组 BBB 和辅助数组 CCC 的情况。其中数组 BBB 只有浅色阴影部分有元素值填充;
(f)最终排好序的输出数组 BBB。

计数排序的一个重要性质就是它是稳定的:具有相同值的元素在输出数组中的相对次序相同。也就是说,对两个相同的数来说,在输入数组中先出现的数,在输出数组中在位于前面。
计数排序的稳定性很重要的另一个原因是:计数排序经常会被用作计数排序算法的一个子过程。

虽然计数排序看上去很强大,但是它存在两大局限性:

  • 当数据最大值和最小值差距过大时,并不适用于计数排序。

    比如给定 20 个随机整数,范围在 0 到 1 亿之间,此时如果使用计数排序的话,就需要创建长度为 1 亿的数组,不但严重浪费了空间,而且时间复杂度也随之升高。
    因此计数排序只适用于元素值较为集中的情况。

  • 当数列元素不是整数时,并不适用于计数排序。

    如果数列中的元素都是小数,比如 3.1415,或是 0.00000001 这样子,则无法创建对应的统计数组,这样显然无法进行计数排序。

正是由于这两大局限性,才使得计数排序不像快速排序、归并排序那样被人们广泛适用。

Counting-sort(A, B) {maximum = max(A);minimum = min(A);int k = maximum - minimum + 1;let C[0..k] be a new array// initialionfor i=0 to k            C[i] = 0;for j=0 to A.length - 1C[A[j]-minimum]++;// C[i] now contains the number of elements equal to i.for i=1 to kC[i] = C[i] + C[i-1]// C[i] now contains the number of elements less than or equal to i. for j = A.length-1 downto 0B[C[A[j]-minimum]] = A[j];C[A[j]-minimum]--;
}

排序算法——计数排序详解相关推荐

  1. 三种线性排序算法 计数排序、桶排序与基数排序—— 转自:BYVoid

    三种线性排序算法 计数排序.桶排序与基数排序 [非基于比较的排序] 在计算机科学中,排序是一门基础的算法技术,许多算法都要以此作为基础,不同的排序算法有着不同的时间开销和空间开销.排序算法有非常多种, ...

  2. JavaScript实现十大排序算法(图文详解)

    冒泡排序 排序的效果图 解法 当前解法为升序 冒泡排序的特点,是一个个数进行处理.第i个数,需要与后续的len-i-1个数进行逐个比较. 为什么是 `len-i-1`个数? 因为数组末尾的i个数,已经 ...

  3. 排序算法---计数排序(java版)

    计数排序 原理 计数排序(Counting Sort) 使用了一个额外的数组 C,其中第 i 个元素是待排序数组A 中值等于 i 的元素的个数.然后根据数组 C 来将 A 中的元素排到正确的位置.其实 ...

  4. 十大排序算法——计数排序

    计数排序 一. 计数排序介绍 二. 计数排序基础版 三. 计数排序改进版 四. 优化最终版本_空间节省 一. 计数排序介绍 计数排序(Counting sort)是一种稳定的排序算法.计数排序使用一个 ...

  5. c语言归并排序代码详细注释,C语言实现排序算法之归并排序详解

    排序算法中的归并排序(Merge Sort)是利用"归并"技术来进行排序.归并是指将若干个已排序的子文件合并成一个有序的文件. 一.实现原理: 1.算法基本思路 设两个有序的子文件 ...

  6. 排序算法之快速排序详解

    一.算法介绍 快速排序:快速排序的基本思想是通过一次排序将等待的记录分成两个独立的部分,其中一部分记录的关键字小于另一部分的关键字.C部分的快速排序一直持续到整个序列被排序. 任取一个元素 (如第一个 ...

  7. 归并排序java_Java经典排序算法之归并排序详解

    一.归并排序 归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.将已有序的子序列合并,得到完全有序的序列:即先使每个子序列 ...

  8. 选择排序算法与示例详解(c语言)

    选择排序是排序算法的一种,思想就是,每一轮寻找数组中最大的值或者最小的值,放在头部或者放入一个新的数组.这样经历一轮遍历,数组或者新数组就是排好序的,他的目的很明确,每次找最大值或者最小值. 这个放在 ...

  9. C++排序算法:归并排序详解

            目录 一.归并排序 二.基本算法 1.分离 2.合并 3.图片讲解 三.C++代码实现 1.分离函数 2.合并函数 3.C++完整代码 4.样例 四.总结 一.归并排序 归并排序(Me ...

最新文章

  1. 28自定义View 模仿联系人字母侧栏
  2. 水平,垂直居中的15种方法
  3. MVC Razor模板引擎
  4. 十大最常见的Java性能问题
  5. Multi-thread--C++11中atomic的使用
  6. deep_learning 03. tf.nn.rnn_cell.MultiRNNCell()
  7. 苏州旅游网站的设计与实现 毕业论文+Html静态源码
  8. 51单片机数码管中断倒计时报警
  9. 将2010年的旧电脑升级为Win8.1遇到的问题及解决办法
  10. 矩阵求逆(JAVA)利用伴随矩阵
  11. 网传华为员工未加班领夜宵被冻薪降考评,并终身不得领夜宵
  12. 台式计算机机箱型号及价格,顶级组装台式电脑配置清单
  13. 最小-最大搜索和Alpha-beta剪枝搜索
  14. DBF文件使用JAVA读写解决方案
  15. [web-css] 白天/黑夜场景切换案例
  16. 【快速入门大数据】hadoop和它的hdfs、yarn、mapreduce
  17. 三维投影总结:数学原理、投影几何、OpenGL教程、我的方法
  18. 利用“bert模型”预测英语“完形填空”答案
  19. DeepHPV:一个用于预测HPV整合人类基因位点的深度学习模型
  20. 黑帽子技能|爆破Android的锁屏密码

热门文章

  1. 51单片机入门学习--LED流水灯呼吸灯
  2. APS排程系统的生产模型
  3. 两万多字长文:人工智能新趋势(CB Insights)
  4. 手机打开USB调试(华为)
  5. Android--仿QQ空间动态页(继续拖动查看详情)及标题栏渐变
  6. 广州今年将严打黑客攻击和侵犯公民个人信息犯罪_金羊网新闻
  7. 关于电容,这篇说得太详细了
  8. linux 复制硬盘无法启动,linux – 用克隆替换硬盘失败
  9. css放在上面,js放在下面的原因
  10. GridView编辑EmptyDataTemplate控数据模板