主定理:设a>=1,b>1和d>=0,设f(n)为一函数,T(n)由递归式
, 那么
1>.如果,
2>.如果,
3>.如果,
该问题的常见形式是在一个有序数组中寻找某个元素。假设数组array[ ]存储升序序列,变量left表示查找范围的左边界,right表示查找范围的有边界,mid表示查找范围的中间位置,target为要查找的元素。用分治法实现过程如下:
1>初始化。令left=0,即指向array[ ]的第一个元素;right=array.length-1,即指向有序列表array[ ]的最后一个元素。
2>mid=(left+right)/ 2,即指向查找范围的中间元素。(low+high)为奇数的话,除以2并不能得到整数,此处向下取整,比如:4.5向下取整为4。
3>判定 left<=right是否成立,如果成立,转第4步,否则,说明该列表中没有指定元素,算法结束。
4>判断target 与 array[mid] 的关系。如果 target==array[mid] ,搜索成功,算法结束;如果 target >array[mid] ,令 left=middle+1,继续在数组的后半部分进行搜索;如果 target <array[mid] ,令 right=middle-1,继续在数组的前半部分进行搜索,即转向第2步。
由上图可以看出用分治法来实现大整数相乘的思路:
1>首先将要相乘的两个数X和Y分成A,B,C,D四部分。
2>此时将X和Y的乘积转化为图中的式子,把问题转化为求解式子的值。
3>递归处理,直至算出最后的结果。
使用分治法,将一个矩阵转换为子矩阵相乘的方式。矩阵乘法耗费时间要比矩阵加法耗费的时间多,想要改进矩阵乘法的计算时间复杂性,必须减少乘法运算。Strassen矩阵乘法用了7次对于n/2阶矩阵乘积的递归调用和18次n/2阶矩阵的加减运算。
在解决该问题时,需要将原始的棋盘划分成四个元素个数相同的棋盘,再根据特殊元素是否在划分后的区域进行不同的处理;然后递归地执行这个过程,直到最后划分的区域为包含四个元素单位。不难看出,这里面也体现了分–治的思想。
即归并排序,是典型的一种分治思想的运用,其过程如下:
1>分:将待排序元素划分成大小大致相同的两个子序列,直到每个子序列只有1个元素。
2>治:对两个子序列进行合并排序。
3>合:将排好序的有序子序列进行合并,得到最终的有序序列。
最坏时间复杂度:O(nlogn)
最好时间复杂度:O(nlogn)
平均时间复杂度:O(nlogn)
稳定性:稳定
归并排序是将待排列元素打散再重新聚合,快速排序是将待排列元素持续分堆,两者排序的过程中都是体现着不断拆分为子问题的痕迹,所以其实快速排序也是用分治思想来实现的。
快速排序的步骤如下:
1>先从数列中取出一个数作为基准数。
2>分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3>再对左右区间重复第二步,直到各区间只有一个数。
最坏时间复杂度:O(n^2)
最好时间复杂度:O(nlogn)
平均时间复杂度: O(nlogn)
稳定性:不稳定
此算法常使用的场景是:找出待排序序列中, 第k大或第k小元素(1<k<n)。
此算法使用步骤如下:
1>分组并取各组中位数 (将元素每5个分成一组,分别排序,并将该组中位数与该组的首元素交换,目的是使所有组的中位数都排列在数组最左侧,以便进一步查找中位数的中位数 。
2>查找中位数的中位数。
3>进行划分过程,即每轮排序后中位数对应的下标,在整个序列中的相对位置。
4>判断第k个数在划分结果的左边、右边还是恰好是划分结果本身,前两者递归处理,后者直接返回答案。
该问题指的是:在一个平面上,有着许多的散点,如果找出欧式距离最近的两个点。从问题表面可以看出,该问题可以用暴力法求解,即求出所有点之间的距离,再统一进行比较,选出距离最近的点对。但这样做,难免时间复杂度较高,所以就需要用别的解法来计算,常用的是分治法:即按X坐标或Y坐标将元素区分成两部分,然后不断划分,直到每个子区间中只有一个元素,求出左右区间中最小点对之间的距离,这样就求出了两个区间最小值。接下来要求出最复杂的第三个最小值:两个点在不同的子区间,如何在不同区间寻找这两个点就成了最近点对问题的难点。
具体步骤如下:
1>选择所有点的某一坐标(X坐标或Y坐标,此处以X轴为例),求出平均值,划分中轴线,将数据按某一坐标轴分为左右两个部分。
2>求出左半边和右半边的最小距离,选取较小值d,此步骤可以用递归实现。
3>根据上一步求出的d,求出最小点对在不同区间时的最小距离。
4>比较这三个最小距离。
分治法求解平面最近点对问题
该问题描述为:设有n=2^k个运动员要进行网球循环赛。现要设计一各满足一下要求的比赛日程表:
1>每个选手必须与其他n-1个选手各比赛一次。
2>每个选手一天只能赛一次。
3>循环赛一共进行n-1天。
按照上面的要求,可以将比赛表设计成一个n行n列的二维表,其中第 i 行第 j+1 列的元素表示和第 i 个选手在第 j 天比赛的选手号。
在具体进行代码实现时,可以先填满array的第一行,然后按照左上角数字与右下角数字相同的关系、左下角数字与右上角数字相同的关系,逐渐填满整张表就行。之所以说此问题中体现了分治思想,是因为可以不断对n进行n/2划分,直到划分为2人时,赛程就可确定,然后再逐渐合并出整个赛程安排。