插入排序是一个重要的排序算法,其思想类比于打扑克牌时候调整手牌的策略。
一、插入排序过程
大学本科期间在数据结构与算法课中,应该都学习过插入排序算法的过程与时间复杂度。下面简单来复习一下插入排序算法的过程与时间复杂度。
- 插入排序过程
假设对n个元素进行插入排序,则需要进行n-1趟排序。
示例代码如下所示,使用java书写的,可以很容易改为c代码和python代码,大家可以进行简单的调式深刻理解插入排序的过程。
public
从上面的过程我们可以看到,插入排序的过程分为两步:
- 首先和当前位置的前一个元素进行比较,如果前一个元素比当前元素大,则后续进行调整,将前面的大元素不断向后移动,并找到合适的位置将当前元素插入进去;
- 如果发现前一个元素比当前元素小,则不会进行调整,默认前面的元素已经有序。
这样的两步就是内循环和外循环,后续我们会有插入排序的正确性的证明,也是通过这样两步进行证明其正确性。
基于这样的过程我们很容易分心排序算法的最好情况和最坏情况。
- 最好情况:元素升序有序。那么我们只需要进行n-1次元素比较,0次元素移动即可。
- 最坏情况:元素降序有序。那么我们需要进行
次元素比较,同样次数的元素移动。
那么我们已经清楚了最好情况和最坏情况的时间复杂度,那么平均时间复杂度应该是什么量级呢?
二、插入排序算法时间复杂度分析
首先,分析平均时间复杂度,我们有两个假设的前提。
1. All permutation of the keys are equally likely as input.
2. Keys are distinct.
我们进行平均时间复杂度分析时,思路是:
分别求每趟排序的平均时间开销,再
小前提:因为移动次数小于比较次数,不是每个比较操作都会发生移动,因此我们将比较次数作为衡量算法时间复杂度的指标。
分析:
在插入下表为i的元素的时候(假设该元素为x),
接下来,我们将n-1趟结果进行加和,得到最终的平均时间复杂度。
因为lnn与n^2不是一个量级的,这样我们就可以知道,插入排序法的平均时间复杂度是
插入排序适合于小序列的排序,当序列长度小于等于20或20左右时,使用插入排序效率更高。
三、插入排序的性能分析
性能分析的目的是讨论是否有方法能对算法进行改进,以提高其平均时间复杂度。
接下来对插入排序进行性能分析:
插入排序的特点是:基于比较、数据移动完成排序
一次比较操作后不发生数据移动或仅仅交换一对相邻的数据元素。
我们的问题是,此类算法是否可以改进?
分析过程:
n个数据元素有n!个不同的排列组合序列。随机给一个序列
我们已知基于比较的排序算法,一次最多只能消除一对逆序关系,这样进一步我们可以知道有多少对逆序,至少需要多少次比较。
n个数据元素,降序有序,是最坏的逆序情况,逆序数量最多有n(n-1)/2个。所以,一个基于比较的排序算法,最坏情况下,最少需要n(n-1)/2次比较。所以最坏情况时间复杂度W(n)无法再改进了。
下面分析平均情况:
平均情况下,一个序列的逆序数量是不确定的,但是我们可以构造一个与原序列完全相反的序列,x1 =(2, 4, 1, 5, 3),x2 = (3, 5, 1, 4, 2)这两个序列总逆序的数量等于n(n-1)/2,则平均一个序列的逆序数量是n(n-1)/4个,那么平均情况也至少需要n(n-1)/4次比较操作,所以平均情况时间复杂度O(n)也没有将n^2降低的可能性。
定理
任何一个基于关键字的比较且每一次比较最多消除一个逆序的排序算法,最坏的情况下至少比较n(n-1)/2次,平均情况至少比较n(n-1)/4次。
四、算法分析及相关问题
算法的评价准则:
- 正确性:一般使用数学归纳法,证明对于每一个合法的输入,在有效时间内,算法都会给出一个满足要求的结果。
- 空间复杂度
- 时间复杂度
- 简单性、清晰性
- 优化
算法分析种常见的时间复杂性函数