三种时间复杂度是O(n)的排序算法:桶排序、计数排序、基数排序。因为这些排序算法的时间复杂度是线性的,所以我们把这类排序算法叫做线性排序(Linear sort).之所以能做到线性的时间复杂度,主要原因是,这三个算法是基于比较的排序算法,都不涉及元素之间的比较操作。
桶排序(Bucket sort)
桶排序,顾名思义,会用到:“桶”,核心思想是将要排序的数据分到几个有序的桶里,每个桶里的数据在单独进行排序。桶内排完序之后,再把每个桶里的数据按照顺序依次取出,组成的数列就是有序的了。
桶排序对排序数据的要求非常苛刻:
首先:要排序的数据需要很容易就能划分成m个桶,并且,桶与桶之间有着天然的大小顺序。这样每个桶内的数据都以排序完之后,桶与桶之间的数据不需在进行排序;
其次,数据在各个桶之间的分布比较均匀的。
桶排序比较适合用在外部排序中。所谓外部排序中就是数据存储在外部的磁盘中,数据量比较大,内存有限,无法将数据全部加载到内存中。
计数排序:(Counting sort)
计数排序其实是桶排序的一种特殊情况。
总结:计数排序只能用在数据范围不大的场景中,如果数据范围K比要排序n大很多,就不适合用计数排序了。而且,计数排序只能给非负整数排序,如果要排序的数据是其他类型的,要将其在不改变相对大小的情况下,转化为非负整数。
基数排序:(Radix sort)
基数排序对要排序的数据是有要求的,需要可以分割出独立的“位”来比较,而且“位”之间有递进的关系,如果a数据的高位比b数据大,那剩下的低位就不用比较了。除此之外每位的数据范围不能太大,要可以用线性排序来排序,否则,基数排序的时间复杂度就无法做到O(n)。
如何优化快速排序:
这种O(n^2)时间复杂度出现的主要原因是还是因为我们分区点选的不够合理。最理想的分区点是:被分区点分开的两个分区中,数据的数量差不多。
比较常用、比较简单的分区算法:
1、三数取中法
我们从区间的首尾、中间分别取出一个数,然后对比大小,取这三个数的中间值作为分区点。但是,如果要排序的数据组比较大,那“三数组中”可能就不够了,可能要“五数组中”或者“十数组中”。
2、随机法
随机法就是每次从要排序的区间中,随机选择一个元素作为分区点。
快速排序是用递归实现的,递归要警惕堆栈溢出。为了避免快速排序里递归过深而堆栈过小,导致堆栈溢出。我们有两种解决办法:第一种是限制递归深度。一旦递归过深,超过了我们事先设定的阈值,就停止递归。第二种是通过在堆栈上模拟实现一个函数调用栈,手动模拟递归压栈、出栈的过程,这样就没有了系统栈大小的限制。
引用自极客时间