2.3-1
使用图2-4作为模型,说明归并排序再数组A=<3, 41, 52, 26, 38, 57, 9, 49>
解答:
两个数中间的“-”号为连接符,代表“-”号两边的数归并一起。
① 3 41 52 26 38 57 9 49
② 3 - 41 26 - 52 38 - 57 9 - 49
③ 3 - 26 - 41 - 52 9 - 38 - 49 - 57
④ 3 - 9 - 26 - 38 - 41 - 49 - 52 - 57
2.3-2
重写MERGE,使之不使用哨兵,而是一旦数组L或R的所有元素均被复制回A就立刻停止,然后把另一个数组的剩余部分复制回A。
解答:
前面的大部分和原始的MERGE差不多,下面贴一下我写的伪代码
MERGE(A, p, q, r)
n1 = q - p + 1
n2 = r - q
let L[1...n1+1] and R[1...n2+1] be new arrays
for i from 1 to n1:
L[i] = A[p + i - 1]
for j from 1 to n2:
R[j] = A[q + j]
i = 1
j = 1
for k from p to r:
if L[i] <= R[j]:
A[k] = L[i]
i = i + 1
if i == n1 + 1:
break
else
A[k] = R[j]
j = j + 1
if j == n2 + 1:
break
if i == n1 + 1:
for j from j to r:
A[n1 + j] = R[j]
if j == n2 + 1:
for i from i to q:
A[n2 + i] = L[i]
2.3-3
使用数学归纳法证明:当n刚好是2的幂时,以下递归式的解是T(n) = nlgn.
T(n) =
2 若 n = 2
2T(n/2) + n 若 n = 2^k, k > 1
解答:
①
当n = 2^1时, T(n) = 2 <=> 2lg2 = 2
当n = 2^2时, T(n) = 2T(2^2/2) + 2^2 = 2T(2) + 4 = 2 * 2 + 4 = 8
nlgn = 2^2 * lg(2^2) = 4 * 2 = 8
左边等于右边
当n = 2^3时, T(n) = 2T(2^3/2) + 2^3 = 2T(4) + 8 = 2 * 8 + 8 =24
nlgn = 2^3 * lg(2^3) = 8 * 3 = 24
左边等于右边
.....
当n = 2^n时, T(n)=2T(2^n/2) + 2^n = 2 * (2T(2^(n-1)/2) + 2^(n-1)) + 2^n = 4T(2^(n-1)/2) + 2 * 2^n = ... = 2^(n-1) * 2 + (n-1)*2^n = n2^n (T(n)的结果会使用到T(n-1)的值,依次类推)
nlgn = 2^n * lg(2^n) = n2^n
左边等于右边
②
1> 等n = 2时,T(n) = 2lg2 = 2成立
2> 假设当n=2^k(k > 1)时,等式成立,即T(2^k) = (2^k)lg(2^k) = k(2^k)
又因为已知n = 2^k(k > 1)时,有T(2^k) = 2T(2^k/2) + 2^k,
所以,T(2^(k+1)) = 2T(2^(k+1)/2) + 2^(k+1) = 2T(2^k) + 2^(k+1) = 2(k * 2^k) + 2^(k+1) = (k+1)*2^(k+1)
3> 所以,当n = 2^(k+1)时,等式也成立。
综合①②,即递归式的解确实为T(n) = nlg(n)
2.3-4
我们可以把插入排序表示为如下的一个递归过程。为了排序A[1...n], 我们递归地排序A[1...n-1],然后把A[n]插入已排序的数组A[1..n-1]。
为插入排序的这个递归版本的最坏情况运行时间写一个递归式。
解答:
这里可以借鉴2.3-3中的结论。
这里对A的前n-1个数进行递归排序。所以,前n-1个的递归式可以写成
T(n-1)= 【这里我们假设n-1为2的幂,主要是这样能简化解答过程】
2 若 n - 1 = 2
2T((n-1)/2) + n -1 若 n -1 = 2^k, k>1
等待排序结束后,将A[n]插入。
这里我们考虑的是最坏的运行情况,所以,这个插入过程需要遍历整个列表,也就是Θ(n)。
结合两个表达式,
T(n) =
5 若n - 1 = 2
2T((n-1)/2) + 2n -1 若 n -1 = 2^k, k>1
PS. 想要获得更一般的表达式可以参考20页中的T(n)表达式进行求解。
2.3-5
回顾查找问题,主意到,如果序列A已排好序,就可以将改序列的中点与v进行比较。根据比较的结果,原序列中有一半就可以不用再做进一步的考虑了。二分查找算法重复这个过程,每次都将序列剩余部分的规模减半。为二分查找写出迭代或递归的伪代码。证明:二分查找的最坏情况运行时间为Θ(lgn)。
解答:
伪代码写起来比较简单
BINARY(A[1..n], v):
low = 1, high = n
while low <= high:
mid = (low + high)/2
case:
A[mid] < t : low = mid + 1
A[mid] = t : return mid
A[mid] > t : high = mid - 1
return 0
这里最坏的情况就是长度一直在对折,直到某一子段里面只有一个元素的时候。
在不停对折的过程中,就是一直对除以2,也就是lgn
这里说的不是很直观…… 当然在书中有图可以看的更直观一些。
在书的第21页中,我们可以看到一个树状图,其实就可以看做是二分查找的分解图。
其深度也就是这个查找的最坏情况所用的时间。
2.3-6
注意到2.1节中的过程INSERTION-SORT的第5~7行的while循环采用一种线性查找(反向)扫描已排好的子数组A[1..j-1].我们可以使用二分查找来把插入排序的最坏情况总运行时间改进到Θ(nlgn)吗?
解答:
这里应该是不行的。这里查找的时间复杂度是Θ(nlgn)没错。不过,这里不仅仅涉及到查找,在排序的过程中(元素交换)时间复杂度并没有减少,依旧是Θ(n^2)。
如果采用的数据结果有高速的元素交换速度,那么这个时间会相应的减少一些。
PS 在做这道题的时候不小心找到了这版的答案,也和大家共享一下吧 算法导论第三版课后答案 这个有助于我们的对问题的解答,不过对于答案来说都是参考的,只有自己做出来才是自己的成果。
2.3-7
描述一个运行时间为Θ(nlgn)的算法,给定n个整数的集合和另一个整数x,该算法能确定S中是够存在两个其和刚好为x的元素。
解答:
这个是可以做的,不过提供的集合需要事先进行排序。
RESEARCH-SUM(S[1..n], x):
// S need sorted
for i from 1 to n:
index = BINARY(S, x - S[i])
if index && (S[i] + S[index] == x)
return TRUE
return FALSE