![1c3fefcb4593e2aca9057956b5d72568.png](https://i-blog.csdnimg.cn/blog_migrate/ef28775a7b07eca961685f987023cf64.png)
简介
插入排序和比较排序是排序算法中比较基础和简单的两种,其时间复杂度均为
我之前的文章 排序算法详解 里给出了几个基本排序算法的JavaScript版本实现,感兴趣的也可以移步。
空间复杂度
插排和选排的均在交换时使用了一个临时空间,其空间复杂度均为
- 插排从无序列表中取第一个数,与有序列表的数依次比较,有序列表的已排数据的位置均可能发生变化。
- 选排从无序列表中取最小数,只和无序列表中第一个数交换,此时无序列表第一个数归于有序列表(相当于最后一个数)。
在每一轮排序过程中,均需要有一个临时空间用来存储无序列表提取的这一个数,用于未来的交换。
时间复杂度
众所周知,插排和选排的时间复杂度均为
比较复杂度对比
- 插入排序
- 最差情况:最差情况下反向有序,每一轮插入,都需要依次比较到有序列表的第一个数,第一轮比较0次,第二轮比较1次,第N轮比较N-1次。一共比较
次,复杂度
- 最好情况:最好情况下有序,每一轮插入,都只需要比较1次,一共比较
次,复杂度
- 平均情况:平均情况下,每一轮插入,假设依次比较到有序列表的中间位置,一共比较
次,复杂度
- 最差情况:最差情况下反向有序,每一轮插入,都需要依次比较到有序列表的第一个数,第一轮比较0次,第二轮比较1次,第N轮比较N-1次。一共比较
- 选择排序选择排序比较次数是固定的,每一轮都需要从待排序的无序列表中选取一个最小(或最大)的数,选取中都需要比较到最后一个元素才能得到结果。第一轮比较N-1次,第N轮比较0次。一共比较
次,复杂度
因此可以得出结论:在最差情况下,两者复杂度一样。在最好情况下,两者复杂度差异是比较大的(1个次方),而在平均情况下,插排的比较次数也只是选排的一半。这也是关于插排和选排的通用结论,一般情况下插排优于选排,主要就在于插排是插入有序列表,而选排是需要在无序列表中选择一个最大值(或最小值),想象一下我们斗地主摸牌,摸到一张牌我们是可以马上从小到大判断插入到哪的(这里假设只能从小到大比较),而不必每一张牌都对比一下。
但是上面的结论只讨论了比较复杂度,其实在为什么说平均情况下,插入排序比选择排序快? - 莫涛的回答 - 知乎 和Stack Overflow上,也有人对这种回答中不谈交换表示疑惑,下面我们再来分析一下交换复杂度。
交换复杂度对比
- 插入排序
- 最差情况:每一次比较完都需要交换。第一轮交换0次,第二轮交换1次,第N轮交换N-1次。一共交换
次,复杂度
- 最好情况:每一次比较完都无需交换,总共交换
次,复杂度
- 平均情况:每一轮都插入到中间位置,总共交换次数为
次,复杂度
- 最差情况:每一次比较完都需要交换。第一轮交换0次,第二轮交换1次,第N轮交换N-1次。一共交换
- 选择排序
- 最差情况:每一轮都需要交换,总共交换
次,复杂度
- 最好情况:每一轮都无需交换,总共交换
次,复杂度
- 平均情况:有一半轮次需要交换,总共交换
次,复杂度
- 最差情况:每一轮都需要交换,总共交换
交换复杂度的对比中我们可以得出:最好情况下两者都无需交换,然而在最差和平均情况下,插入排序的交换次数都高于选择排序,差异为一个次方。可以看出差异还是很大的,单从这样来看,是无法忽略其影响的。
影响时间复杂度的其他因素
其实,在《算法导论》一书中还提到了一个算法性能分析依赖的以下要素:
- 待排项数
- 这些项已排序程度
- 项值的限制
- 计算机体系结构
- 使用的存储设备种类(主存,磁盘或磁带)
回到这个例子中,我们可以假设忽略硬件的影响、项值无限制。而已排序程度随机(也就是选用平均复杂度,不过一般算法分析都采用最坏情况下的复杂度作为瓶颈进行分析),因此分析要素只剩下待排项数N,可以使用上面的分析给出结论。
结论
插入排序和比较排序谁更优?主要在于比较开销和交换开销的量级:
- 如果两者量级相当,则插入排序优于选择排序
- 如果比较开销量级小于交换开销,则选择排序优于插入排序
- 如果比较开销量级大于交换开销,如果差别不大则难以比较,如果差异较大,则可以忽略交换复杂度,此时插入排序优于选择排序
事实上,交换一般直接交换内存地址(指针)而不是交换真实的数据,而比较则需要CPU的一些运算。这里的一个回答便给出了自定义赋值函数,如果直接交换数据,当数据量过大,交换开销大大增加,此时插入排序反而不如选择排序,因为其交换次数平均情况下和选择排序不在一个量级。
当然,由于交换排序进行了过多的交换次数(也就是写操作),如果使用Flash Memory,则需要额外注意,因为Flash Memory的擦除次数有限,过多的写操作会消耗其擦除次数,从而消耗Flash Memory的寿命。
总结 & 参考
一般情况下,插入排序确实优于选择排序,但也有需要注意的点,而不单单是只判断比较复杂度那么简单。需要我们了解清楚再做判断。
文章参考了以下资料:
- Insertion Sort vs. Selection Sort
- 为什么说平均情况下,插入排序比选择排序快? - 知乎
- When should one use Insertion vs. Selection sort?