转载请声明出处:http://blog.csdn.net/zhongkelee/article/details/45485943
一、分治法的基本思想
分治法的适用条件
分治法所能解决的问题一般具有以下几个特征:
(1)该问题的规模缩小到一定程度就可以容易地解决。
(2)该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。
(3)利用该问题分解出的子问题的解可以合并为该问题的解。
(4)该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。(对于有公共部分的子问题,用动态规划较好,后续博客会讲解)
分治法的基本步骤
devide-and-conquer(P)
{
if (|P| <= n0) adhoc(P);//解决小规模问题
devide P into smaller sub-instances P1,P2,...,Pk;//分解问题
for (i = 1; i <= k; i++)
yi = devide-and-conquer(Pi);//递归地解各个子问题
return merge(y1,y2,...,yk);//将各个子问题的解合并为原问题的解
}
人们从大量实践中发现,在用分治法设计算法时,最好使子问题的规模大致相同,即将一个问题分成大小相等的k个子问题的处理方法是行之有效的。这种使子问题规模大致相等的做法是出自一种平衡子问题的思想,它几乎总是比子问题规模不等的做法要好。
分治法的复杂性分析
分治法将规模为n的问题分成k个规模为n/m的子问题去解。设分解阀值n0=1,且adhoc解规模为1的问题耗费1个单位时间;再设将原问题divide为k个子问题和用merge将k个子问题的解合并为原问题的解需用f(n)个单位时间。用T(n)表示该分治法解规模为|P|=n的问题所需的计算时间,则有
应用主定理求得方程的解。
下面讨论一些运用分治策略的实例。
二、二分搜索技术
给定已按升序排好序的n个元素a[0:n-1],现要在这n个元素中找出以特定元素x。
分析:
1.该问题的规模缩小到一定的程度就可以容易地解决;
2.该问题可以分解为若干个规模较小的相同问题;
3.分解出的子问题的解可以合并为原问题的解;
4.分解出的各个子问题是相互独立的。
无论是在前面还是后面查找x,其方法都和在a中查找x一样,只不过是查找的规模缩小了。这就说明了此问题满足分治法的第二个和第三个适用条件。很显然此问题分解出的子问题相互独立,即在a[i]的前面或后面查找x是独立的子问题,因此满足分治法的第四个适用条件。
二分搜索算法实现:
#include <iostream>
using namespace std;
int BinarySearch(int arr[], int x, int left, int right){
while(left <= right){
int middle = (left + right)/2;
if (arr[middle] == x)
return middle;
if (arr[middle] > x)
right = middle - 1;
else
left = middle + 1;
}
return -1;
}
int main()
{
int array[] = {0,1,2,3,4,5,6,7,8,9};
cout << "0 in array position: " << BinarySearch(array,0,0,9) << endl;
cout << "9 in array position: " << BinarySearch(array,9,0,9) << endl;
cout << "2 in array position: " << BinarySearch(array,2,0,9) << endl;
cout << "6 in array position: " << BinarySearch(array,6,0,9) << endl;
cout << "10 in array position: " << BinarySearch(array,10,0,9) << endl;
return 0;
}
运行结果:
算法复杂度分析:
每执行一次算法的while循环,待搜索数组的大小减小一半。因此,在最坏情况下,while循环被执行了O(logn)次。循环体内运算需要O(1)时间,因此整个算法在最坏情况下的计算时间复杂性为O(logn)。