|
| 1 | +### 本文罗列八大排序的复杂度、稳定性,并相互对比。 |
| 2 | +*** |
| 3 | +### 一、**冒泡排序**: |
| 4 | + |
| 5 | +### 时间复杂度: |
| 6 | +#### 若文件的初始状态是正序的,一趟扫描即可完成排序。所需的关键字比较次数C和记录移动次数M均达到最小值:Cmin = N - 1, Mmin = 0。所以,冒泡排序最好时间复杂度为O(N)。 |
| 7 | +#### 若初始文件是反序的,需要进行 N -1 趟排序。每趟排序要进行 N - i 次关键字的比较(1 ≤ i ≤ N - 1),且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值: |
| 8 | +##### Cmax = N(N-1)/2 = O(N2) |
| 9 | +##### Mmax = 3N(N-1)/2 = O(N2) |
| 10 | +##### 冒泡排序的最坏时间复杂度为O(N2)。 |
| 11 | +##### 因此,冒泡排序的平均时间复杂度为O(N2)。 |
| 12 | +### 算法稳定性: |
| 13 | +#### 冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。 |
| 14 | +*** |
| 15 | +### 二、**简单选择排序**: |
| 16 | +### 性能表: |
| 17 | + |
| 18 | +### 时间复杂度: |
| 19 | +#### 简单选择排序的比较次数与序列的初始排序无关。 假设待排序的序列有 N 个元素,则比较次数总是N (N - 1) / 2。 |
| 20 | +#### 而移动次数与序列的初始排序有关。当序列正序时,移动次数最少,为 0. |
| 21 | +#### 当序列反序时,移动次数最多,为3N (N - 1) / 2。 |
| 22 | +#### 所以,综合以上,简单排序的时间复杂度为 O(N2)。 |
| 23 | +### 空间复杂度: |
| 24 | +#### 简单选择排序需要占用 1 个临时空间,在交换数值时使用。 |
| 25 | +*** |
| 26 | +### 算法稳定性: |
| 27 | +#### 举个栗子: |
| 28 | +#### 序列5 8 5 2 9, 我们知道第一遍选择第1个元素5会和2交换搜索,那么原序列中2个5的相对前后顺序就被破坏了,所以选择排序不是一个稳定的排序算法 |
| 29 | +### 三、**直接插入排序**: |
| 30 | +### 性能表: |
| 31 | + |
| 32 | +### 时间复杂度: |
| 33 | +#### 当数据正序时,执行效率最好,每次插入都不用移动前面的元素,时间复杂度为O(N)。 当数据反序时,执行效率最差,每次插入都要前面的元素后移,时间复杂度为O(N2)。所以,数据越接近正序,直接插入排序的算法性能越好。 |
| 34 | +### 空间复杂度: |
| 35 | +#### 由直接插入排序算法可知,我们在排序过程中,需要一个临时变量存储要插入的值,所以空间复杂度为 1 。 |
| 36 | +### 算法稳定性: |
| 37 | +#### 直接插入排序的过程中,不需要改变相等数值元素的位置,所以它是稳定的算法。 |
| 38 | +### 四、**希尔排序**: |
| 39 | +### 性能表: |
| 40 | +  |
| 41 | +### 时间复杂度: |
| 42 | +#### 步长的选择是希尔排序的重要部分。只要最终步长为1任何步长序列都可以工作。 |
| 43 | +#### 算法最开始以一定的步长进行排序。然后会继续以一定步长进行排序,最终算法以步长为1进行排序。当步长为1时,算法变为插入排序,这就保证了数据一定会被排序。 |
| 44 | +#### Donald Shell 最初建议步长选择为N/2并且对步长取半直到步长达到1。虽然这样取可以比O(N2)类的算法(插入排序)更好,但这样仍然有减少平均时间和最差时间的余地。可能希尔排序最重要的地方在于当用较小步长排序后,以前用的较大步长仍然是有序的。比如,如果一个数列以步长5进行了排序然后再以步长3进行排序,那么该数列不仅是以步长3有序,而且是以步长5有序。如果不是这样,那么算法在迭代过程中会打乱以前的顺序,那就不会以如此短的时间完成排序了。 |
| 45 | + |
| 46 | +#### 已知的最好步长序列是由Sedgewick提出的(1, 5, 19, 41, 109,...),该序列的项来自这两个算式。 |
| 47 | +#### 研究也表明"比较在希尔排序中是最主要的操作,而不是交换。"用这样步长序列的希尔排序比插入排序和堆排序都要快,甚至在小数组中比快速排序还快,但是在涉及大量数据时希尔排序还是比快速排序慢。 |
| 48 | +### 算法稳定性: |
| 49 | +#### 希尔排序中相等数据可能会交换位置,所以希尔排序是不稳定的算法。 |
| 50 | +*** |
| 51 | +### 五、**快速排序**: |
| 52 | +### 性能表 |
| 53 | + |
| 54 | +### 时间复杂度: |
| 55 | +#### 当数据有序时,以第一个关键字为基准分为两个子序列,前一个子序列为空,此时执行效率最差。而当数据随机分布时,以第一个关键字为基准分为两个子序列,两个子序列的元素个数接近相等,此时执行效率最好。所以,数据越随机分布时,快速排序性能越好;数据越接近有序,快速排序性能越差。 |
| 56 | +### 空间复杂度: |
| 57 | +#### 快速排序在每次分割的过程中,需要 1 个空间存储基准值。而快速排序的大概需要 Nlog2N次 的分割处理,所以占用空间也是 Nlog2N 个。 |
| 58 | +### 算法稳定性: |
| 59 | +#### 在快速排序中,相等元素可能会因为分区而交换顺序,所以它是不稳定的算法。 |
| 60 | +### 六、**堆排序**: |
| 61 | +### 性能表: |
| 62 | + |
| 63 | +### 时间复杂度: |
| 64 | +#### 堆的存储表示是顺序的。因为堆所对应的二叉树为完全二叉树,而完全二叉树通常采用顺序存储方式。 |
| 65 | +#### 当想得到一个序列中第k个最小的元素之前的部分排序序列,最好采用堆排序。 |
| 66 | +#### 因为堆排序的时间复杂度是O(n+klog2n),若k≤n/log2n,则可得到的时间复杂度为O(n)。 |
| 67 | +### 算法稳定性: |
| 68 | +#### 一种不稳定的排序方法 |
| 69 | +#### 因为在堆的调整过程中,关键字进行比较和交换所走的是该结点到叶子结点的一条路径, |
| 70 | +#### 因此对于相同的关键字就可能出现排在后面的关键字被交换到前面来的情况。 |
| 71 | +### 七、** 归并排序**: |
| 72 | +### 性能表 |
| 73 | + |
| 74 | +### 时间复杂度: |
| 75 | +#### 归并排序的形式就是一棵二叉树,它需要遍历的次数就是二叉树的深度,而根据完全二叉树的可以得出它的时间复杂度是O(n*log2n)。 |
| 76 | +### 空间复杂度 |
| 77 | +#### 由前面的算法说明可知,算法处理过程中,需要一个大小为n的临时存储空间用以保存合并序列。 |
| 78 | +### 算法稳定性 |
| 79 | +#### 在归并排序中,相等的元素的顺序不会改变,所以它是稳定的算法。 |
| 80 | +### 七、** 基数排序**: |
| 81 | +### 性能表 |
| 82 | + |
| 83 | +### 时间复杂度 |
| 84 | +#### 通过上文可知,假设在基数排序中,r为基数,d为位数。则基数排序的时间复杂度为O(d(n+r))。 |
| 85 | +#### 可以看出,基数排序的效率和初始序列是否有序没有关联。 |
| 86 | +### 空间复杂度 |
| 87 | +#### 在基数排序过程中,对于任何位数上的基数进行"装桶"操作时,都需要n+r个临时空间。 |
| 88 | +### 算法稳定性 |
| 89 | +#### 在基数排序过程中,每次都是将当前位数上相同数值的元素统一"装桶",并不需要交换位置。所以基数排序是稳定的算法。 |
| 90 | +*** |
| 91 | +## 比较: |
| 92 | +### (1)直接插入排序和希尔排序的比较: |
| 93 | +#### 直接插入排序是稳定的;而希尔排序是不稳定的。 |
| 94 | +#### 直接插入排序更适合于原始记录基本有序的集合。 |
| 95 | +#### 希尔排序的比较次数和移动次数都要比直接插入排序少,当N越大时,效果越明显。 |
| 96 | +#### 在希尔排序中,增量序列gap的取法必须满足:最后一个步长必须是 1 。 |
| 97 | +#### 直接插入排序也适用于链式存储结构;希尔排序不适用于链式结构。 |
| 98 | +### (2)归并排序和堆排序、快速排序的比较 |
| 99 | +#### 若从空间复杂度来考虑:首选堆排序,其次是快速排序,最后是归并排序。 |
| 100 | +#### 若从稳定性来考虑,应选取归并排序,因为堆排序和快速排序都是不稳定的。 |
| 101 | +#### 若从平均情况下的排序速度考虑,应该选择快速排序。 |
| 102 | + |
| 103 | + |
0 commit comments