2.1 插入排序
插入排序的思想:
把列表分成一个有序列表和一个无序列表,每次选取无序列表中的第一个元素,并插入到有序列表的相应位置。
练习
2.1-3:
循环不变式:在A[1...i-1]中不存在v。
初始化:在第一次迭代之前,i=1,A[1...0]中没有任何元素,成立。
保持:由于在程序中只要发现v(A[i] == v)就立即退出循环,在这种情况下,下次迭代之前很明显A[1...i-1]中不存在v,成立;如果没有发现v则i自增1,下一次迭代之前依然成立。
终止:最后i=length(A)+1,此时A[1...length(A)],这说明整个数组不存在v。
2.1-4:
形式化描述:
输入:
n位二进制数<a1, a2, ..., an>;
n位二进制数<b1, b2, ..., bn>;
输出:上述两个二进制数之和,保存在序列C中。
伪代码:
up = 0
for i = length[A] to 1
do sum = A[i] + B[i] + up
if sum > 1
up = 1
else
up = 0
C[i+1] = sum mod 2
if up == 1 // note: it's impossible that up is larger than one
C[i+1] = up
2. 2 算法分析
练习
2. 2-2:
伪代码:
SELECTIONS-SORT(A)
for i = 1 to length(A)-1
do max = i
for j = i to length(A)
if A[j] > A[max]
max = j
swap(A[i], A[max])
循环不变式:A[1...i-1]是排好序的。
选择排序的思想和插入排序本质上是相同的,也是把一个列表分成一个有序列表和一个无序列表,只不过这次是每次取出无序列表的最小值放到有序列表当中,换句话说,它与插入排序的不同之处就在于它填充有序列表(减少无序列表)的方式不同。
循环结束时i = length(A) = n,此时有序列表A[i...n-1]是排好序的,无序列表A[n-1...n]只剩下一个元素,也是排好序的,并且它在循环当中从没有被选成最小值过,所以它是整个列表的最大值,所以它只需要在头n-1个元素上运行。
选择排序由于不管什么情况都会每次得到无序列表的最小值并且进行交换,所以其最坏情况和最佳情况的差别仅仅在于max = j这行的执行次数而已,但它无关紧要,所以它们的运行时间都是:theta(n^2)。
2.2 -4:
最佳运行时间与常数项的关系密切,所以应该尽量减少常数项之和的大小。