算法导论第四章分治策略编程实践(二)

  在上一篇中,通过一个求连续子数组的最大和的例子讲解,想必我们已经大概了然了分治策略和递归式的含义,可能会比较模糊,知道但不能用语言清晰地描述出来。但没关系,我相信通过这篇博文,我们会比较清楚且容易地用自己的话来描述。

  通过前面两章的学习,我们已经接触了两个例子:归并排序和子数组最大和。这两个例子都用到了分治策略,通过分析,我们可以得出分治策略的思想:顾名思义,分治是将一个原始问题分解成多个子问题,而子问题的形式和原问题一样,只是规模更小而已,通过子问题的求解,原问题也就自然出来了。总结一下,大致可以分为这样的三步:

分解:将原问题划分成形式相同的子问题,规模可以不等,对半或2/3对1/3的划分。

解决:对于子问题的解决,很明显,采用的是递归求解的方式,如果子问题足够小了,就停止递归,直接求解。

合并:将子问题的解合并成原问题的解。

  这里引出了一个如何求解子问题的问题,显然是采用递归调用栈的方式。因此,递归式与分治法是紧密相连的,使用递归式可以很自然地刻画分治法的运行时间。所以,如果你要问我分治与递归的关系,我会这样回答:分治依托于递归,分治是一种思想,而递归是一种手段,递归式可以刻画分治算法的时间复杂度。所以就引入本章的重点:如何解递归式?

解递归式的三种方法

这里有三种方法:代入法、递归树法和主方法。(下面这一部分结合有些网友的总结和我的总结得来)

代入法:

定义:先猜测某个界的存在,再用数学归纳法去证明该猜测的正确性。
缺点:只能用于解的形式很容易猜的情形。
总结:这种方法需要经验的积累,可以通过转换为先前见过的类似递归式来求解。

递归树法:

起因:代换法有时很难得到一个正确的好的猜测值。
用途:画出一个递归树是一种得到好猜测的直接方法。
分析(重点):在递归树中,每一个结点都代表递归函数调用集合中一个子问题的代价。将递归树中每一层内的代价相加得到一个每层代价的集合,再将每层的代价相加得到递归式所有层次的总代价。
总结:递归树最适合用来产生好的猜测,然后用代换法加以验证。
递归树的方法非常直观,总的代价就是把所有层次的代价相加起来得到。但是分析这个总代价的规模却不是件很容易的事情,有时需要用到很多数学的知识。

主方法:

主方法是最好用的方法,书本上以”菜谱“来描述这种方法的好用之处,它可以瞬间估计一个递推式的算法复杂度。但是我们知道,这后面肯定是严格的数学证明在支撑着,对于我们用户来说,我们只用知道怎么用就行了。

优点:针对形如T(n) = af(n/b) + f(n)的递归式

缺点:并不能解所有上述形式的递归式,有一些特殊情况,见下文分析。

分析:三种情况,如下图,着重看圈线的部分:

直觉:看 f(n) 和 nlogba 的关系,谁大取谁,相等则两个相乘,但要注意看是否相差因子 nε。对于3),还要看是否满足条件 af(n/b) <= cf(n) .

就像上面所说的,该方法不能用于所有的形如上式的递归式,f(n)和nlogba的关系必须是多项式意义上的小于大于,即渐近关系(渐近小于、渐近大于),什么是渐近,就是两者相差一个因子nε。所以,在情况1和情况2之间有一定的间隙,同样情况2和请看3之间也有一定的间隙;对于情况3,还要看是否满足正则条件。

  通过上面的讲述,我相信自己应该讲清楚了这三种方法,你也许还是有些困惑,但没关系,你只是缺乏例子的引导,下面我们就来看几个例子,其充分应用到了这三种方法。

代入法:(凭直觉、经验)

1)、习题4.3-1:T(n) = T(n-1) + n

2)、习题4.3-2:T(n) = T(n/2) + 1

递归树法:

1)、对递归式T(n) = 3T(n/2) +n,利用递归树确定一个好的渐近上界,用代入法进行验证。

2)、对递归式T(n) = T(n/2) + n2,利用递归树确定一个好的渐近上界,用代入法进行验证。

主方法:

1)、对于下列递归式,使用主方法求出渐近紧确界。

  a、T(n) = 2T(n/4) + 1

  b、T(n) = 2T(n/4) + n1/2

  c、T(n) = 2T(n/4) + n

  d、T(n) = 2T(n/4) + n2

好了,以上只是热身用的,关于更多的课后习题的解答,请详见:http://www.cnblogs.com/Jiajun/archive/2013/05/08/3066979.html

