插入排序
-
插入排序
输入: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中,每条语句的执行时间和执行次数。对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)
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的线性函数。

即使对于给定规模的输入,一个算法的运行时间也可能依赖于给定的是该规模下的哪个输入。例如在 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的二次函数。

和

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

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