2.3-1
使用图2-4作为模型,说明归并排序再数组A=<3,41,52,26,38,57,9,49>A=<3, 41, 52, 26, 38, 57, 9, 49>A=<3,41,52,26,38,57,9,49>上的操作
答:
[39263841495257][ 3 \quad 9 \quad 26 \quad 38 \quad 41 \quad 49 \quad 52 \quad 57 ][39263841495257]
↑\uparrow↑
[3264152∣9384957][ 3 \quad 26 \quad 41 \quad 52 | 9 \quad 38 \quad 49 \quad 57 ][3264152∣9384957]
↑\uparrow↑
[341∣2652∣3857∣949][ 3 \quad 41 | 26 \quad 52 | 38 \quad 57 | 9 \quad 49 ][341∣2652∣3857∣949]
↑\uparrow↑
[3∣41∣52∣26∣38∣57∣9∣49][ 3 | 41 | 52 | 26 | 38 | 57 | 9 | 49 ][3∣41∣52∣26∣38∣57∣9∣49]
2.3-2
重写过程MERGE,使之不使用哨兵,而是一旦数组L或R的所有元素均被复制回A就立即停止,然后把另一个数组的剩余部分复制回A。
答:
伪代码1:
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[j] = A[q + j]
i = 1
j = 1
for k = p to r
if L[i] <= R[j]
A[k] = L[i]
i = i + 1
else
A[k] = R[j]
j = j + 1
if i > n1 or j > n2
break
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:
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[j] = A[q + j]
i = 1
j = 1
for k = p to r
if i > n1
A[k] = R[j]
j = j + 1
else if j > n2
A[k] = L[i]
i = i + 1
else if L[i] <= R[j]
A[k] = L[i]
i = i + 1
else
A[k] = R[j]
j = j + 1
2.3-3
使用数学归纳法证明:当nnn刚好是2的幂时,以下递归式的解是T(n)nlog2nT(n)nlog_2nT(n)nlog2n。
T(n)={2若n=22T(n2)若n=2k,k>1T(n) = \begin{cases}
2 & \text{若}n=2 \\
2T(\frac{n}{2}) & \text{若}n=2^k,k>1
\end{cases}T(n)={22T(2n)若n=2若n=2k,k>1
证明:
(1)当n=21n=2^1n=21时,T(n)=2=2log22T(n)=2=2log_22T(n)=2=2log22。即当n=21n=2^1n=21时,T(n)=nlog2nT(n)=nlog_2nT(n)=nlog2n成立。
(2)假设当n=2kn=2^kn=2k时,T(n)=nlog2nT(n)=nlog_2nT(n)=nlog2n成立。即T(n)=T(2k)=2klog2k=2kkT(n)=T(2^k)=2^klog_2k=2^kkT(n)=T(2k)=2klog2k=2kk。
(3)当n=2k+1n=2^k+1n=2k+1时,
T(n)=T(2k+1)T(n)=T(2^k+1)T(n)=T(2k+1)
=2T(2k+12)+2k+1=2T(\frac{2^k+1}{2})+2^{k+1}=2T(22k+1)+2k+1
=2T(2k)+2k+1=2T(2^k)+2^{k+1}=2T(2k)+2k+1
=2×2kk+2k+1=2\times2^kk+2^{k+1}=2×2kk+2k+1
=2k+1k+2k+1=2^{k+1}k+2^{k+1}=2k+1k+2k+1
=2k+1(k+1)=2^{k+1}(k+1)=2k+1(k+1)
=2k+1log22k+1=2^{k+1}log_22^{k+1}=2k+1log22k+1
=nlog2n=nlog_2n=nlog2n
即,当$n=2^{k+1}时,
T(n)=nlog2nT(n)=nlog_2nT(n)=nlog2n成立。
综上所述,当nnn刚好是2的幂时,以下递归式的解是T(n)=nlog2nT(n)=nlog_2nT(n)=nlog2n。
T(n)={2若n=22T(n2)若n=2k,k>1T(n) = \begin{cases}
2 & \text{若}n=2 \\
2T(\frac{n}{2}) & \text{若}n=2^k,k>1
\end{cases}T(n)={22T(2n)若n=2若n=2k,k>1
2.3-4
我们可以把插入排序表示为如下的一个递归过程。为了排序A[1..n]A[1 .. n]A[1..n],我们递归地排序A[1..n−1]A[1 .. n-1]A[1..n−1],然后把A[n]A[n]A[n]插入已排序地数组A[1..n−1]A[1 .. n-1]A[1..n−1]。为插入排序的这个递归版本的最坏情况运行时间写一个递归式。
答:
T(n)={Θ(1)若n=1,T(n−1)+Θ(n)若n>1。
T(n) = \begin{cases}
\Theta(1) & \text{若}n=1, \\
T(n-1) + \Theta(n) & \text{若}n>1。
\end{cases}
T(n)={Θ(1)T(n−1)+Θ(n)若n=1,若n>1。
2.3-5
回顾查找问题(参见联系2.1-3),注意到,如果序列AAA已排好序,就可以将该序列的重点与vvv进行比较。根据比较的结果,原序列中有一半就可以不用再做进一步的考虑了。二分查找算法重复这个过程,每次将序列剩余部分的规模减半。为二分查找写成迭代或递归的伪代码。证明:二分查找的最坏情况运行时间为Θ(log2n)\Theta(log_2n)Θ(log2n)。
答:
迭代伪代码:
BINARY-SEARCH-ITERATION(A, low, high, v)
while low ≤ high
middle = (low + high) / 2
if v < A[middle]
high= middle - 1
else if v > A[middle]
low = middle + 1
else
return middle
return NIL
迭代C#代码:
private static int BinarySearchIteration(int[] array, int low, int high, int v)
{
while (low <= high)
{
int middle = (low + high) / 2;
if (v < array[middle])
{
high = middle - 1;
}
else if (v > array[middle])
{
low = middle + 1;
}
else
{
return middle;
}
}
return -1;
}
递归伪代码:
BINARY-SEARCH-RECURSION(A, low, high, v)
if low > high
return NIL
middle = (low+ high) / 2
if(v < A[middle])
return BINARY-SEARCH-RECURSION(A, low, middle - 1, v)
else if(v > A[middle])
return BINARY-SEARCH-RECURSION(A, middle + 1, high, v)
else
return middle
递归C#代码:
private static int BinarySearchRecursin(int[] array, int low, int high, int v)
{
if(low > high)
{
return -1;
}
int middle = (low + high) / 2;
if(v < array[middle])
{
return BinarySearchRecursin(array, low, middle - 1, v);
}
else if(v > array[middle])
{
return BinarySearchRecursin(array, middle + 1, high, v);
}
else
{
return middle;
}
}
证明二分查找的最坏情况运行时间为Θ(log2n)\Theta(log_2n)Θ(log2n):
每次我们将vvv与中间元素进行比较时,搜索范围都将继续进行。此时,搜索范围减半。故运行时间的递归式为:
T(n)={Θ(1)若n=1T(n)=T(n2)+Θ(1)若n>1
T(n) = \begin{cases}
\Theta(1) & \text{若}n=1 \\
T(n) = T(\frac{n}{2}) + \Theta(1) & \text{若}n>1
\end{cases}
T(n)={Θ(1)T(n)=T(2n)+Θ(1)若n=1若n>1
此递归式的解为Θ(log2n)\Theta(log_2n)Θ(log2n)。
2.3-6
注意到2.1节中的过程INSERTION-SORT的第5~7行的while循环采用一种线性查找来(反向)扫描已排好序的子数组A[1..j−1]A[1 .. j-1]A[1..j−1]。我们可以是哟个二分查找(参见联系2.3-5)来把插入排序的最坏情况总运行时间改进到Θ(nlog2n)\Theta(nlog_2n)Θ(nlog2n)吗?
答:
在最坏情况中,待排序的元素是按与要求相反的顺序排布的。插入排序算法INSERTION-SORT,在插入第j个元素的迭代中需要做两个步骤:首先,通过线性查找来(反向)扫描已排好序的子数组A[1..j−1]A[1 .. j-1]A[1..j−1];然后将A[1..j−1]A[1 .. j-1]A[1..j−1]中的元素逐个向后移动一个位置。如果使用二分查找,仅仅是改变了查找过程的运行时间,但未改变移动过程的运行时间。
而移动过程的总运行时间依然是Θ(n2)\Theta(n^2)Θ(n2),因此,我们无法使用二分查找来把插入排序的最坏情况总运行时间改进到Θ(nlog2n)\Theta(nlog_2n)Θ(nlog2n)。
我们也可以通过计算得出类似的结论。
为了简化问题,我们假设将目标数字与数组中某个下标的元素进行对比的时间为1,而移动一个元素的时间也为1。但是,我们不考虑类似操作下标这种不太重要的时间,也不考虑将目标数组放置到数组的指定位置的时间。
在原来的INSERTION-SORT算法中,对于要插入的第kkk个元素,在该次迭代中,比较所需要的运行时间为k−1k-1k−1,移动所需要的运行时间也为k−1k-1k−1,所需要的运行时间为2(k−1)2(k-1)2(k−1)。
所以,总运行时间为
∑k=1n(k−1)+(k−1)\sum_{k=1}^{n}(k-1)+(k-1)k=1∑n(k−1)+(k−1)
=∑k=1n2(k−1)=\sum_{k=1}^{n}2(k-1)=k=1∑n2(k−1)
=n(n−1)=n(n-1)=n(n−1)
在改进后的INSERTION-SORT算法中,对于要插入的第kkk个元素,在该次迭代中,比较所需要的运行时间为log2klog_2klog2k,移动所需要的运行时间仍然为k−1k-1k−1。
所以,总运行时间为
∑k=1nlog2k+(k−1)\sum_{k=1}^{n}log_2k+(k-1)k=1∑nlog2k+(k−1)
=n(n−1)2+log2(n!)=\frac{n(n-1)}{2} + log_2(n!)=2n(n−1)+log2(n!)
因为n(n−1)2\frac{n(n-1)}{2}2n(n−1)的增长速度大于nlog2nnlog_2nnlog2n,我们无法使用二分查找来把插入排序的最坏情况总运行时间改进到Θ(nlog2n)\Theta(nlog_2n)Θ(nlog2n)。
通过下图,我们也可以直观地看出这一情况:

*2.3-7
描述一个运行时间为Θ(nlog2n)\Theta(nlog_2n)Θ(nlog2n)的算法,给定nnn个整数的集合SSS和另一个整数xxx,该算法能确定SSS中是否存在两个其和刚好为xxx的元素。
答:
首先,使用归并排序算法对集合SSS进行排序,运行时间为Θ(nlog2n)\Theta(nlog_2n)Θ(nlog2n)。
其次,对于排序后的集合SSS中的元素中的每一个元素sis_isi(i=1..ni = 1 .. ni=1..n),使用二分查找算法在S[i+1..n]S[i+1 .. n]S[i+1..n]中查找是否有元素si′s_i^{'}si′符合si′=x−sis_i^{'}=x-s_isi′=x−si,这个过程的运行时间是Θ(log2n)\Theta(log_2n)Θ(log2n)。如果找到了,就返回该元素的位置,如果没有找到,则继续下一次迭代。
所以,总的运行时间为:
T(n)=Θ(nlog2n)+n⋅Θ(log2n)=Θ(nlog2n)
T(n) = \Theta(nlog_2n)+n\cdot\Theta(log_2n)=\Theta(nlog_2n)
T(n)=Θ(nlog2n)+n⋅Θ(log2n)=Θ(nlog2n)
因此,该算法能确定SSS中是否存在两个其和刚好为xxx的元素。
本文探讨了如何利用归并排序和二分查找技术优化插入排序的最坏情况,以及在查找问题中实现高效搜索。通过数学归纳法证明了归并排序的时间复杂性,并展示了如何通过二分查找减少查找次数,最终达到O(nlog2n)的时间复杂度。
6239

被折叠的 条评论
为什么被折叠?