时间: 2024-10-23 02:35:32

算法导论第四章分治策略编程实践(二)的相关文章

算法导论 第四章 分治策略

分治策略中,我们递归地求解了一个问题,在每层递归都应用了三步 1.分解,将问题划分为一些子问题,子问题的形式与原问题一样,只是规模更小 2.解决,递归地求解出子问题,如果子问题的规模足够小,则停止递归,直接求解 3.合并,把子问题的解给合并为原问题的解 当子问题足够大的时候,需要递归,那就是递归情况 当问题足够小的时候,不需要递归,那就是基本情况 三种求解递归式的方法:代入法 猜测一个界,用数学归纳法来证明这个界 递归树法 将递归式转化为一棵树,其节点表示不同层次的递归调用产生的代价,然后采用边

第四章 分治策略 4.1 最大子数组问题 (暴力求解算法)

/** * 最大子数组的暴力求解算法,复杂度为o(n2) * @param n * @return */ static MaxSubarray findMaxSubarraySlower(int[] n) { long tempSum = 0; int left = 0; int right = 0; long sum = Long.MIN_VALUE; for (int i = 0; i < n.length; i++) { for (int j = i; j < n.length; j++

第四章 分治策略 4.1 最大子数组问题(自己想的,不知道是不是减治法)

package chap04_Divide_And_Conquer; import static org.junit.Assert.*; import java.util.Arrays; import org.junit.Test; /** * 算反导论第四章 4.1 最大子数组 * * @author xiaojintao * */ public class Maximum_Subarray_Problem { /** * 最大子数组类 left为头部索引,right为尾部索引,sum为数组和

第四章 分治策略 4.1 最大子数组问题 (减治法,别人的,拿来看看)

/** * 获得连续子数组的最大和 * * @author dfeng * */ private static long getMax(long a, long b) { return a > b ? a : b; } /** * 获得连续子数组的最大和 * * @param array * @return 最大和,此处用了Long型是为了表示当参数为null或空时,可以返回null,返回其它任何数字都可能引起歧义. */ public static Long getMax(int[] arra

第四章 分治策略——最大子数组问题

最大子数组问题 方法一:暴力求解方法 我们可以很容易地设计出一个暴力方法来求解本问题:简单地尝试没对可能的子数组,共有O(n2)种 #include<iostream> using namespace std; #define INT_MIN 0x80000000 int main() { int arr[10]={9,8,-3,-5,7,-39,79,-37,8,9}; int i,j; int sum=0,maxsum=INT_MIN; int imax; for(i=0;i<10;

第四章 分治策略 4.2 矩阵乘法的Strassen算法

package chap04_Divide_And_Conquer; import static org.junit.Assert.*; import java.util.Arrays; import org.junit.Test; /** * 矩阵相乘的算法 * * @author xiaojintao * */ public class MatrixOperation { /** * 普通的矩阵相乘算法,c=a*b.其中,a.b都是n*n的方阵 * * @param a * @param b

算法导论 第三章 and 第四章 python

第三章 渐进的基本O().... 常用函数 % 和  // 转换 斯特林近似公式 斐波那契数 第四章 分治策略:分解(递归)--解决(递归触底)--合并 求解递归式的3种方法: 1:代入法(替代法):猜测一个(靠经验)--数学归纳法 ·2:递归树法:画树p31[第3版中文]p51->递归式--证明 3:主方法: 快速,有些地方不能涉及,递归式不易写出 4.1最大数组问题 分治法: 1.A[low ,mid]  2.A[mid+1, high] 3.包含mid中间(想左和右分别遍历组合找出最大)

算法导论 第2章

本章主要是算法知识的基础讲解,介绍了循环不变式,几个简单的排序算法,递归分治算法等内容. 1.循环不变式 循环不变式主要用来说明算法的正确性,那么什么是循环不变式呢,其实就是在循环过程中,一些元素数据必须保持的一些性质,例如在插入排序中,数组为A,必须保证三个性质: (1) 初始化:在循环开始之前,循环不变式是成立的,即:A[0]是有序的,A[1...n-1]是无序的. (2) 保持:在循环的某一次迭代开始之前,循环不变式是成立的,那么在此次迭代结束后依然应该是成立的,即:A[0...i]是有序

Java-第十四章-代参的方法(二)-编程实现,输入班里10名学生的身高,获得身高最高的学生要求对象数组类型方法

package com.ww.yzpA; public class Students { int No; int Height; } package com.ww.yzpA; public class Height { public Students getMaxHeigth(Students[] str) { Students A = new Students(); for (int i = 0; i < str.length; i++) { if (str[i].Height > A.He