第二章 2.3节

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

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页