线性排序

477 阅读4分钟

介绍

  • 包含桶排序,计数排序,基数排序
  • 时间复杂度为O(n)
  • 都不涉及元素之间的比较操作,是非基于比较的排序算法
  • 对排序数据的要求苛刻

桶排序

  • 核心思想:将要排序的数据分到几个有序的桶里,每个桶里的数据再单独进行排序。桶内排完序之后,再把每个桶里的数据按照顺序依次取出,组成的序列就是有序的了。
  • 使用条件:桶排序对要排序数据的要求是非常苛刻的。
    • 首先,要排序的数据需要很容易就能划分成m个桶,并且,桶与桶之间有着天然的大小顺序。这样每个桶内的数据都排序完之后,桶与桶之间的数据不需要再进行排序。

    • 其次,数据在各个桶之间的分布是比较均匀的。如果数据经过桶的划分之后,有些桶里的数据非常多,有些非常 少,很不平均,那桶内数据排序的时间复杂度就 不是常量级了。在极端情况下,如果数据都被划分到一个桶里,那就退化为O(nlogn)的排序算法了。

    • 桶排序比较适合用在外部排序中。所谓的外部排序就是数据存储在外部磁盘中,数据量比较大,内存有限,无法将数据全部加载到内存中。

计数排序

  • **核心思想:**其实是桶排序的一种特殊情况。当要排序的n个数据,所处的范围并不大的时候,比如最大值是k,我们就可以把数据划分成k个桶。每个桶内的数据值都是相同的,省掉了桶内排序的时间。
  • **案例:**考生的满分是900分,最小是0分,这个数据的范围很小,所以我们可以分成901个桶,对应分数从0分到900分。根据考生的成绩,我们将这50万考生划分到 这901个桶里。桶内的数据都是分数相同的考生,所以并不需要再进行排序。我们只需要依次扫描每个桶,将桶内的考生依次输出到一个数组中,就实现了50万考 生的排序。因为
    只涉及扫描遍历操作,所以时间复杂度是O(n)。
  • 使用条件:
    • 只能用在数据范围不大的场景中,若数据范围k比要排序的数据n大很多,就不适合用计数排序

    • 只能给非负整数排序

基数排序

  • 核心思想(以排序10万个手机号为例子):

    • 比较两个手机号码a,b的大小,如果在前面几位中a已经比b大了,那后面几位就不用看了。

    • 借助稳定排序算法的思想,可以先按照最后一位来排序手机号码,然后再按照倒数第二位来重新排序,以此类推,最后按照第一个位重新排序。

    • 经过11次排序后,手机号码就变为有序的了。

    • 每次排序有序数据范围较小,可以使用桶排序或计数排序来完成。

  • 使用条件:

    • 要求数据可以分隔独立的"位"来比较;
    • 位之间有递进关系,比较两个数,我们只需要比较高位,高位相同的再比较低位。
    • 每一位的数据范围不能太大,要可以用线性排序,否则基数排序的时间复杂度无法做到O(n)。

问题

  • 假设我们现在需要对D,a,F,B,c,A,z这个字符串进行排序,要求将其中所有小写字母都排在大写字母的前面,但小写字母内部和大写字母内部不要求有 序。比如经过排序之后为a,c,z,D,F,B,A,这个如何来实现呢?如果字符串中存储的不仅有大小写字母,还有数字。要将小写字母的放到前面,大写字母 放在最后,数字放在中间,不用排序算法,又该怎么解决呢?

  • 解答: 用两个指针a,b:a指针从头开始往后遍历,遇到大写字母就停下,b从后往前遍历,遇到小写字母就停下,交换a,b指针对应的元素;重复如上过程,直到a.b指针相交。

  • 对于小写字母放前面,数字放中间,大写字母放后面,可以先将数据分为小写字母和非小写字母两大类,进行如上交换后再在非小写字母区间内分为数字和大写字母做同样处理