分治法
分治法的工作方案:
a. 将规模为n的问题的实例,划分为同一个问题的几个较小规模的实例,最好拥有同样的规模(n/b)。
b. 对这些较小的实例(规模为n/b)求解(一般使用递归方法,但在问题规模足够小的时候,有时也会使用一些其他方法)
c. 如果必要的话,合并这些较小问题的解,以得到原始问题的解。
通用分治递推式: T(n) = aT(n/b) + f(n) f(n)是表示分解和合并问题所消耗的时间。
主定理:当f(n)规模为n的d次方时,1.当a<bd:T(n)的规模为nd;2.当a=bd时:T(n)的规模为ndlog n;3.当a>b时,T(n)的规模为nlogba
分治法对于并行计算是非常理想的,因为各个子问题可以由不同的CPU同时计算。
1. 合并排序:
Mergesort(A[0…n-1])
If n>1
Copy A[0… n/2-1] to B[0… n/2-1]
Copy A[n/2 … n-1] to C[0… n/2-1]
Mergesort(B[0… n/2-1])
Mergesort(C[0… n/2-1])
Merge( B, C, A) //把排序好的B和C数组,合并成A。
2. 快速排序:
合并排序是按照元素在数组中的位置对它们进行划分,而 快速排序是按照元素的值对他们进行划分。
Quicksort(A[l..r])
If l<r
S <— Partition(A[l..r]) //
Quciksort(A[l..s-1])
Quciksort(A[s+1..r])
Partition(A[l..r])
p <— A[l]; i <— l ; j <— r+1
repeat
repeat i=i+1 until A[i]>=p
repeat j=j-1 until A[j]=<p
swap(A[i],A[j])
until I>=j
swap(A[i],A[j])
swap(A[l],A[j])
return j
3. 折半查找:
高效的查找有序数组,不是纯粹的分治法,适合归类到减半算法。
4. 分治法的其他例子:
a. 二叉树遍历及其相关特性:前序(根—左—右);中序(左—根—右);后序(左—右—根)
b. 大整数乘法和Strassen矩阵乘法:大整数乘法公式: c = a*b = (a1a0)*(b1b0) = c2*100 + c1*10 + c0其中:c2 = a1*b1;c0=a0*b0 ;c1=(a1+a0)*(b1+b0) – (c2+c0)
c. 分治法解最近对问题和凸包问题:最近对问题,先按照x坐标排列,然后可以画一条中线x=c;凸包问题,先找出左右顶点,分成上下包,。。。。。。原理和快速排序类似,平均效率是n log n,最差效率是n的平方。
可以采用更好的中轴选择方法(比如三平均分区法等)……主要缺点:需要额外的线形空间。