算法导论(第三版) 第二章思考题

http://www.cnblogs.com/Jiajun/archive/2013/05/02/3055460.html

2-1
a. 每个子序列的元素数量为k,最差的情况下需要进行 k(k1)/2 次基础操作,一共有 n/k 个子序列,所以总的基础操作次数为

nkk(k1)2=n(k1)2=Θ(nk)
b. 每一遍归并都对所有元素进行拷贝,所以单次复杂度为 Θ(n) ,而将n/k组子序列归并为一个序列最多需要 lgn/k 次,所以总的时间复杂度为 Θ(nlgn/k)
c. 由前两问的结果可知,复杂度为 Θ(nk+nlgn/k) 。要找到最大的k就应该使得 Θ(nk) Θ(nlgn/k) 的增长率相等,这时 k=lgn ,即
Θ(nlgn+nlgnlgn)=Θ(2nlgnnlglgn)=Θ(nlgn)
d. 实际应用上k应该选取使得插入排序和归并排序运行时间相同时的输入规模,充分发挥插入排序常数系数小的优势。


2-2
a. 需要证明最终的序列是非递减的,还需要证明最终序列是原序列的一种排列。
b.

  • Initialization: 一开始j=A.length,有A[j]不大于子序列[j, A.length]中的元素;
  • Maintenance: 接下来,每次循环开始的时候都有A[j]不大于子序列[j, A.length]中的元素。而每次循环都把A[j]和A[j-1]中较小的元素放到A[j-1],则有A[j-1]不大于子序列[j-1, A.length]中的元素,然后让j减1,满足了循环初始的条件,由于只做了比较和交换操作,所以序列[i, A.length]只是原来序列的一种排列。
  • Termination: 最后当循环退出的时候有A[i]不大于子序列[i, A.length]中的元素,即A[i]是子序列[i, A.length]中最小的之一。
c.
  • Initialization: 一开始i=1,[1, i-1]中的元素非递减,且[i, A.length]中的元素都不小于[1, i-1]中的元素;
  • Maintenance: 接下来,每次循环开始的时候都有[1, i-1]中的元素非递减,且[i, A.length]中的元素不小于[1, i-1]中的元素。而每次循环都把A[i]和[i, A.length]中最小的之一交换,又A[i]不小于[1, i-1]中的元素,所以[1, i]中的元素非递减,且[i+1, A.length]中的元素都不小于[1, i]中的元素,这时i增加1,满足了循环初始的条件。
  • Termination: 最后当循环退出的时候有[1, A.length-1]中的元素非递减,且A.length不小于[1, i-1]中的元素。所以整个序列[1, A.length]非递减。
d. 最差的情况下,冒泡排序(bubblesort)需要进行 n(n1)/2 次比较,所以时间复杂度为 Θ(n2) 和插入排序一致;在最好的情况下,比较的次数不变,而插入排序比较的次数减少为n-1次,总体来说效率比插入排序差。


2-3
a. 循环中的运算可以在常量时间内完成,所以复杂度是 Θ(1) ,循环次数为n,所以总的时间复杂度为 Θ(n)
b.

1
2
3
4
5
6
7
8
Evaluate-Polynomial(A, x, n)
     y = 0
     for  k = 0 to n
         t = 1
         for  i = 1 to k
             t = t * x;
         y = y + A[k] * t
     return  y
两重循环内的乘法运算次数最多,总数为
k=0nk=n(n1)2
所以时间复杂度为 Θ(n2) ,效率低于霍纳法则(Horner's Rule)。
c. 当循环进行到最后一次时,i = 0,可得
y=a0+xk=0n(0+1)ak+0+1xk=a0+k=0n1ak+1xk+1=k=0nakxk
得到所求 
d. 根据c的循环不变式可以保证该算法所得结果正确。


2-4
a. (8, 6) (2, 1) (3, 1) (8, 1) (6, 1) 
b. 拥有逆序数最多的是  {n,n1,,3,2,1} ,其中任意两个数之间都是逆序的,所以总计 n(n1)/2 个。
c. 逆序数应该与元素移动的数量相同。插入排序每次移动元素都将一个较大的数移到较小的数后面,使得总逆序数减少1,而排序完成后逆序数是0,所以开始的逆序数和元素移动的次数相同。
d.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Merge-Inversion(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[i] = A[q + j]
     i = 1, j = 1, k = p, inv = 0
     while  i <= n1 and j <= n2
         if  L[i] <= R[j]
             A[k] = L[i]
             i = i + 1
         else
             inv = inv + n1 - i + 1
             A[k] = R[j]
             j = j + 1
         k = k + 1
     while  i v= n1
         A[k] = L[i]
         i = i + 1
         k = k + 1
     while  j <= n2
         A[k] = R[j]
         j = j + 1
         k = k + 1
     return  inv
 
Calculate-Inversion(A, p, r)
     inv = 0
     if  p < r
         q = (p + r) / 2
         inv = inv + Calculate-Inversion(A, p, q)
         inv = inv + Calculate-Inversion(A, q, r)
         inv = Merge-Inversion(A, p, q, r)
     return  inv
利用归并排序,先算出每个子序列的逆序数并排序,使得子序列的逆序数为0,然后再归并成更大的序列并重复计算,最后所有子序列的逆序总和为所求。
在Merge过程中如果R序列中的元素 rj 出现在L中的元素 li 之前,说明 rj [li,ln1] 中的所有元素都组成逆序数,一共有n1 - i + 1个。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值