排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。
十种常见排序算法可以分为两大类,如下图所示。
- 比较类排序: 通过比较来决定元素间的相对次序,由于其时间复杂度不能突破 O ( n l o g n ) O(nlogn) O(nlogn),因此也称为非线性时间比较类排序。
- 非比较类排序: 不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。
常见排序算法简介如下表所示。
排序方法 | 最好时间复杂度 | 最坏时间复杂度 | 平均时间复杂度 | 辅助空间复杂度 | 稳定性 | 博客链接 |
---|---|---|---|---|---|---|
冒泡排序 | O ( n ) O(n) O(n) | O ( n 2 ) O(n^{2}) O(n2) | O ( n 2 ) O(n^{2}) O(n2) | O ( 1 ) O(1) O(1) | 稳定 | 冒泡排序算法 |
选择排序 | O ( n 2 ) O(n^{2}) O(n2) | O ( n 2 ) O(n^{2}) O(n2) | O ( n 2 ) O(n^{2}) O(n2) | O ( 1 ) O(1) O(1) | 不稳定 | 选择排序算法 |
插入排序 | O ( n ) O(n) O(n) | O ( n 2 ) O(n^{2}) O(n2) | O ( n 2 ) O(n^{2}) O(n2) | O ( 1 ) O(1) O(1) | 稳定 | 插入排序算法 |
折半插入排序 | O ( n ) O(n) O(n) | O ( n 2 ) O(n^{2}) O(n2) | O ( n 2 ) O(n^{2}) O(n2) | O ( 1 ) O(1) O(1) | 稳定 | 折半插入排序算法 |
希尔排序 | – | – | – | O ( 1 ) O(1) O(1) | 不稳定 | 希尔排序算法 |
快速排序 | O ( n l o g n ) O(nlogn) O(nlogn) | O ( n 2 ) O(n^{2}) O(n2) | O ( n l o g n ) O(nlogn) O(nlogn) | O ( n ) O(n) O(n) | 不稳定 | 快速排序算法 |
归并排序 | O ( n l o g n ) O(nlogn) O(nlogn) | O ( n l o g n ) O(nlogn) O(nlogn) | O ( n l o g n ) O(nlogn) O(nlogn) | O ( n ) O(n) O(n) | 稳定 | 归并排序算法 |
堆排序 | O ( n l o g n ) O(nlogn) O(nlogn) | O ( n l o g n ) O(nlogn) O(nlogn) | O ( n l o g n ) O(nlogn) O(nlogn) | O ( 1 ) O(1) O(1) | 不稳定 | 堆排序算法 |
计数排序 | O ( n + k ) O(n+k) O(n+k) | O ( n + k ) O(n+k) O(n+k) | O ( n + k ) O(n+k) O(n+k) | O ( k ) O(k) O(k) | 稳定 | 计数排序算法 |
桶排序 | O ( n + k ) O(n+k) O(n+k) | O ( n + k ) O(n+k) O(n+k) | O ( n 2 ) O(n^{2}) O(n2) | O ( n + k ) O(n+k) O(n+k) | 稳定 | 桶排序算法 |
基数排序 | O ( n × k ) O(n \times k) O(n×k) | O ( n × k ) O(n \times k) O(n×k) | O ( n × k ) O(n \times k) O(n×k) | O ( n + k ) O(n+k) O(n+k) | 稳定 | 基数排序算法 |
结论: 1. 当初始序列基本有序时,直接插入排序最快,快速排序慢(在初始序列较为混乱时快);
2. 归并排序对初始序列排序不敏感,速度稳定;
3. 记录个数较少,采用插入排序或选择排序,记录本身信息量大,采用简单选择排序;
4. 记录较大,采用快速排序、堆排序、归并排序。
各种排序算法的主要思想总结:
- 冒泡排序: 通过交换使相邻的两个数变成小数在前大数在后,这样每次遍历后,最大的数就“沉”到最后面了,重复 N 次即可以使数组有序。
- 选择排序: 数组分成有序区和无序区,初始时整个数组都是无序区,然后每次从无序区选一个最小的元素直接放到有序区的最后,直到整个数组变有序区。
- 插入排序: 每次将一个待排序的数据,插入到前面已经排好序的序列之中,直到全部数据插入完成。
- 希尔排序: 先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的),分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。由于希尔排序是对相隔若干距离的数据进行直接插入排序,因此可以形象的称希尔排序为“跳着插”。
- 归并排序: 当一个数组左边有序,右边也有序,那合并这两个有序数组就完成了排序。如何让左右两边有序了?用递归!这样递归下去,合并上来就是归并排序。
- 快速排序: “挖坑填数+分治法”, 首先令
i =Left; j = Right;
将a[i]
挖出形成第一个坑,称a[i]
为基准数。然后j--
由后向前找比基准数小的数,找到后挖出此数填入前一个坑a[i]
中,再i++
由前向后找比基准数大的数,找到后挖出此数填到前一个坑a[j]
中,重复进行这种“挖坑填数”直到i==j
。再将基准数填入a[i]
中,这样i
之前的数都比基准数小,i
之后的数都比基准数大,因此将数组分成两部分再分别重复上述步骤就完成了排序。 - 堆排序: 一种利用堆的概念来排序的选择排序,把未排序的数据一个一个放入堆里进行调整,然后再一个一个取出来。