计算模型
在能够分析算法之前,我们必须有一个要使用的实现技术的模型,包括描述所用资源及其代价的模型。对于本书的大多数章节,我们假定一种通用的单处理器计算模型——随机访问机(RAM)来作为我们的实现技术。在RAM模型中,指令是一条一条执行。
#插入排序算法的分析
一个算法在特定输入上的运行时间是指执行的基本操作数或步数。执行每行代码需要常量时间。虽然一行与另一行可能需要不同数量的时间,但是我们假设第i行的每次执行需要时间ci,其中ci是一个常量。
对于插入排序,对j=2,3,…,n,其中n=A.length,假设tj表示对那个值j第5行执行while循环测试的次数。当一个for或while循环按通常的方式(即循环头中的测试)退出时,执行测试的次数比执行循环体的次数要多1。

运行时间T[n]:
T(n)=c1n+c2(n−1)+c4(n−1)+c5j=2∑ntj+c6j=2∑n(tj−1)+c7j=2∑n(tj−1)+c8(n−1)
即使对给定规模的输入,一个算法的运行时间也可能依赖于给定的是该规模的哪种输入。对于插入排序,若输入数组已经有序,那么出现最好情况。此时tj=1,有
T(n)=c1n+c2(n−1)+c4(n−1)+c5(n−1)+c8(n−1) =(c1+c2+c4+c5+c8)n−(c1+c2+c4+c5+c8)
我们可以把该运行时间表示为an+b,其中常量a跟b依赖于语句代价ci。因此它是n的线性函数。
若输入数组是反向数组,那么出现最坏情况。此时tj=j,注意到:
j=2∑nj=2(2+n)(n−1) =2n(n+1)−1
或
j=2∑n(j−1)=2n(n−1)
所以
T(n)=(2c5+2c6+2c7)n2+(c1+c2+c4+2c5−2c6−2c7+c8)n−(c2+c4+c5+c8)
我们可以把该运行时间表示为an2+bn+c,其中常量a、b跟c依赖于语句代价ci。因此它是n的二次函数。
因此,插入排序的最好情况运行时间是线性函数,最坏情况运行时间是二次函数。
在分析算法时,我们往往只会集中求最坏情况运行时间,即对于规模为n的如何输入,算法的最长运行时间。
练习

答:略。

答:伪代码:
for j = 1 to A.length - 1
least = j
i = j + 1
while i <= A.length
if A[least] > A[i]
least = i
i = i + 1
temp = A[j]
A[j] = A[least]
A[least] = temp
把for循环每次开始,包含元素A[1..j−1]的数组称为子数组,它的循环不变式如下:
- 初始化:在第一次循环迭代之前(当j=1时),此时子数组没有元素。
- 保持:在每次循环开始时,在整个数组的剩余元素中找出最小的元素,放到子数组的末尾,所以在第n次迭代之前,此时子数组A[1..n−1],其中A[1]是整个数组的最小元素,A[2]是倒数第二小的元素,以此类推,直到n−1,所以子数组有序;然后进行本次迭代,找出A[n..a.length]中最小的元素跟A[n]交换,此时A[n]是数组中倒数第n小的元素,大于等于A[1..n−1]中的任何元素,所以在第n+1次迭代之前,子数组$A[1…n]有序。
- 终止:当j=A.length时,循环终止。此时子数组A[1..A.length−1]有序,且A[A.length]是最大的元素,所以整个数组有序,算法正确。
在排序时,每次都选出第N小的元素,在迭代进行都n-1个元素时,该元素是第n-1小,所以剩余的最后一个元素是第n小,也就是最大,所以整个数组已经有序,不再需要对最后一个元素进行排序。
根据伪代码可得:
T(n)=c1n+c2(n−1)+c3(n−1)+c4j=1∑n−1tj+c5j=1∑n−1(tj−1)+c6j=1∑n−1(tj−1)+c7j=1∑n−1(tj−1)+c8(n−1)+c9(n−1)+c10(n−1)
当数组有序,不需要执行least = i
语句,此时出现最好情况。
T(n)=(2c4+2c5+2c7)n2+(2c4−2c5−2c7+c1+c2+c3+c8+c9+c10)n−(c2+c3+c4+c8+c9+c10)
我们可以把该运行时间表示为an2+bn+c,其中常量a、b跟c依赖于语句代价ci。因此它是n的二次函数。
当数组逆向有序,每次都会执行least = i
语句,此时出现最坏情况。
T(n)=(2c4+2c5+2c6+2c7)n2+(2c4−2c5−2c6−2c7+c1+c2+c3+c8+c9+c10)n−(c2+c3+c4+c8+c9+c10)
可以得出结论,选择排序的最好情况运行时间和最坏情况运行时间都为Θ(n2)。

答:
平均需要检查输入序列(n+1)/2个元素,在最坏情况下需要检查n个元素。平均情况跟最坏情况的运行时间都为Θ(n)。
证明:根据平均查找长度公式
ASL=i=1∑npici
其中:pi为查找表中第i个数据元素的概率,ci为找到第i个数据元素时已经比较过的次数。
其平均查找长度为(n+1)/2。
若考虑元素不在数组中的情况,则平均需要检查输入序列n/2+n/(n+1)个元素
因为查找的过程就是关键字比较的过程,比较次数的多少就是算法的时间复杂度,所以平均情况跟最坏情况的运行时间都为Θ(n)。

答:可以在运行算法之前先检查输入是否是最好情况,如果是,则运行以最好情况条件下编写的算法,以获得最好的最好情况运行时间;如果不是,则运行普通的算法。如我们改变现在排序,我们先判断输入是否有序,如果已经有序,则直接返回,否则运行普通的选择排序。这样修改后,选择排序的最好情况运行时间为Θ(n)。