算法设计与分析第二章:递归与分治策略

 主定理—递归式求解

主定理:设a>=1,b>1和d>=0,设f(n)为一函数,T(n)由递归式

T(n)=aT(n/b)+\Theta (n^{d})   , 那么

1>.如果a<b^{d}T(n)=\Theta (n^{d})

2>.如果a=b^{d}T(n)=\Theta (n^{d}logn)

3>.如果a>b^{d}T(n)=\Theta (n^{log_{b}a})

分治法经典范例

1>二分搜索

该问题的常见形式是在一个有序数组中寻找某个元素。假设数组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步。


2>大整数乘法

 由上图可以看出用分治法来实现大整数相乘的思路:
   1>首先将要相乘的两个数X和Y分成A,B,C,D四部分。
   2>此时将X和Y的乘积转化为图中的式子,把问题转化为求解式子的值。
   3>递归处理,直至算出最后的结果。

大整数乘法详解
3>Strassen矩阵乘法

使用分治法,将一个矩阵转换为子矩阵相乘的方式。矩阵乘法耗费时间要比矩阵加法耗费的时间多,想要改进矩阵乘法的计算时间复杂性,必须减少乘法运算。Strassen矩阵乘法用了7次对于n/2阶矩阵乘积的递归调用和18次n/2阶矩阵的加减运算。


4>棋盘覆盖

 在解决该问题时,需要将原始的棋盘划分成四个元素个数相同的棋盘,再根据特殊元素是否在划分后的区域进行不同的处理;然后递归地执行这个过程,直到最后划分的区域为包含四个元素单位。不难看出,这里面也体现了分–治的思想。


5>合并排序

即归并排序,是典型的一种分治思想的运用,其过程如下:
   1>分:将待排序元素划分成大小大致相同的两个子序列,直到每个子序列只有1个元素。
   2>治:对两个子序列进行合并排序。
   3>合:将排好序的有序子序列进行合并,得到最终的有序序列。

最坏时间复杂度:O(nlogn)
最好时间复杂度:O(nlogn)
平均时间复杂度:O(nlogn)
稳定性:稳定


6>快速排序

归并排序是将待排列元素打散再重新聚合,快速排序是将待排列元素持续分堆,两者排序的过程中都是体现着不断拆分为子问题的痕迹,所以其实快速排序也是用分治思想来实现的。
  快速排序的步骤如下:
   1>先从数列中取出一个数作为基准数。
   2>分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
   3>再对左右区间重复第二步,直到各区间只有一个数。

最坏时间复杂度:O(n^2) 
最好时间复杂度:O(nlogn)
平均时间复杂度: O(nlogn)
稳定性:不稳定


7>线性时间选择

此算法常使用的场景是:找出待排序序列中, 第k大或第k小元素(1<k<n)。
  此算法使用步骤如下:
   1>分组并取各组中位数 (将元素每5个分成一组,分别排序,并将该组中位数与该组的首元素交换,目的是使所有组的中位数都排列在数组最左侧,以便进一步查找中位数的中位数 。
   2>查找中位数的中位数。
   3>进行划分过程,即每轮排序后中位数对应的下标,在整个序列中的相对位置。
   4>判断第k个数在划分结果的左边、右边还是恰好是划分结果本身,前两者递归处理,后者直接返回答案。


8>最接近点对问题

 该问题指的是:在一个平面上,有着许多的散点,如果找出欧式距离最近的两个点。从问题表面可以看出,该问题可以用暴力法求解,即求出所有点之间的距离,再统一进行比较,选出距离最近的点对。但这样做,难免时间复杂度较高,所以就需要用别的解法来计算,常用的是分治法:即按X坐标或Y坐标将元素区分成两部分,然后不断划分,直到每个子区间中只有一个元素,求出左右区间中最小点对之间的距离,这样就求出了两个区间最小值。接下来要求出最复杂的第三个最小值:两个点在不同的子区间,如何在不同区间寻找这两个点就成了最近点对问题的难点。
  具体步骤如下:
   1>选择所有点的某一坐标(X坐标或Y坐标,此处以X轴为例),求出平均值,划分中轴线,将数据按某一坐标轴分为左右两个部分。
   2>求出左半边和右半边的最小距离,选取较小值d,此步骤可以用递归实现。
   3>根据上一步求出的d,求出最小点对在不同区间时的最小距离。
   4>比较这三个最小距离。
分治法求解平面最近点对问题


9>循环赛日程表

该问题描述为:设有n=2^k个运动员要进行网球循环赛。现要设计一各满足一下要求的比赛日程表:
   1>每个选手必须与其他n-1个选手各比赛一次。
   2>每个选手一天只能赛一次。
   3>循环赛一共进行n-1天。
  按照上面的要求,可以将比赛表设计成一个n行n列的二维表,其中第 i 行第 j+1 列的元素表示和第 i 个选手在第 j 天比赛的选手号。
  在具体进行代码实现时,可以先填满array的第一行,然后按照左上角数字与右下角数字相同的关系、左下角数字与右上角数字相同的关系,逐渐填满整张表就行。之所以说此问题中体现了分治思想,是因为可以不断对n进行n/2划分,直到划分为2人时,赛程就可确定,然后再逐渐合并出整个赛程安排。
 

 

 

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值