[算法导论][练习题]2.2

本文探讨了选择排序算法的实现及其复杂度分析,并对比了线性查找算法的不同情况下的运行时间。

2.2-1

Θ\ThetaΘ记号表示函数n3/1000−100n2−100n+3n^3 / 1000 - 100n^2 - 100n + 3n3/1000100n2100n+3


答:
Θ(n3)\Theta(n^3)Θ(n3)

2.2-2

考虑排序存储在数组AAA中的nnn个数:首先找出AAA中的最小元素并将其与A[1]A[1]A[1]中的元素进行交换。接着,找出AAA中次最小元素并将其与A[2]A[2]A[2]中的元素进行交换。对AAA中前n−1n-1n1个元素按该方式继续。该算法称为选择算法,写出其伪代码。该算法维持的循环不变式是什么?为什么它只需要对前n−1n-1n1个元素,而不是对所有nnn个元素运行?用Θ\ThetaΘ记号给出选择排序的最好情况与最坏情况运行时间。


答:

  • 伪代码:
SELECTION-SORT(A)
	n = A.length
	for i = 1 to n - 1
		minIndex = i
		for j = i + 1 to n
			if A[minIndex] > A[j]
				minIndex = j
		swap(A[i], A[minIndex])
  • c#代码
static void SelectionSort(int[] A)
{
	for(int i = 0; i < A.Length - 1; i++)
	{
		int minIndex = i;
		for(int j = i + 1; j < A.Length; j++)
		{
			if (A[minIndex] > A[j])
				minIndex = j;
		}

		int temp = A[i];
		A[i] = A[minIndex];
		A[minIndex] = temp;
	}
}
  • 该算法维持的循环不变式是“f循环迭代每次开始之前,数组A[1..i−1]A[1 .. i - 1]A[1..i1]中的元素均为已排序好的元素”。
  • i==n−1i == n - 1i==n1时,数组AAA中前n−2n - 2n2个元素均已排好序,而剩余未排序的元素只有A[n−1]A[n - 1]A[n1]A[n]A[n]A[n]这两个元素了。在内层for循环体内对这两个未排序元素进行了比较,并且将较小的元素保存在A[n−1]A[n-1]A[n1]了,同时也就将两者中的较大的元素保存在A[n]A[n]A[n]中了。这样,对于最后一次循环迭代(i==n−1i == n - 1i==n1),会同时将数组AAA中最后两个一同排序。所以,选择排序只需要对前n−1n - 1n1个元素而不是对所有nnn个元素运行。
  • 运行时间
    为选择排序算法SELECTION-SORT(A)中每一行的设定执行代价,即第kkk行的执行代价为ckc_kck,每行代码的执行情况如下所示:
代码代价执行次数
SELECTION-SORT(A)
n = A.lengthc1c_1c1111
for i = 1 to n - 1c2c_2c2nnn
minIndex = ic3c_3c3n−1n - 1n1
for j = i + 1 to nc4c_4c4∑j=2n(n−j+1)+1\sum_{j=2}^{n}(n-j+1)+1j=2n(nj+1)+1
if A[minIndex] > A[j]c5c_5c5∑j=2n(n−j+1)\sum_{j=2}^{n}(n-j+1)j=2n(nj+1)
minIndex = jc6c_6c6∑k=1n−1tk\sum_{k=1}^{n-1}t_kk=1n1tk,其中tkt_ktk为在k=ik=ik=i时此行的执行次数
swap(A[i], A[minIndex])c7c_7c7n−1n-1n1

T(n)=c1+c2n+c3(n−1)+c4(∑j=2n(n−j+1)+1)+c5∑j=2n(n−j+1)+c6∑k=1n−1tk+c7(n−1)T(n) = c_1 + c_2n + c_3(n - 1) + c_4(\sum_{j=2}^{n}(n-j+1)+1) + c_5\sum_{j=2}^{n}(n-j+1) + c_6\sum_{k=1}^{n-1}t_k + c_7(n-1)T(n)=c1+c2n+c3(n1)+c4(j=2n(nj+1)+1)+c5j=2n(nj+1)+c6k=1n1tk+c7(n1)
=c4+c52n2+(c2+c3+c7−c4+c52)n+(c1−c3+c4−c7)+c6∑k=1n−1tk=\frac{c_4+c_5}{2}n_2 + (c_2+c_3+c_7-\frac{c_4+c_5}{2})n+(c_1-c_3+c_4-c_7) + c_6\sum_{k=1}^{n-1}t_k=2c4+c5n2+(c2+c3+c72c4+c5)n+(c1c3+c4c7)+c6k=1n1tk
a=c4+c52,b=c2+c3+c7−c4+c52,c=(c1−c3+c4−c7)a=\frac{c_4+c_5}{2}, b=c_2+c_3+c_7-\frac{c_4+c_5}{2}, c=(c_1-c_3+c_4-c_7)a=2c4+c5,b=c2+c3+c72c4+c5,c=(c1c3+c4c7),则
T(n)=an2+bn+c+c6∑k=1n−1tkT(n) = an^2 + bn + c + c_6\sum_{k=1}^{n-1}t_kT(n)=an2+bn+c+c6k=1n1tk

