一、归并排序
1、原理
采用分治思想。将数组分成前后两部分,先将这两部分进行排序,然后再将二者合并即可。
2、原地排序?
不属于原地排序。因为每次合并都需要申请大小为 n 的临时数组用于保存合并之后的结果,所以空间复杂度为O(n)。
3、稳定性排序?
属于稳定排序算法。为了达到上述目的,只需要在合并时将前后两部分相同的元素中的属于前面部分的数据先放入临时数组即可。
4、时间复杂度
因为代码采用了递归方式,所以这里需要使用递归公式来估计时间复杂度。递归公式如下:
这里的 T(a) 表示单次递归时的耗时,T(a1)代表均分之后前一部分的排序时间,T(a2)代表均分之后后一部分的排序时间,t 为二者合并时间。通过代码发现,合并 n 个数据,需要比较 n 次,如下图所示:
故所以 t = n 。
对于归并排序,时间复杂度的公式:
经过递推,则公式如下:
当 时,。将 k 代入上述公式中,则结果为 ,这里面的 。所以时间复杂度为 O(nlogn) 。
二、快速排序
1、原理
采用分治思想,是优化之后的冒泡排序。随机从数列找到一个数作为中心点(pivot),小于该数的放在左边,大于该数的放在右边,上述操作取名为“分区”。上述两部分数据在再依次分区,直至数据不能再分区为止,这样数据就变成有序的了。
2、原地排序?
属于原地排序算法。因为在分区的过程中,使用了交换数据的方法,并没有建 n 个临时内存,所以空间复杂度为 O(1) 。
3、稳定性排序?
不属于稳定性排序。栗子:
6、7、9、6、3、5
经过排序之后发现,第1个“6”和第2个“6”发生了位置颠倒,所以该算法不属于稳定性排序算法。
4、时间复杂度
(1)最好的情况
每次分区时选择的 pivot 均是数组的中间值,那么时间复杂度就是 O(nlogn) 。
(2)最坏的情况
原数组已经有序但是是逆序,例如:102、10、8、5、2,目标是从小到大排序,每次分区时选择的 pivot 均是最右面的值,则需要比较 n-1 、n-2、n-3、……、1,那么时间复杂度的和就是 O(n^2) 。
(3)平均时间复杂度
(后续补充)
三、总结
1、性质
算法种类 | 时间复杂度 | 空间复杂度 | 原地排序 | 稳定排序 |
归并排序 | O(nlogn) | O(n) | × | √ |
快速排序 | O(nlogn) | O(1) | √ | × |
2、源码
(SAW:Game Over!)