零、前言
1、常用的排序算法总结
排序算法种类 | 时间复杂度 | 是否基于比较 |
冒泡、插入、选择 | O(n^2) | √ |
快排、归并 | O(nlogn) | √ |
桶、计数、基数 | O(n) | × |
2、算法的内存消耗 - 原地排序
指的是空间复杂度是 O(1) 排序算法。
4、算法的稳定性
原来序列中相等的元素,经过排序之后,相等元素之间原有的先后顺序不变。
一、冒泡排序
1、原地排序?
属于原地排序算法。冒泡排序仅仅数据交换用到了交换操作,只需常量级的临时空间,空间复杂度为O(1)。
2、稳定性排序?
属于稳定排序算法。为了实现稳定排序,只需要保证在比较时发现相等时不交换数据即可,故。
3、时间复杂度
(1)最好的情况
待排序的数据已有序,则只需进行一次冒泡排序即可,时间复杂度为 O(1) 。
(2)最坏的情况
待排序的数据是倒序,则需要 n 次冒泡排序,时间复杂度为 O(n^2) 。具体的计算公式看下面网址:https://blog.csdn.net/itworld123/article/details/90766948
(3)平均时间复杂度
对于最好的情况,需要交换 0 次,针对最坏的情况,需要交换 n(n-1)/2,因为数据排布具有随机性,故交换次数的平均值为 n(n-1)/4,时间复杂度依然为 O(n^2) 。
二、插入排序
1、原理
将待排序的数列分成两组,分别是已排序部分和未排序部分。排序的过程就是将未排序中的数据逐一与已排序的数据进行比较,将该数据插入到已排序的数列中。
2、原地排序?
属于原地排序算法。根据代码,插入排序过程中不需要额外的空间,空间复杂度为 O(1) 。
3、稳定性排序?
属于稳定排序算法。为了实现稳定性排序,可以将后面数据插入到前面与之相同的数据的后面即可。
4、时间复杂度
(1)最好的情况
待排序的数据已有序,每个元素进行一次比较即可,时间复杂度为 O(1) 。
(2)最坏的情况
待排序的数据是倒序,则:
第 2 个数据和第 1 个数据比较,比较 1 次;
第 3 个数据和第1、2个数据比较,比较 2 次;
第 4 个数据和第1、2、3个数据比较,比较 3 次;
…… ……
第 n 个数据和第1、2、3、……、(n-1) 个数据比较,比较 (n-1) 次;
比较次数和为 n(n-1)/2,时间复杂度为 O(n^2) 。
(3)平均时间复杂度
由于数据排布具有随机性,故平均时间复杂度为 O(n^2) 。
三、选择排序
1、原理
和插入排序类似,也是将数列分成了已排序部分和未排序部分,但是选择排序算法是从未排序部分选择最小值和当前数据进行交换。
2、原地排序?
属于原地排序算法。根据代码,选择排序过程中不需要额外的空间,空间复杂度为 O(1) 。
3、稳定性排序?
不属于稳定排序算法。因为存在大量的交换,容易导致在交换过程中相同的两个数据前后位置发生变化。
栗子:5、8、5、2、9
比较时,“5”和“2”会调换位置,那么两个“5”的原来的位置就颠倒了。
4、时间复杂度
(1)最好的情况
待排序的数据已有序,每个元素进行一次比较即可,时间复杂度为 O(1) 。
(2)最坏的情况
待排序的数据是倒序,则:
第 1 个数据和第 2、3、……、n 个数据比较,比较 (n-1) 次;
第 2 个数据和第 3、4、……、n 个数据比较,比较 (n-2) 次;
第 3 个数据和第 4、5、……、n 个数据比较,比较 (n-3) 次;
…… ……
第 (n-1) 个数据和第 n 个数据比较,比较 1 次;
比较次数和为 n(n-1)/2,时间复杂度为 O(n^2) 。
(3)平均时间复杂度
由于数据排布具有随机性,故平均时间复杂度为 O(n^2) 。
四、插入比冒泡更受欢迎的原因
因为冒泡排序中每次交换需要 3 条赋值语句,而插入排序则仅仅需要1次。
#define SWAP(x, y) \
do \
{ \
(x) ^= (y); \
(y) ^= (x); \
(x) ^= (y); \
} while (false)
五、总结
1、性质
算法种类 | 时间复杂度 | 空间复杂度 | 原地排序 | 稳定排序 |
冒泡排序 | O(n^2) | O(1) | √ | √ |
插入排序 | O(n^2) | O(1) | √ | √ |
选择排序 | O(n^2) | O(1) | √ | × |
2、源代码
(SAW:Game Over!)