最好情况即为原数组中的元素已经按从小到大的顺序排序,则对于minIndex=jminIndex = jminIndex=j这一句的执行因ifA[minIndex]>A[j]if A[minIndex] > A[j]ifA[minIndex]>A[j]判断不为真,而从来没用执行过。此时,当k=1,2,...n−1k = 1, 2, ... n-1k=1,2,...n1时,tk=0t_k=0tk=0,故
T1(n)=an2+bn+cT_1(n) = an^2 + bn + cT1(n)=an2+bn+c
所以
Θ(T1(n))=Θ(n2)\Theta(T_1(n)) = \Theta(n^2)Θ(T1(n))=Θ(n2)

最坏情况即为原数组中的元素已经按从大到小的顺序排序,则对于minIndex=jminIndex = jminIndex=j这一句的执行因ifA[minIndex]>A[j]if A[minIndex] > A[j]ifA[minIndex]>A[j]判断总是真,而一直都在执行。此时,当k=1,2,...n−1k = 1, 2, ... n-1k=1,2,...n1时,tk=n−1,n−2,...1t_k=n-1, n-2, ... 1tk=n1,n2,...1,故
T2(n)=an2+bn+c+∑k=1n−1(n−k)T_2(n) = an^2 + bn + c + \sum_{k=1}^{n-1}{(n-k)}T2(n)=an2+bn+c+k=1n1(nk)
=an2+bn+c+n(n−1)2=an^2+bn+c+\frac{n(n-1)}{2}=an2+bn+c+2n(n1)
=2a+12n2+2b−12n+c=\frac{2a+1}{2}n^2 + \frac{2b-1}{2}n+c=22a+1n2+22b1n+c
a′=2a+1,b′=2b−1a'=2a+1, b'=2b-1a=2a+1,b=2b1,则
T2(n)=a′n2+b′n+cT_2(n)=a'n^2+b'n+cT2(n)=an2+bn+c
所以
Θ(T2(n))=Θ(n2)\Theta(T_2(n)) = \Theta(n^2)Θ(T2(n))=Θ(n2)

综上所述,最好情况与最坏情况的运行时间均为Θ(T(n))=Θ(n2)\Theta(T(n))=\Theta(n^2)Θ(T(n))=Θ(n2)

2.2-3

再次考虑线性查找问题(参见练习2.1-3)。假定要查找的元素等可能地为数组中地任意元素,平均需要检查输入序列的多少元素?最坏情况又如何呢?用Θ\ThetaΘ记号给出线性查找的平均情况和最坏情况运行时间。证明你的答案。


答:
线性查找算法伪代码:

LINEAR-SEARCH(A, v)
	for i = 1 to A.length
		if A[i] == v
			return i
	return NIL
代码代价执行次数
LINEAR-SEARCH(A, v)
for i = 1 to A.lengthc1c_1c1n+1n+1n+1
if A[i] == vc2c_2c2nnn
return ic3c_3c3111
return NILc4c_4c4111

线性查找算法的运行时间
T(n)=(n+1)+n+1+1T(n) = (n+1) + n + 1 + 1T(n)=(n+1)+n+1+1
=2n+3=2n + 3=2n+3

  • 在平均情况下,需要检查输入序列一半的元素。此时
    T1(n)=(n2+1)+n2+1+1T_1(n) = (\frac{n}{2} + 1) + \frac{n}{2} + 1 + 1T1(n)=(2n+1)+2n+1+1
    =n+3= n + 3=n+3
    故,运行时间
    Θ(T(n))=Θ(n)\Theta(T(n)) = \Theta(n)Θ(T(n))=Θ(n)

  • 在最坏情况下,需要检查输入序列所有的元素。此时
    T1(n)=(n+1)+n+1+1T_1(n) = (n + 1) + n + 1 + 1T1(n)=(n+1)+n+1+1
    =2n+3= 2n + 3=2n+3
    故,运行时间
    Θ(T(n))=Θ(n)\Theta(T(n)) = \Theta(n)Θ(T(n))=Θ(n)

综上所述,在平均情况和最坏情况下,它们的运行时间为Θ(n)\Theta(n)Θ(n)

2.2-4

我们可以如何修改几乎任意算法来使之具有良好的最好情况运行时间?


答:

  • 首先,可以判断算法是否为无法匹配期望结果的输入。如果相匹配,则直接返回。
  • 其次,可以添加特殊情况,让算法优先检查是否匹配这些特殊情况。如果相匹配,则直接返回预先计算出的结果。
  • 最后,可以对一般输入进行分类,让出现概率更高的输入优先匹配最适算法,以减少执行步数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值