<算法导论>第二章思考题

2-1
a、
  对长度为k的子表使用插入排序最坏的情况下复杂度为Θ( k 2 k^{2} k2),因此对n/k个每个长度为k的子表排序最坏需要 Θ ( k 2 ∗ n / k ) = Θ ( n k ) Θ(k^2 *n/k)=Θ(nk) Θ(k2n/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+nlgnnlgk)
  令 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+nlgnnlg(lgn))=Θ(2nlgnnlg(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=0n(i+1)ak+i+1xk=aix0+k=0ni1ak+i+1xk+1=aix0+k=1niak+ixk=k=0niak+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=0ni1ak+i+1xk=k=0nakxk
  即所要证明的。

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 (n1)+(n2)+...+1=n(n1)/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)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值