译自Michelle Bodnar与Andrew Lohr两位大牛
答案网址在CLRS Solutionshttps://sites.math.rutgers.edu/~ajl213/CLRS/CLRS.html
目录
译自Michelle Bodnar与Andrew Lohr两位大牛
问题2.1
解答
Exercise 2.1-1
Exercise 2.1-2
Exercise 2.1-3
在循环体的每次迭代中,进入循环体时的不变量是不存在索引 k < j,因此A[k] = v。为了继续循环的下一次迭代,我们需要对于当前的j值,我们不需要A[j] = v。如果循环在第5行退出,那么我们就在前一行的i中放置了一个可接受的值。如果通过耗尽j的所有可能值来退出循环,那么我们知道不存在值为j的索引,因此在i中保留NIL是正确的。
Exercise 2.1-4
问题2.2
解答
Exercise 2.2-2
输入:一个n元素的数组A。
输出:数组A的元素按递增顺序重新排列。选择排序的循环不变量如下:在第1到第10行for循环的每次迭代中,子数组A[1...i−1]按递增顺序包含A中i−1个最小的元素。经过n−1次循环后,A中最小的n−1个元素按递增顺序位于A的前n−1个位置,因此第n个元素必然是最大的元素。因此,我们不需要最后一次运行循环。选择排序的最佳情况和最坏情况运行时间为Θ(n^2)。这是因为无论元素最初是如何排列的,在主for循环的第i次迭代时,算法总是检查剩余的n - i个元素中的每一个,以找到剩余的最小的元素。
Exercise 2.2-3
假设每一项都有一个固定的概率p成为要找的元素。在本解答的末尾给出了对这个问题的另一种解释。然后,如果前k−1个位置不是要查找的元素,并且第k个位置是期望的值,我们将只检查k个元素。这意味着走k步的概率是p*(1−p)^k。最后一种可能性是,数组中没有一个元素与我们正在寻找的匹配,在这种情况下,我们查看所有A.length多个位置,并且它发生的概率为(1−p)。通过将每种情况下的步数乘以这种情况发生的概率,我们得到期望值:
最坏的情况显然是如果你要检查所有可能的位置,在这种情况下,它将花费正好A.length的步骤,所以它是Θ(A.length)现在,我们分析平均情况下的渐近行为。考虑以下操作,首先,我们将单求和重写为双求和,然后两次使用几何求和公式。
因此,由于我们以一个常数为上下边界,我们得到了一个有点不直观的结果,即期望运行时间作为a .length的函数,其中p保持常数为Θ(1)。
另一种解释这个问题的方法是数组中只有一个元素是你要找的,然后每个位置都有可能包含这个元素。在这种情况下,最坏情况的行为是不变的,而预期的运行时是 这使得期望情况的渐近值Θ(A.length)。
Exercise 2.2-4
为了获得最佳运行时间,修改算法,首先随机产生输出,然后检查它是否满足算法的目标。如果是,则产生此输出并停止。否则,请照常运行算法。这不太可能成功,但在最好的情况下,运行时间将仅与检查解决方案所需的时间相同。例如,我们可以修改选择排序,首先随机排列A中的元素,然后检查它们是否按有序顺序排列。如果是,则输出a,否则像往常一样运行选择排序。在最好的情况下,这个修改后的算法的运行时间为Θ(n)。
问题2.3
解答
Exercise 2.3-1
Exercise 2.3-2
下面是MERGE的重写,避免了使用哨兵。与MERGE非常相似,它首先将A的子数组复制到数组L和R中。在从第13行开始的while循环的每次迭代中,它从L或R中选择下一个最小的元素放入A中。如果L或R中的元素耗尽,则停止,此时它将其他子数组的剩余部分复制到A的剩余位置。
Exercise 2.3-3
Exercise 2.3-4
设T(n)表示对大小为n的数组进行插入排序的运行时间。我们可以递归地将T(n)表示为
其中I(n)表示将A[n]插入已排序数组A[1...n-1]所花费的时间。因为一旦我们找到插入A[n]的正确位置,我们可能需要移动多达n - 1个元素,我们有I(n) = θ(n)。
下面的递归算法在调用a = 1和b = n时给出了期望的结果。注意,初始调用应该是BinSearch(1, n, v)。每次调用都会导致固定数量的操作加上对问题实例的调用,其中数量b−a至少下降了两倍。因此,运行时间满足递归式T(n) = T(n/2) + c,因此,T(n)∈Θ(lg(n))。
Exercise 2.3-6
二分搜索不会改善最坏情况下的运行时间。插入排序必须将每个大于key的元素复制到数组中相邻的位置。进行二分查找会告诉我们需要复制多少个元素,但不会消除需要进行的复制。
Exercise 2.3-7
我们可以看到while循环最多运行O(n)次,因为j - i从n - 1开始,每一步都减少。此外,由于代码体只包含一定量的工作,所以所有第2-15行只需要O(n)时间。因此,运行时主要是执行排序的时间,即Θ(n*lg(n))。
我们将用相互归纳法来证明其正确性。设mi,j是命题A[i] + A[j] < S, Mi,j是命题A[i] + A[j] > S。请注意,因为数组是有序的,mi,j⇒∀k < j, mi,k, and Mi,j⇒∀k > i, Mk,j。显然,我们的程序只会在存在有效的i和j的情况下输出true。现在,假设我们的程序输出false,即使没有考虑到a [i] + a [j] = s的i, j。如果我们有i > j,那么交换这两个,和不会改变,所以,假设i≤j,我们现在有两种情况:
情况1∃k,(i, k)被考虑,且j < k。在这种情况下,我们取最小的这样的k,这个非零的事实意味着在考虑它之后,我们马上考虑(i+1,k)这意味着mi,k这意味着mi,j
情形2∃k,(k, j)是考虑的并且k < i,在这种情况下,我们取最大的k,事实是非零的,这意味着在考虑它之后,我们立即考虑(k,j-1)这意味着Mk,j这意味着Mi,j
注意,这两种情况中的一种必须为真,因为所考虑的点集将{(m, m0): m≤m0 < n}分隔为至多两个区域。如果您在包含(1,1)(如果非空)的区域中,则属于情形1。如果你在包含(n, n)(如果非空)的区域,那么你就在情况2中。