一.目录
1.算法基本原理
2.经典问题
二.分治法基本原理
分而治之,先将原问题的规模下降,分解为子问题,此所谓“分”,然后解决子问题,此为“治”。
分治法的基本思想是将一个规模为n的原问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题相同。递归地解这些子问题,然后将子问题的解合并为原问题的解。
分治法的伪代码:
v divide_and_conquer(proplem p){//n为问题规模
if(|p|
solve(p);
else{
divide p into smaller subproblem P1,P2,...Pk;
for(i=1;i<=k;i++){
yi=divide_and_conquer(Pi);
return merge(y1,y2,...,yk);
}
}
}
可以看到,分治法与递归是一对孪生兄弟,有分治法的地方就有递归的身影。
使用分治法时,要将原问题进行规模分解,分解为独立的子问题。一般来说,将原问题分解为两个大小相同的子问题可以得到将好的效率。
对分治法的复杂度分析是通过对递归的复杂度进行分析。递归复杂度分析方法有三种,即主定理,递归树,代入法。
三.经典问题
3.1.合并排序
3.2.快速排序
3.3.线性时间选择
3.1合并排序
合并排序是利用分治法对n个元素进行排序的方法。其基本思想,先将原元素集合分解为规模大小基本相同的两个子集合,然后依次递归地对子问题进行排序。最后将排好序的子集合合并为所要求的排好序的集合。
伪代码:
void merge_sort(Type a[],int left,int right){
if(left
int i = (left+right)/2;
merge_sort(a,left,i);
merge_sort(a,i+1,right);
merge(a,b,left,i,right);//合并到数组b
copy(a,b,left,right);//复制回数组a
}
}
void merge(Type origin[],Type destint[],int left,int middle,int right){
int i=left; int k=left; int j=middle+1;
while(i
if(origin[i]
else destin[k++] = origin[j++];
}
//处理剩余元素
if(i
while(i
else
while(j
}
}
分治法的复杂度分析:
分治法的递归语句复杂度为T(n/2);
合并(merge) n个元素的复杂度为O(n);
复制(copy) n个元素的复杂度为O(n);
O(1) n<=1;
T(n) ={
T(n/2) + O(n); n>=2;
可以得出分治法的平均复杂度为O(nlogn);