插入排序

本文详细介绍了插入排序算法的工作原理,包括其基本步骤、循环不变式的概念及其正确性的证明,并通过具体实例展示了排序过程。同时,文章还分析了插入排序的时间复杂度,尤其是在最好情况和最坏情况下的表现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

插入排序

  • 插入排序

输入:n个数的一个序列(a1,a2,...,an)

输出:输入序列的一个排列(a1',a2',...,an'),满足a1'<=a2'<=...<=an'

 

 

对于少量的元素的排序,它是一个有效的算法。插入排序的工作方式像排序一手扑克牌。如下图。



 

 INSERTION-SORT

参数:一个数组A[1...n],包含长度为n的要排序的一个序列。

 

 INSERTION-SORT(A)

 

1 for j = 2 to A.length
2     key = A[j]
3     //Insert A[j] into the sorted sequence A[1...j-1]。
4     i = j -1;
5     while i > 0 and A[i] > key
6     A[i + 1] = A[i]
7     i = i - 1
8     A[i + 1] = key
 

 

循环不变式与插入排序的正确性

如图2-2表明对A=(5,2,4,6,1,3)该算法如何工作。下标 j 指出正被插入到手中的“当前牌”。在for循环(循环变量为 j)的每次迭代的开始,包含元素A[1...j-1]的子数组构成了当前排序好的左手牌,剩余的子数组A[j-1...n]并未排序。元素A[1..j-1]还是原来位置1到j-1的元素,只是已经按顺序排列好了。我们把A[1..j-1]的这些性质形式的表示为一个循环不变式

      在1-8行的 for 循环的每次迭代开始时,子数组A[1..j-1]由原来在A[1..j-1]中的元素组成,但已按序排列。



 

循环不变式的三条性质:

初始化:循环的第一次迭代之前,它为真。

保持:如果循环的某次迭代之前它为真,那么下次迭代之前它仍为真。

终止在循环终止时,不变式为我们提供一个有用的性质,该性质有助于证明算法是正确的

 

  • 插入排序的算法分析

过程 INSERTION-SORT需要的时间依赖于输入:排序1000个数比3个需要更长的时间。此外根据他们已经被排序的程度, INSERTION-SORT需要不同长短的时间来排序两个相同规模的输入序列。一般情况下,算法需要的时间与输入的规模同步增长,所以通常把一个程序的运行时间描述成输入规模的函数。
 
输入规模:依赖于所研究的问题。对于排序问题,输入规模指的是输入的项数。对于两个数相乘的问题,输入规模指的是二进制记号表示输入所需的总位数。(个人理解为两个数的大小)
 
输入运行时间:执行的基本操作数或步数。
 
首先给出过程INSERTION-SORT中,每条语句的执行时间和执行次数。对j = 2,3,...,n,其中n = A.length,假设 tj 表示对那个值 j 第5行执行while循环测试的次数。当一个for或while循环按照通常的方式退出时,执行测试的次数比循环体的次数多1。
INSERTION-SORT(A)                                                     代价         次数
1 for j = 2 to A.length                                                        c1             n
2     key = A[j]                                                                    c2            n - 1
3     //Insert A[j] into the sorted sequence A[1...j-1]。       0              n - 1
4     i = j -1;                                                                        c4            n - 1
5     while i > 0 and A[i] > key                                            c5            ∑tj  
( n,j=2)
6     A[i + 1] = A[i]                                                              c6           
∑tj ( n-1,j=2)
7     i = i - 1                                                                        c7            ∑tj ( n-1,j=2)
8     A[i + 1] = key                                                              c8           n - 1
 该算法的运行时间是执行每条语句的时间总和。

 即使对于给定规模的输入,一个算法的运行时间也可能依赖于给定的是该规模下的哪个输入。例如在
INSERTION-SORT中,若数组已经排好序,则出现最佳的情况。这是对于每个j=2,3,...n,我们发现第5行,当i取其初值j - 1时,有A[i]<=key,从而对 j=2,3,...n,有tj = 1,该最佳情况的运行时间为:

 
我们可以把该运行时间表示为an+b,其中常量a和b依赖于语句代价ci。因此,它是n的线性函数。
若输入数组已反向排序,即按递减序排好序,则导致最坏情况。我们必须将每个元素A[j]与整个已排序子数组A[1,...,j-1]中的每个元素进行比较,所以对 j=2,3,...n,有tj = j。注意到

 和

 我们发现在最坏的情况下,INSERTION-SORT的运行时间为

 我们可以把最坏情况的运行时间表示为an²+bn+c,其中常量a,b和c又依赖于语句代价ci。因此,它是n的二次函数。
实际中,对于输入时间,我们更多考虑的是最坏情况所消耗的时间。
事实上,我们真正感兴趣的是运行时间的增长率或增长量级。所以我们只考虑公式中的最重要的项(例如 an²)。因为当n取很大的值时,低阶项相对来说不重要。我们也会忽略重要的项的常项系数。因为对大的输入,在计算效率时常量因子不如增长率重要。对于插入排序具有最坏情况的运行时间为Θ(n²)。
 
如果一个算法的最坏情况运行时间具有比另外一个算法更低的增量级,那么我们通常认为前者比后者更有效。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值