2.1-1
初始 31 41 59 26 41 58
第一遍 31 41 59 26 41 58
第二遍 31 41 59 26 41 58
第三遍 26 31 41 59 41 58
第四遍 26 31 41 41 59 58
第五遍 26 31 41 41 58 59
2.1-2
把顺序改成非递增只要把判断大小时的条件改成小于即可
Insertion-Sort(A) for j = 2 to A.length key = A[j] i = j - 1 while i > 0 and A[i] < key A[i + 1] = A[i] i = i - 1 A[i + 1] = key
2.1-3
Linear-Search(A, v) for i = 1 to A.length if A[i] == v return i return NIL
2.1-4
Input: 两个n比特序列 $A = \{ a_1, a_2, …, a_n \}$ $B = \{ b_1, b_2, …, b_n \}$
Output: 一个n+1比特序列 $C = \{ c_1, c_2, …, c_{n+1} \}$ 使得等式 $(c_{n+1} c_n…c_2 c_1)_2 = (a_n a_{n-1}…a_2 a_1)_2 + (b_n b_{n-1}…b_2 b_1)_2$ 成立
利用全加器的逻辑位运算可以简单得到每一位的结果和进位。
Binary-Addition(A, B) inc = 0 i = 1 while i <= A.length k = A[i] xor B[i] g = A[i] and B[i] C[i] = k xor inc inc = inc and k or g i = i + 1 C[i] = inc return C
2.2-1
$\Theta (n^3)$
2.2-2
Selection-Sort(A) for i = 1 to A.length - 1 min = i for j = i + 1 to A.length if A[j] < A[min] min = j tmp = A[min] A[min] = A[i] A[i] = tmp
2.2-3
第i个元素为所找元素需要的比较次数为i
如果每个元素被找的几率相同且必定查找成功的时候,平均比较次数 $c = (1 + 2 + ... + n)/n = (n+1)/2$
当元素不存在或者是最后一个元素的时候需要比较的次数最多,为n次。
平均和最坏时间复杂度都是 $\Theta (n)$
2.2-4
当输入有可能就是结果(比如排序)或者能够直接算出的情况(比如全零矩阵相乘),直接输出结果。
2.3-1
[3 9 26 38 41 49 52 57] [3 26 41 52] [9 38 49 57] [3 41] [26 52] [38 57] [9 49] [3] [41] [52] [26] [38] [57] [9] [49]
2.3-2
Merge(A, p, q, r) n1 = q - p + 1 n2 = r - q let L[1..n1] and R[1..n2] be new arrays for i = 1 to n1 L[i] = A[p + i - 1] for j = 1 to n2 R[i] = A[q + j] i = 1, j = 1, k = p while i <= n1 and j <= n2 if L[i] <= R[j] A[k] = L[i] i = i + 1 else A[k] = R[j] j = j + 1 k = k + 1 while i <= n1 A[k] = L[i] i = i + 1 k = k + 1 while j <= n2 A[k] = R[j] j = j + 1 k = k + 1
2.3-3
当n=2时, $T(n) = 2 * \lg 2 = 2$ 满足;
假设当n=k时有 $T(k) = k * \lg k $ ,
那么当n=2k时有
$\eqalign{ T(2k) & = 2 T(k) + 2k \\ & = 2k \lg k + 2k \\ & = 2k \lg k + 2k \lg 2 \\ & = 2k \lg {2k} }$
得证。
2.3-4
Insertion-Sort(A, n) if n > 1 Insertion-Sort(A, n - 1) i = n - 1 key = A[n] while i > 0 and A[i] > key A[i + 1] = A[i] i = i - 1 A[i + 1] = key
2.3-5
Binary-Search(A, v) low = 1, high = A.length while low <= high mid = (low + high) / 2 if A[mid] == v return mid else if A[mid] < v low = mid + 1 else high = mid - 1 return NIL假设循环开始前序列的长度为k,循环之后长度至多为 $\lfloor k/2 \rfloor$,每次比较大小花费常数时间,
2.3-6
不可以,因为虽然每次查找的时间复杂度为 $\Theta (\lg n)$ 但是把元素放到正确的位置仍然需要移动同样多的元素,所以复杂度没有变化,在n比较大的时候系数可能会变小一点。
2.3-7
Sum-Exist(A, x) Merge-Sort(A) low = 1, high = A.length while low < high sum = A[low] + A[high] if sum == x return true else if sum > x high = high - 1 else low = low + 1 return false
2-1
a. 每个子序列的元素数量为k,最差的情况下需要进行$k(k-1)/2$次基础操作,一共有$n/k$个子序列,所以总的基础操作次数为 $$\frac {n} {k} * \frac {k(k-1)} {2} = \frac {n(k-1)} {2} = \Theta (nk)$$ b. 每一遍归并都对所有元素进行拷贝,所以单次复杂度为$\Theta (n)$,而将n/k组子序列归并为一个序列最多需要$\lg {\lfloor n/k \rfloor}$次,所以总的时间复杂度为$\Theta (n \lg {n/k} )$
c. 由前两问的结果可知,复杂度为$\Theta (nk + n \lg {n/k})$。要找到最大的k就应该使得$\Theta (nk)$和$\Theta (n \lg {n/k} )$的增长率相等,这时$k = \lg n$,即
$$\Theta (n \lg n + n \lg {\frac {n} {\lg n}}) = \Theta (2n \lg n - n \lg {\lg n}) = \Theta (n \lg n)$$ d. 实际应用上k应该选取使得插入排序和归并排序运行时间相同时的输入规模,充分发挥插入排序常数系数小的优势。
2-2
a. 需要证明最终的序列是非递减的,还需要证明最终序列是原序列的一种排列。
b.
2-3
a. 循环中的运算可以在常量时间内完成,所以复杂度是$\Theta (1)$,循环次数为n,所以总的时间复杂度为$\Theta (n)$。
b.
Evaluate-Polynomial(A, x, n) y = 0 for k = 0 to n t = 1 for i = 1 to k t = t * x; y = y + A[k] * t return y两重循环内的乘法运算次数最多,总数为 $$\sum_{k=0}^n {k} = \frac {n(n-1)} {2}$$ 所以时间复杂度为$\Theta (n^2)$,效率低于霍纳法则(Horner's Rule)。
2-4
a. (8, 6) (2, 1) (3, 1) (8, 1) (6, 1)
b. 拥有逆序数最多的是 $\{n, n-1, \cdots, 3, 2, 1 \}$,其中任意两个数之间都是逆序的,所以总计$n(n-1)/2$个。
c. 逆序数应该与元素移动的数量相同。插入排序每次移动元素都将一个较大的数移到较小的数后面,使得总逆序数减少1,而排序完成后逆序数是0,所以开始的逆序数和元素移动的次数相同。
d.
Merge-Inversion(A, p, q, r) n1 = q - p + 1 n2 = r - q let L[1..n1] and R[1..n2] be new arrays for i = 1 to n1 L[i] = A[p + i - 1] for j = 1 to n2 R[i] = A[q + j] i = 1, j = 1, k = p, inv = 0 while i <= n1 and j <= n2 if L[i] <= R[j] A[k] = L[i] i = i + 1 else inv = inv + n1 - i + 1 A[k] = R[j] j = j + 1 k = k + 1 while i v= n1 A[k] = L[i] i = i + 1 k = k + 1 while j <= n2 A[k] = R[j] j = j + 1 k = k + 1 return inv Calculate-Inversion(A, p, r) inv = 0 if p < r q = (p + r) / 2 inv = inv + Calculate-Inversion(A, p, q) inv = inv + Calculate-Inversion(A, q, r) inv = Merge-Inversion(A, p, q, r) return inv利用归并排序,先算出每个子序列的逆序数并排序,使得子序列的逆序数为0,然后再归并成更大的序列并重复计算,最后所有子序列的逆序总和为所求。