这是我参与更文挑战的第 9 天,活动详情查看: 更文挑战
排序
冒泡排序、插入排序、选择排序、归并排序、快速排序、计数排序、基数排序、桶排序
排序算法的执行效率
-
最好情况,最坏情况,平均情况时间复杂度
还要说出最好、最坏时间复杂度对应的要排序的原始数据是什么样的。
-
时间复杂度的系数,常数,低阶
-
比较次数和交换(或移动)次数
基于比较的排序算法的执行过程,会涉及两种操作,一种是元素比较大小,另一种是元素交换或移动。所以,如果我们在分析排序算法的执行效率的时候,应该把比较次数和交换(或移动)次数也考虑进去。
排序算法的内存消耗 算法的内存消耗可以通过空间复杂度来衡量,原地排序(Sorted in place),原地排序算法,就是特指空间复杂度是 的排序算法。
排序算法的稳定性
稳定的排序算法和不稳定的排序算法
冒泡排序是原地排序算法,空间复杂度为 ,冒泡排序是稳定的排序算法。冒泡排序的最好情况时间复杂度是 ,就是要排序的数据已经是有序的了,只需要进行一次冒泡操作。最坏的情况是,要排序的数据刚好是倒序排列的,需要进行 n 次冒泡操作,所以最坏情况时间复杂度为 。平均情况时间复杂度为 。
插入排序是原地排序算法,空间复杂度为 ,插入排序是稳定的排序算法。核心思想是取未排序区间的元素,在已排序区间找到合适的位置将其插入,并保证已排序区间数据一直有序。初始已排序区间只有一个元素,就是数组的第一个元素。 插入排序的最好时间复杂度为 ,注意这里是从尾到头遍历已经有序的数据。如果数组是倒序的,每次插入都相当于在数组的第一个位置插入新的数据,所以需要移动大量的数据,所以最坏情况时间复杂度为 。平均时间复杂度为 。
选择排序是一种原地排序算法,空间复杂度为 ,是一种不稳定的原地排序算法。算法的思想有点类似插入排序,也分已排序区间和未排序区间。但是选择排序每次都会从未排序区间中找到最小的元素,将其放到已排序区间的末尾。选择排序最好,最坏,平均情况时间复杂度都为 。
虽然冒泡排序和插入排序在时间复杂度都是一样的,都是 ,冒泡排序的数据交换要比插入排序的数据移动要复杂,但是如果我们希望把性能优化做到极致,那肯定选插入排序(优化:希尔排序)。
归并排序不是原地排序算法(致命弱点),这是因为归并排序的合并函数,在合并两个有序数组为一个有序数组时,需要借助额外的存储空间。它是一个稳定的排序算法,最好,最坏,平均情况时间复杂度都是 ,空间复杂度是 。
快速排序是原地排序算法,不是一个稳定的排序算法。最好时间复杂度是 ,是在分区及其均衡的情况下;最坏时间复杂度是 ,是在分区极不均衡的情况下;平均时间复杂度是 。
桶排序(Bucket sort),比较合适用在外部排序中。所谓的外部排序就是数据存储在外部磁盘中,数据量比较大,内存有限,无法将数据全部加载到内存中。
**计数排序(Counting sort)**其实是桶排序的一种特殊情况。当要排序的 n 个数据,所处的范围并不大的时候,比如最大值是 k,我们就可以把数据划分成 k 个桶。每个桶内的数据值都是相同的,省掉了桶内排序的时间。(900分和50万考生,时间复杂度是)。计数排序的时间复杂度都是。
计数排序只能用在数据范围不大的场景中,如果数据范围 k 比要排序的数据 n 大很多,就不适合用计数排序了。而且,计数排序只能给非负整数排序,如果要排序的数据是其他类型的,要将其在不改变相对大小的情况下,转化为非负整数。
基数排序(Radix sort)