国科大计算机算法刘玉贵第三章分治算法笔记

基本思想

将规模为n的问题规约为规模减小的一个或多个子问题,分别求解每个子问题,然后把子问题的解综合,得到原问题的解。

Divide-and-conquer(p)
if |p|≤c then S(p)     //S(p)代表直接求解
  divide p into p1,p2,…pk
    for i=1 to k do 
      yi=divide-and-conque(pi)    //递归求解每个子问题
    end{for}
end{if}
Return Merge(y1,y2,…,yk)    //把子问题的解进行综合

二分查找/折半搜索

 proc BiFind(a,n) 
 //在数组 a[1..n]中搜索 x,数组中的元素满足 a[1] ≤ a[2] ≤ … ≤ a[n]。如果找到 x,则返回所在位置(数组元素的下标),否则返回 –1 
    global a[1..n], n; 
    integer left,right,middle; 
    left:=1; right:=n; 
    while left ≤ right do 
      middle:=(left+right)/2; 
      if x=a[middle] then return(middle); 
      end{if} 
      if x>a[middle] then left:=middle+1; 
      else right:=middle-1; 
      end{if} 
    end{while} 
 return(–1); //未找到 x 
end{BiFind} 

复杂度分析

{ T ( n ) = T ( ⌊ n 2 ⌋ ) + 1 T ( 1 ) = 1 \left\{\begin{array}{c} T(n)=T\left(\left\lfloor\frac{n}{2}\right\rfloor\right)+1 \\ T(1)=1 \end{array}\right. {T(n)=T(2n)+1T(1)=1

设n=2k,T(n)= T(n/2)+1 =T(n/4)+2=T(n/8)+3 =… =T(1)+k=1+logn=Θ(logn)

若用一一比较的算法,则T(n)=O(n)

查找最大最小

MaxMin(i,j,fmax,fmin) 
//A[1:n]是n元数组,参数i,j :1≤i≤j≤n,使用该过程将数组A[i..j]中的最大最小元分别赋给fmax和fmin。
      global n, A[1..n]; 
      integer i, j;
      if i=j then   
         fmax:=A[i]; fmin:=A[i]; //子数组A[i..j]中只有一个元素
      elseif i=j-1 then //子数组A[i..j]中只有两个元素
         if A[i]<A[j] then
         fmin:=A[i]; fmax:=A[j];
         else fmin:=A[j]; fmax:=A[i];
         end{if}
      else   //子数组A[i..j]中的元素多于两个
        mid:=⌊(i+j)/2⌋; 
        MaxMin(i, mid, lmax, lmin);//递归
        MaxMin(mid+1, j, rmax, rmin);//递归
        fmax:=max(lmax, rmax);
        fmin:=min(lmin, rmin);
      end{if}
     end{MaxMin} 

复杂度分析

T ( n ) = { 0 n = 1 1 n = 2 T ( ⌈ n / 2 ⌉ ) + T ( ⌊ n / 2 ⌋ ) + 2 n > 2 \mathrm{T}(n)=\left\{\begin{array}{lc} 0 & n=1 \\ 1 & n=2 \\ T(\lceil n / 2 \rceil)+T(\lfloor n / 2\rfloor)+2 & n>2 \end{array}\right. T(n)=01T(n/2)+T(n/2)+2n=1n=2n>2

设n=2k,T(n)=2T(n/2)+2=4T(n/4)+4+2=2k-1+2k-2=3n/2-2

若用一一比较的算法,则T(n)=2(n-1)

排序算法

插入排序

proc InSort(a, n)
//对 a[1..n]进行插入排序
for i from 2 to n do//将a[i]插入a[1..i-1]
   x:=a[i];   integer j;
   for j from i-1 by -1 to 1 do 
     if x<a[j] then a[j+1]:=a[j]; //更小值向后移位
     end{if}
   end{for}
   a[j+1]:=x;//插入更大值之后
end{for}
end{InSort}

T(n)=1+2+…+(n-1) =n(n-1)/2=Θ(n2)

归并排序

proc MergeSort(low, high)
 // A[low .. high]是一个全程数组,含有 high-low+1个待排序的元素。
integer  low, high;
if  low < high  then
       mid:=(low+high)/2//求当前数组的分割点
       MergeSort(low, mid)  //将第一子数组排序
       MergeSort(mid+1, high)  //将第二子数组排序
       Merge(low, mid, high)  //归并两个已经排序的子数组
end{if}
end{MergeSort} 
proc Merge(low, mid, high) //已知全程数组 A[low .. high], 其由两部分已经排好序的子数组构成:A[low .. mid]和 A[mid+1 .. high]。本程序的任务是将这两部分子数组合并成一个整体排好序的数组,再存于数组 A[low .. high]. 
integer h, i, j, k, low, mid, high; 
global A[low .. high];  
local B[low .. high]; //借用临时数组 B 
h:=low, i:=low, j:=mid+1;  
 // h, j 是拣取游标, i 是向 B 存放元素的游标 
while h≤mid and j≤high do  //当两个集合都没有取尽时 
    if A[h]≤A[j] then B[i]:=A[h], h:=h+1; 
    else B[i]:=A[j], j:=j+1; 
    end{if} 
      i:=i+1; 
end{while} 
if h>mid then  //当第一子组元素被取尽,而第二组元素未被取尽时 
  for k from j to high do 
     B[i]:=A[k]; i:=i+1; 
  end{for} 
else //当第二子组元素被取尽,而第一组元素未被取尽时 
  for k from h to mid do 
          B[i]:=A[k]; i:=i+1; 
  end{for} 
end{if} 
 //将临时数组 B 中元素再赋给数组 A 
for k from low to high do  
     A[k]:=B[k]; 
end{for} 
end{Merge} 

时间复杂度

T ( n ) = { a n = 1 2 T ( n / 2 ) + c n n > 1 T(n)=\left\{\begin{array}{ll} a & n=1 \\ 2 T(n / 2)+c n & n>1 \end{array}\right. T(n)={a2T(n/2)+cnn=1n>1

令n=2k ,

T ( n ) = 2 ( 2 T ( n / 4 ) + c n / 2 ) + c n = 4 T ( n / 4 ) + 2 c n ⋯ ⋯ = 2 k T ( 1 ) + k c n = a n + c n log ⁡ n \begin{aligned} T(n) &=2(2 T(n / 4)+c n / 2)+c n \\ &=4 T(n / 4)+2 c n \\ & \cdots \cdots \\ &=2^{k} T(1)+k c n \\ &=a n+c n \log n \end{aligned} T(n)=2(2T(n/4)+cn/2)+cn=4T(n/4)+2cn=2kT(1)+kcn=an+cnlogn

当2k < n ≤ 2^k +1^ ,T (n) = O(nlogn)

快速排序

算法思想:将A[1…n]划分成B[1…p]和B[p+1…n],使得B[1…p]中的元素均不大于B[p+1…n]中的元素,然后分别对它们排序,最后接起来即可。

首元素划分:选定A中的首元素,将A中的所有元素与之比较,小于等于的元素构成B[1…p],大于的元素构成B[p+1…n]。

快速排序算法:

proc QuickSort(p,q) //将数组A[1..n]中的元素A[p], A[p+1], ... , A[q] 按不降次序排列,并假定A[n+1]是一个确定数,且大于A[1..n]中所有的数。划分后j成为划分元素的位置。

        integer p,q; 
        global n, A[1..n];
       if p<q then
         j:=q+1;//保持对称性
         Partition(p,j); //首元素划分
         QuickSort(p,j-1); 
         QuickSort(j+1,q); 
       end{if}
      end{QuickSort}

最坏复杂度T(n)=T(n-1)+n-1=T(n-2)+n-2+n-1=1+2+…+n-1=(n-1)(n-2)/2=O(n2)

首元素划分算法:

请添加图片描述

proc Partition(m,p) 
// 用首元素划分数组A[m,p-1],划分后首元素放中间。
integer m, p, i;  
global A[m ..p-1]; 
v:=A[m]; i:=m; 
loop 
     loop i:=i+1; until A[i]>v; end{loop} //自左向右查 
     loop p:=p-1; until A[p]≤v; end{loop} //自右向左查 
     if i<p then 
       Swap(A[i],A[p]); //交换 A[i]和 A[p]的位置 
     else go to *; 
     end{if} 
end{loop} 
*: A[m]:=A[p]; A[p]:= v; // 划分元素在位置 p 
end{Partition}

平均复杂度T(n) = 2(n+1)logn=O(nlogn)

请添加图片描述

选择问题

问题描述:确定数组A[1…n]的第k小元素。

若使用某种排序算法将A按不降次序排序,从排好序的数组中检出第k个元素。最坏时间复杂度O(nlogn)

划分法

请添加图片描述

proc PartSelect(A, n, k) //在数组 A[1..n]中找第 k 小元素 t,并将其存放于位置 k,即 A[k]=t。而剩下的元素按着以 t 为划分元素的划分规则存放。再令 A[n+1]=+∞. 
 integer n, k, m, r, j; 
 m:=1; r:=n+1; A[n+1]:= +∞; 
 loop 
   j:=r; 
   Partition(m,j);  
   case 
      k=j : return // 返回 j,当前数组的元素 A[j]是第 j 小元素 
      k<j : r:=j; // j 是新的下标上界 
      else : m:=j+1; k:=k-j; //j+1 是新的下标下界 
   end{case} 
end{loop} 
end{PartSelect}

矩阵乘法

矩阵加法和乘法

假定 A, B 都是 n×n 矩阵,它们的 i 行 j 列元素分别记为 A(i,j)和 B(i,j)。
如果用 S 和 C 分别记 A+B 和 A*B, 则有

S ( i , j ) = A ( i , j ) + B ( i , j ) 1 ≤ i , j ≤ n C ( i , j ) = ∑ k = 1 n A ( i , k ) ∗ B ( k , j ) 1 ≤ i , j ≤ n \begin{array}{lc} S(i, j)=A(i, j)+B(i, j) & 1 \leq i, j \leq n \\ C(i, j)=\sum_{k=1}^{n} A(i, k) * B(k, j) & 1 \leq i, j \leq n \end{array} S(i,j)=A(i,j)+B(i,j)C(i,j)=k=1nA(i,k)B(k,j)1i,jn1i,jn

可见,矩阵加法运算的时间复杂度是 Θ(n2) ,而矩阵乘法的时间复杂度是 Θ(n3)

分块矩阵乘法

设n=2k,将A、B各分为4个n/2阶矩阵

请添加图片描述

T ( n ) = { b n ≤ 2 8 T ( n / 2 ) + d n 2 n > 2 T(n)=\left\{\begin{array}{ll} b & n \leq 2 \\ 8 T(n / 2)+d n^{2} & n>2 \end{array}\right. T(n)={b8T(n/2)+dn2n2n>2

T ( n ) = b n 3 / 8 + 4 d ( n 2 − 16 ) / 3 = Θ ( n 3 ) T(n)=b n^{3} / 8+4 d\left(n^{2}-16\right) / 3=\Theta(n^3) T(n)=bn3/8+4d(n216)/3=Θ(n3)

Strassen矩阵乘法

P = ( A 11 + A 22 ) ( B 11 + B 22 ) Q = ( A 21 + A 22 ) B 11 R = A 11 ( B 12 − B 22 ) S = A 22 ( B 21 − B 11 ) T = ( A 11 + A 12 ) B 22 U = ( A 21 − A 11 ) ( B 11 + B 12 ) V = ( A 12 − A 22 ) ( B 21 + B 22 ) C 11 = P + S − T + V C 12 = R + T C 21 = Q + S C 22 = P + R − Q + U \begin{array}{l} P=\left(A_{11}+A_{22}\right)\left(B_{11}+B_{22}\right) \\ Q=\left(A_{21}+A_{22}\right) B_{11} \\ R=A_{11}\left(B_{12}-B_{22}\right) \\ S=A_{22}\left(B_{21}-B_{11}\right) \\ T=\left(A_{11}+A_{12}\right) B_{22} \\ U=\left(A_{21}-A_{11}\right)\left(B_{11}+B_{12}\right) \\ V=\left(A_{12}-A_{22}\right)\left(B_{21}+B_{22}\right) \\ C_{11}=P+S-T+V \\ C_{12}=R+T \\ C_{21}=Q+S \\ C_{22}=P+R-Q+U \end{array} P=(A11+A22)(B11+B22)Q=(A21+A22)B11R=A11(B12B22)S=A22(B21B11)T=(A11+A12)B22U=(A21A11)(B11+B12)V=(A12A22)(B21+B22)C11=P+ST+VC12=R+TC21=Q+SC22=P+RQ+U

T ( n ) = { b n ≤ 2 7 T ( n / 2 ) + a n 2 n > 2 = Θ ( n 2.81 ) T(n)=\left\{\begin{array}{ll} b & n \leq 2 \\ 7 T(n / 2)+a n^{2} & n>2 \end{array}\right.=\Theta(n^{2.81}) T(n)={b7T(n/2)+an2n2n>2=Θ(n2.81)

快速Fourier变换

N 个数据的离散 Fourier 变换

A j = ∑ 0 ≤ k ≤ N − 1 a k e 2 π i j k / N , 0 ≤ j A_{j}=\sum_{0 \leq k \leq N-1} a_{k} e^{2 \pi i j k / N}, \quad 0 \leq j Aj=0kN1ake2πijk/N,0j

ω = e 2 π i / N \omega=e^{2 \pi i / N} ω=e2πi/N,相当于计算多项式 a ( x ) = ∑ 0 ≤ k ≤ N − 1 a k x k a(x)=\sum_{0 \leq k \leq N-1} a_{k} x^{k} a(x)=0kN1akxk ω j \omega^j ωj处的值。T(N)=N*2(N-1)

采用分治算法,将求 N = 2n 个数据的 Fourier 变换归结为求两次具有 n 个数据的 Fourier 变换。

b ( x ) = a 1 + a 3 x + a 5 x 2 + … + a N − 1 x ( N − 2 ) / 2 c ( x ) = a 0 + a 2 x + a 4 x 2 + … + a N − 2 x ( N − 2 ) / 2 \begin{array}{l} b(x)=a_{1}+a_{3} x+a_{5} x^{2}+\ldots+a_{N-1} x^{(N-2) / 2} \\ c(x)=a_{0}+a_{2} x+a_{4} x^{2}+\ldots+a_{N-2} x^{(N-2) / 2} \end{array} b(x)=a1+a3x+a5x2++aN1x(N2)/2c(x)=a0+a2x+a4x2++aN2x(N2)/2

a ( x ) = b ( x 2 ) x + c ( x 2 ) a(x)=b\left(x^{2}\right) x+c\left(x^{2}\right) a(x)=b(x2)x+c(x2)

a ( ω j ) = b ( ω 2 j ) ω j + c ( ω 2 j ) a ( ω j + n ) = − b ( ω 2 j ) ω j + c ( ω 2 j ) , j = 0 , 1 , ⋯   , n − 1 \begin{array}{l} a\left(\omega^{j}\right)=b\left(\omega^{2 j}\right) \omega^{j}+c\left(\omega^{2 j}\right) \\ a\left(\omega^{j+n}\right)=-b\left(\omega^{2 j}\right) \omega^{j}+c\left(\omega^{2 j}\right) \end{array}, \quad j=0,1, \cdots, n-1 a(ωj)=b(ω2j)ωj+c(ω2j)a(ωj+n)=b(ω2j)ωj+c(ω2j),j=0,1,,n1

时间复杂度

T ( N ) = { a ,  if  N = 1 2 T ( N / 2 ) + c N ,  if  N > 1 = O ( N l o g N ) T(N)=\left\{\begin{array}{l} a, \text { if } N=1 \\ 2 T(N / 2)+c N, \text { if } N>1 \end{array}\right. =O(NlogN) T(N)={a, if N=12T(N/2)+cN, if N>1=O(NlogN)

Proc FFT(N,a,w,A)
//N=2n,w是n次单位根,a是已知的N元数组,代表多项式a(x)的系数,A是计算出来的N元数组,A[j]=a(w^j), j=0,1,…,N-1.
 real b[ ], c[ ];  int j;
 complex B[ ], C[ ], wp[ ];
 if  N=1 then A[0]:=a[0]; 
 else 
       n:=N/2;
       for j from 0 to n-1 do
         b[j]:=a[2*j+1];  c[j]:=a[2*j];
       end{for}
 end{if}
 FFT(n,b,w*w,B);
 FFT(n,c,w*w,C);
 wp[0]:=1; 
for j from 0 to n-1 do
      wp[j+1]:=w*wp[j]; 
      A[j]:= C[j]+B[j]*wp[j]; 
      A[j+n]:= C[j]-B[j]*wp[j];  
  end{for}
end{FFT} 

分治算法中常见的递归方程

T ( n ) = ∑ i = 1 k a i T ( n − i ) + f ( n ) T(n)=\sum_{i=1}^{k} a_{i} T(n-i)+f(n) T(n)=i=1kaiT(ni)+f(n)

可用迭代求解、递归树分析求解

T ( n ) = a T ( n / b ) + f ( n ) T(n)=aT(n/b)+f(n) T(n)=aT(n/b)+f(n)

可用主定理分析:

设a≥1,b >1为常数,f(n)为函数,T(n)为非负整数,且

T ( n ) = a T ( n / b ) + f ( n ) , c = log ⁡ b a T(n)=aT(n/b)+f(n),c=\log b^a T(n)=aT(n/b)+f(n),c=logba

则有

T ( n ) = { Θ ( n c ) Θ ( n c log ⁡ n ) Θ ( f ( n ) ) f ( n ) = O ( n c − ε ) f ( n ) = Θ ( n c ) f ( n ) = Ω ( n c + ε ) T\left( n \right) =\left\{ \begin{matrix} \begin{array}{l} \Theta \left( n^c \right)\\ \Theta \left( n^c\log n \right)\\ \Theta \left( f\left( n \right) \right)\\ \end{array}& \begin{array}{l} f\left( n \right) =O\left( n^{c-\varepsilon} \right)\\ f\left( n \right) =\Theta \left( n^c \right)\\ f\left( n \right) =\Omega \left( n^{c+\varepsilon} \right)\\ \end{array}\\ \end{matrix} \right. T(n)=Θ(nc)Θ(nclogn)Θ(f(n))f(n)=O(ncε)f(n)=Θ(nc)f(n)=Ω(nc+ε)

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
国科大刘玉贵计算机学院的教授,他的研究领域是算法设计与分析。他在这个领域取得了很多的成果,并且发表了很多相关的论文。其中一篇论文就是关于计算机算法设计与分析的,题目是《计算机算法设计与分析的新方法》。这篇论文总结了他多年来在算法设计与分析方面的研究成果,并提出了一些新的方法。 在这篇论文中,刘玉贵首先介绍了计算机算法设计与分析的基本概念和原理,包括算法的复杂性、算法的正确性、算法的优化等。然后,他详细介绍了一些经典的算法设计与分析方法,如分治法、动态规划、贪心算法等,并且分析了它们的优缺点。接着,他提出了一些新的算法设计与分析方法,这些方法在一些实际问题中取得了很好的效果。最后,他对未来的研究方向进行了展望,提出了一些有意义的问题和可行性的解决方案。 这篇论文对于计算机算法设计与分析领域的研究具有重要的意义,它不仅总结了已有的成果,还提出了一些新的方法,为进一步的研究提供了有益的启示。同时,刘玉贵作为该领域的专家,他的研究具有很高的学术价值和实际应用价值。这篇论文对于计算机学院的学生和教师来说,也是一份很好的参考资料,可以帮助他们更好地理解和应用相关的知识。总的来说,刘玉贵的这篇论文对于促进计算机算法设计与分析领域的发展和研究具有积极的推动作用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值