2-1
a、
对长度为k的子表使用插入排序最坏的情况下复杂度为Θ(
k
2
k^{2}
k2),因此对n/k个每个长度为k的子表排序最坏需要
Θ
(
k
2
∗
n
/
k
)
=
Θ
(
n
k
)
Θ(k^2 *n/k)=Θ(nk)
Θ(k2∗n/k)=Θ(nk).
b、
经过步骤a后,已经有了n/k个已经排好序的长度为k的子序列,每次选择其中的两个进行合并,一共要
l
g
(
n
/
k
)
lg(n/k)
lg(n/k)步,在每一步中都要比较n个元素,因此最坏的情况下需要
Θ
(
n
l
g
(
n
/
k
)
)
Θ(nlg(n/k))
Θ(nlg(n/k)).
c、
即求使方程
Θ
(
n
k
+
n
l
g
(
n
/
k
)
)
=
Θ
(
n
l
g
n
)
Θ(nk+nlg(n/k))=Θ(nlgn)
Θ(nk+nlg(n/k))=Θ(nlgn)成立时k满足的条件。
原式
=
Θ
(
n
k
+
n
l
g
n
−
n
l
g
k
)
=Θ(nk+nlgn-nlgk)
=Θ(nk+nlgn−nlgk)
令
k
=
Θ
(
l
g
n
)
k=Θ(lgn)
k=Θ(lgn)带入上式中,得:
原
式
=
Θ
(
n
l
g
n
+
n
l
g
n
−
n
l
g
(
l
g
n
)
)
=
Θ
(
2
n
l
g
n
−
n
l
g
(
l
g
n
)
)
原式=Θ(nlgn+nlgn-nlg(lgn))\\ =Θ(2nlgn-nlg(lgn))
原式=Θ(nlgn+nlgn−nlg(lgn))=Θ(2nlgn−nlg(lgn))
忽略低阶项和常量2,便得到了期望的结果:原式
=
Θ
(
n
l
g
n
)
=Θ(nlgn)
=Θ(nlgn)
d、
选择插入排序比归并排序快的子列表的最大长度为k。
2.2
a、
还要保证
A
′
A'
A′里的元素均由A中的元素组成
b、
循环不变式:
在2-4行的for循环每次迭代开始时,子数组A [i…n]由进入循环之前原先在A [i…n]中的元素组成,但顺序有可能不同,其中A[i]是最小的。
开始:
只对A[n]进行操作。
维持:
每一步中,比较A[j]与A[j-1],并使A[j-1]成为小的哪一个,在整个迭代结束后子数组长度增加1,并且第一个元素是最小的。
结束:
当i==j时,循环停止,按照循环不变式的描述,A[i]是A[i…n]中的最小的元素,并且A[i…n]中的元素只是位置发生了变化。
c、
循环不变式:
在1-4行的for循环迭代每次开始时,A[1,…i-1]由A[1,…n]中i-1个最小的元素构成。
开始:
开始时A[1,…i-1]子数组为空
维持:
再执行过b部分的内部循环后A[i]成为A[i…n]中最小的元素,在外部循环开始时,A[1,…,i-1]中的元素均小于A[i,…,n]中的元素,因此在外部循环结束后,A[1,…,i]中的元素均小于A[i+1,…n]并已经排好序了。
结束:
循环在
i
=
A
.
l
e
n
g
t
h
i=A.length
i=A.length时停止,此时A已经是有序的了。
d、
冒泡排序的复杂度和插入排序最坏运行时间相同,均为Θ( n 2 n^2 n2)
2.3
a、
时间复杂度为Θ(
n
n
n)
b、
for k in range(n+1):
ans+=a[k]*(x^k)
其中for循环要运行n次,每一次迭代求x的k次幂复杂度是k最大时是n,所以总的时间复杂度是Θ(
n
2
n^2
n2).
其性能要比霍纳规则差
c、
开始:
y=0
维持:
把题目中给出的循环不变式代入代码片段的第三行,就能得到第i次迭代结束后y的值:
y
=
a
i
+
x
∑
k
=
0
n
−
(
i
+
1
)
a
k
+
i
+
1
x
k
=
a
i
x
0
+
∑
k
=
0
n
−
i
−
1
a
k
+
i
+
1
x
k
+
1
=
a
i
x
0
+
∑
k
=
1
n
−
i
a
k
+
i
x
k
=
∑
k
=
0
n
−
i
a
k
+
i
x
k
\begin{aligned} y &=a_i+x\sum_{k=0}^{n-(i+1)}a_{k+i+1} x^k \\ &=a_ix^0+\sum_{k=0}^{n-i-1}a_{k+i+1} x^{k+1} \\ &=a_ix^0+\sum_{k=1}^{n-i}a_{k+i} x^{k} \\ &=\sum_{k=0}^{n-i}a_{k+i}x^k \end{aligned}
y=ai+xk=0∑n−(i+1)ak+i+1xk=aix0+k=0∑n−i−1ak+i+1xk+1=aix0+k=1∑n−iak+ixk=k=0∑n−iak+ixk
结束:
在i=-1的时候循环会结束,代入循环不变式得:
y
=
∑
k
=
0
n
−
i
−
1
a
k
+
i
+
1
x
k
=
∑
k
=
0
n
a
k
x
k
y=\sum_{k=0}^{n-i-1}a_{k+i+1}x^k=\sum_{k=0}^na_kx^k
y=k=0∑n−i−1ak+i+1xk=k=0∑nakxk
即所要证明的。
d、
按上面的循环不变式来看,其总和就是给出的多项式的和
2-4
a、
<2,1> < 3,1> <8,1> <6,1> <8,6>
b、
从大到小排序的序列具有最多的逆序对,最多为:
(
n
−
1
)
+
(
n
−
2
)
+
.
.
.
+
1
=
n
(
n
−
1
)
/
2
(n-1)+(n-2)+...+1=n(n-1)/2
(n−1)+(n−2)+...+1=n(n−1)/2
c、
插入排序与逆序对的数量成正比
d、
求序列中逆序对的个数:在归并排序合并的时候加入一个cont来存储每次合并时找到的逆序对的个数.在《算法竞赛进阶指南》里有这个算法的详细描述,这里不写了。
def merge(a, p, q, r):
n1 = q - p + 1
n2 = r - q
L = [0 for _ in range(n1 + 2)]
R = [0 for _ in range(n2 + 2)]
for i in range(1, n1 + 1):
L[i] = a[p + i - 1]
for j in range(1, n2 + 1):
R[j] = a[q + j]
L[n1 + 1] = float('inf')
R[n2 + 1] = float('inf')
i = 1
j = 1
# 求逆序对的个数
cont = 0
for k in range(p, r + 1):
if L[i] <= R[j]:
a[k] = L[i]
i += 1
else:
cont += n1 - i + 1
a[k] = R[j]
j += 1
return cont
def merge_sort(a, p, r):
if p < r:
q = int((p + r) / 2)
left = merge_sort(a, p, q)
right = merge_sort(a, q + 1, r)
if not left: left = 0
if not right: right = 0
# python 中None 和 int 类型不能一起加
cont = merge(a, p, q, r) + left + right
return cont
# a是待求数组, 下标从1到n,所以a[0]要自己设一个数,k是a中逆序对的个数,n是有效数字个数
a=['k',2,3,8,6,1]
n=5
k = merge_sort(a, 1, n)
print(k)