面试中经常碰到排序算法的问题,所以这里把常用的几种排序总结一下
线性时间排序
计数排序:首先统计每个数的个数,然后直接得出有序的序列。时间复杂度O(n + k),空间复杂度O(k),k表示数组中最大的数--------不稳定
基数排序:从最低位开始,先按照该位的大小排序,然后按照次低位的大小排序.......最后按照最高位大小排序,n个d位数,每位可能取值有k种,用基数排序时间复杂度为O(d * (n + k)) --------稳定的
桶排:把一个长为L的等分成k个大小相同的区间,或者称为桶,然后把长度为n的数组的每一个数扔到对应的桶里面,第二遍将每个桶里面的数进行排序,最后按顺序输出每一个桶中的元素。桶排基于一种假设,就是所有n个数均匀的分布在区间上,如果满足这个假设,平均时间复杂度是O(n)。在极端情况下,也大量的数集中到一个桶里,时间复杂度依然是很高的。(实现桶排建议用邻接表)
基于比较的排序 (在最坏情况下,任何比较排序算法都需要做n*lg(n)次比较)
比较排序可以被抽象为一棵决策树,如上图,是一棵对三个数进行排序的决策树,每一个叶结点对应着一种序列。。
考虑一棵高度为h,具有l个可达的叶节点的决策树,它对应n个元素所做的排序:
n! <= l <= 2^h
=>h >= O(n * lg(n))
1、冒泡排序,时间复杂度O(n ^ 2),空间O(1) --------稳定的
2、插入排序,时间O(n ^ 2),空间O(1) -------- 稳定的
3、选择排序,时间O(n ^ 2),空间O(1) --------不稳定的
4、堆排,时间O(n * lg(n)),空间O(n) --------不稳定的
5、归并排序,分治法的一个非常典型的应用,把一个长度为n的待排序数组每次平均分成两个子序列,得到一个二叉递归数,递归到最后每个子序列的长度为1,也就是每个子序列都有序的时候,开始回溯,每向上回溯一层时,将两个有序的子序列合并成一个有序的序列。归并排序如果除去控制以及数据移动所花的时间的话,时间复杂度也是O(n * lg(n)),但是在进行归并操作的时候,往往要花掉很多的时间,大致有两种选择,一种是用空间换时间,利用一个临时数组,这样空间复杂度稍高;另一种是采用类似插入排序的方法,可以进行原址排序,时间上花费要更高。--------稳定
6、快速排序,时间复杂度依赖于划分是否平衡。最坏情况下,时间复杂度为O(n ^ 2),最好情况下O(n * lg(n))
对于快速排序,《算法导论》里面是这样说的:快速排序通常是实际排序应用中最好的选择,因为它的平均性能非常好,期望时间复杂度是渐进O(n * lg(n)),而且O(n * lg(n))中隐含的常数因子非常小,此外,可以进行原址排序,在虚存环境下也能很好工作。--------不稳定