2.2-1
用 Θ \Theta Θ记号表示函数 n 3 / 1000 − 100 n 2 − 100 n + 3 n^3 / 1000 - 100n^2 - 100n + 3 n3/1000−100n2−100n+3。
答:
Θ
(
n
3
)
\Theta(n^3)
Θ(n3)
2.2-2
考虑排序存储在数组 A A A中的 n n n个数:首先找出 A A A中的最小元素并将其与 A [ 1 ] A[1] A[1]中的元素进行交换。接着,找出 A A A中次最小元素并将其与 A [ 2 ] A[2] A[2]中的元素进行交换。对 A A A中前 n − 1 n-1 n−1个元素按该方式继续。该算法称为选择算法,写出其伪代码。该算法维持的循环不变式是什么?为什么它只需要对前 n − 1 n-1 n−1个元素,而不是对所有 n n n个元素运行?用 Θ \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..i−1]中的元素均为已排序好的元素”。
- 当 i = = n − 1 i == n - 1 i==n−1时,数组 A A A中前 n − 2 n - 2 n−2个元素均已排好序,而剩余未排序的元素只有 A [ n − 1 ] A[n - 1] A[n−1]和 A [ n ] A[n] A[n]这两个元素了。在内层for循环体内对这两个未排序元素进行了比较,并且将较小的元素保存在 A [ n − 1 ] A[n-1] A[n−1]了,同时也就将两者中的较大的元素保存在 A [ n ] A[n] A[n]中了。这样,对于最后一次循环迭代( i = = n − 1 i == n - 1 i==n−1),会同时将数组 A A A中最后两个一同排序。所以,选择排序只需要对前 n − 1 n - 1 n−1个元素而不是对所有 n n n个元素运行。
- 运行时间
为选择排序算法SELECTION-SORT(A)中每一行的设定执行代价,即第 k k k行的执行代价为 c k c_k ck,每行代码的执行情况如下所示:
代码 | 代价 | 执行次数 |
---|---|---|
SELECTION-SORT(A) | ||
n = A.length | c 1 c_1 c1 | 1 1 1 |
for i = 1 to n - 1 | c 2 c_2 c2 | n n n |
minIndex = i | c 3 c_3 c3 | n − 1 n - 1 n−1 |
for j = i + 1 to n | c 4 c_4 c4 | ∑ j = 2 n ( n − j + 1 ) + 1 \sum_{j=2}^{n}(n-j+1)+1 ∑j=2n(n−j+1)+1 |
if A[minIndex] > A[j] | c 5 c_5 c5 | ∑ j = 2 n ( n − j + 1 ) \sum_{j=2}^{n}(n-j+1) ∑j=2n(n−j+1) |
minIndex = j | c 6 c_6 c6 | ∑ k = 1 n − 1 t k \sum_{k=1}^{n-1}t_k ∑k=1n−1tk,其中 t k t_k tk为在 k = i k=i k=i时此行的执行次数 |
swap(A[i], A[minIndex]) | c 7 c_7 c7 | n − 1 n-1 n−1 |
T
(
n
)
=
c
1
+
c
2
n
+
c
3
(
n
−
1
)
+
c
4
(
∑
j
=
2
n
(
n
−
j
+
1
)
+
1
)
+
c
5
∑
j
=
2
n
(
n
−
j
+
1
)
+
c
6
∑
k
=
1
n
−
1
t
k
+
c
7
(
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(n−1)+c4(j=2∑n(n−j+1)+1)+c5j=2∑n(n−j+1)+c6k=1∑n−1tk+c7(n−1)
=
c
4
+
c
5
2
n
2
+
(
c
2
+
c
3
+
c
7
−
c
4
+
c
5
2
)
n
+
(
c
1
−
c
3
+
c
4
−
c
7
)
+
c
6
∑
k
=
1
n
−
1
t
k
=\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+c7−2c4+c5)n+(c1−c3+c4−c7)+c6k=1∑n−1tk
设
a
=
c
4
+
c
5
2
,
b
=
c
2
+
c
3
+
c
7
−
c
4
+
c
5
2
,
c
=
(
c
1
−
c
3
+
c
4
−
c
7
)
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+c7−2c4+c5,c=(c1−c3+c4−c7),则
T
(
n
)
=
a
n
2
+
b
n
+
c
+
c
6
∑
k
=
1
n
−
1
t
k
T(n) = an^2 + bn + c + c_6\sum_{k=1}^{n-1}t_k
T(n)=an2+bn+c+c6k=1∑n−1tk
最好情况即为原数组中的元素已经按从小到大的顺序排序,则对于
m
i
n
I
n
d
e
x
=
j
minIndex = j
minIndex=j这一句的执行因
i
f
A
[
m
i
n
I
n
d
e
x
]
>
A
[
j
]
if A[minIndex] > A[j]
ifA[minIndex]>A[j]判断不为真,而从来没用执行过。此时,当
k
=
1
,
2
,
.
.
.
n
−
1
k = 1, 2, ... n-1
k=1,2,...n−1时,
t
k
=
0
t_k=0
tk=0,故
T
1
(
n
)
=
a
n
2
+
b
n
+
c
T_1(n) = an^2 + bn + c
T1(n)=an2+bn+c
所以
Θ
(
T
1
(
n
)
)
=
Θ
(
n
2
)
\Theta(T_1(n)) = \Theta(n^2)
Θ(T1(n))=Θ(n2)
最坏情况即为原数组中的元素已经按从大到小的顺序排序,则对于
m
i
n
I
n
d
e
x
=
j
minIndex = j
minIndex=j这一句的执行因
i
f
A
[
m
i
n
I
n
d
e
x
]
>
A
[
j
]
if A[minIndex] > A[j]
ifA[minIndex]>A[j]判断总是真,而一直都在执行。此时,当
k
=
1
,
2
,
.
.
.
n
−
1
k = 1, 2, ... n-1
k=1,2,...n−1时,
t
k
=
n
−
1
,
n
−
2
,
.
.
.
1
t_k=n-1, n-2, ... 1
tk=n−1,n−2,...1,故
T
2
(
n
)
=
a
n
2
+
b
n
+
c
+
∑
k
=
1
n
−
1
(
n
−
k
)
T_2(n) = an^2 + bn + c + \sum_{k=1}^{n-1}{(n-k)}
T2(n)=an2+bn+c+k=1∑n−1(n−k)
=
a
n
2
+
b
n
+
c
+
n
(
n
−
1
)
2
=an^2+bn+c+\frac{n(n-1)}{2}
=an2+bn+c+2n(n−1)
=
2
a
+
1
2
n
2
+
2
b
−
1
2
n
+
c
=\frac{2a+1}{2}n^2 + \frac{2b-1}{2}n+c
=22a+1n2+22b−1n+c
设
a
′
=
2
a
+
1
,
b
′
=
2
b
−
1
a'=2a+1, b'=2b-1
a′=2a+1,b′=2b−1,则
T
2
(
n
)
=
a
′
n
2
+
b
′
n
+
c
T_2(n)=a'n^2+b'n+c
T2(n)=a′n2+b′n+c
所以
Θ
(
T
2
(
n
)
)
=
Θ
(
n
2
)
\Theta(T_2(n)) = \Theta(n^2)
Θ(T2(n))=Θ(n2)
综上所述,最好情况与最坏情况的运行时间均为 Θ ( T ( n ) ) = Θ ( n 2 ) \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.length | c 1 c_1 c1 | n + 1 n+1 n+1 |
if A[i] == v | c 2 c_2 c2 | n n n |
return i | c 3 c_3 c3 | 1 1 1 |
return NIL | c 4 c_4 c4 | 1 1 1 |
线性查找算法的运行时间
T
(
n
)
=
(
n
+
1
)
+
n
+
1
+
1
T(n) = (n+1) + n + 1 + 1
T(n)=(n+1)+n+1+1
=
2
n
+
3
=2n + 3
=2n+3
-
在平均情况下,需要检查输入序列一半的元素。此时
T 1 ( n ) = ( n 2 + 1 ) + n 2 + 1 + 1 T_1(n) = (\frac{n}{2} + 1) + \frac{n}{2} + 1 + 1 T1(n)=(2n+1)+2n+1+1
= n + 3 = n + 3 =n+3
故,运行时间
Θ ( T ( n ) ) = Θ ( n ) \Theta(T(n)) = \Theta(n) Θ(T(n))=Θ(n) -
在最坏情况下,需要检查输入序列所有的元素。此时
T 1 ( n ) = ( n + 1 ) + n + 1 + 1 T_1(n) = (n + 1) + n + 1 + 1 T1(n)=(n+1)+n+1+1
= 2 n + 3 = 2n + 3 =2n+3
故,运行时间
Θ ( T ( n ) ) = Θ ( n ) \Theta(T(n)) = \Theta(n) Θ(T(n))=Θ(n)
综上所述,在平均情况和最坏情况下,它们的运行时间为 Θ ( n ) \Theta(n) Θ(n)。
2.2-4
我们可以如何修改几乎任意算法来使之具有良好的最好情况运行时间?
答:
- 首先,可以判断算法是否为无法匹配期望结果的输入。如果相匹配,则直接返回。
- 其次,可以添加特殊情况,让算法优先检查是否匹配这些特殊情况。如果相匹配,则直接返回预先计算出的结果。
- 最后,可以对一般输入进行分类,让出现概率更高的输入优先匹配最适算法,以减少执行步数。