第2讲 递归与分治策略.ppt_第1页
第2讲 递归与分治策略.ppt_第2页
第2讲 递归与分治策略.ppt_第3页
第2讲 递归与分治策略.ppt_第4页
第2讲 递归与分治策略.ppt_第5页
已阅读5页,还剩75页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第2讲递归与分治策略 王静河南理工大学计算机学院2013年3月 第2讲递归与分治策略 n个元素的排序问题 当n 1时 不需任何计算 当n 2时 只要做一次比较即可排好序 当n 3时 只要做两次比较即可 当n较大时 问题就不那么容易处理了 是否可以将原问题分割成一些规模较小且相同的子问题来求解 第2讲递归与分治策略 分治法的设计思想 将一个难以直接解决的大问题 分割成一些规模较小的相同问题 以便各个击破 分而治之 由分治法产生的子问题往往是原问题的较小模式 这就为使用递归技术提供了方便 在这种情况下 反复应用分治手段 可以使子问题与原问题类型一致而其规模却不断缩小 最终使子问题缩小到很容易直接求出其解 这自然导致递归过程的产生 分治与递归像一对孪生兄弟 经常同时应用在算法设计之中 并由此产生许多高效算法 第2讲递归与分治策略 递归的概念分治法的基本思想分治法范例学习 第2讲递归与分治策略 2 1递归的概念直接或间接地调用自身的较小模式的算法称为递归算法 用函数自身的较小模式给出其定义的函数称为递归函数 第2讲递归与分治策略 递归算法的特点递归就是在过程或函数里调用自身 在使用递归策略时 必须有一个明确的递归结束条件 称为递归出口 递归算法解题通常显得很简洁 但递归算法解题的运行效率较低 所以一般不提倡用递归算法设计程序 在递归调用的过程当中系统为每一层的返回点 局部量等开辟了栈来存储 递归次数过多容易造成栈溢出等 所以一般不提倡用递归算法设计程序 第2讲递归与分治策略 利用递归算法实现象棋游戏程序 第2讲递归与分治策略 例1阶乘函数阶乘函数可递归地定义为 边界条件 递归方程 边界条件与递归方程是递归函数的二个要素 递归函数只有具备了这两个要素 才能在有限次计算后得出结果 factorial intn if n 0 return1 elsereturnn factorial n 1 第2讲递归与分治策略 例1阶乘函数阶乘函数的非递归定义形式 factorial intn inti p 1 for i 1 i n i p p i returnp 第2讲递归与分治策略 include stdafx h includeintFactorial intn if n 0 return1 returnn Factorial n 1 intmain intargc char argv intn intm cout n m Factorial n cout nn的阶乘n 等于 m endl return0 第2讲递归与分治策略 include stdafx h includeintmain intargc char argv intn m 1 cout n for i 1 i n i m m i cout nn的阶乘n 等于 m endl return0 第2讲递归与分治策略 有趣的兔子问题一般而言 兔子在出生两个月后 就有繁殖能力 一对兔子每个月能生出一对小兔子来 如果所有兔子都不死 那么一年以后可以繁殖多少对兔子 第2讲递归与分治策略 分析如下 第一个月小兔子没有繁殖能力 所以还是一对 两个月后 生下一对小兔子 总数共有两对 三个月以后 老兔子又生下一对 因为小兔子还没有繁殖能力 总数共是三对 依次类推可以列出下表 第2讲递归与分治策略 例2Fibonacci数列无穷数列1 1 2 3 5 8 13 21 34 55 称为Fibonacci数列 它可以递归地定义为 边界条件 递归方程 第n个Fibonacci数可递归地计算如下 fibonacci intn if n 1 return1 elsereturnfibonacci n 1 fibonacci n 2 第2讲递归与分治策略 Fibonacci函数的非递归方式定义 第2讲递归与分治策略 include stdafx h includeintFibonacci intn if n n m Fibonacci n cout n第 n 费波拿契数等于 m endl return0 第2讲递归与分治策略 include stdafx h includeintmain intargc char argv intn m a b cout n cout n前 n 1 费波拿契数为 endl a 1 b 1cout a endl b endl for i 1 i n 1 i m a b cout m endl a b b m return0 第2讲递归与分治策略 例3Ackerman函数当一个函数及它的一个变量是由函数自身定义时 称这个函数是双递归函数 Ackerman函数A n m 定义如下 本例中的Ackerman函数无法找到非递归的定义 第2讲递归与分治策略 例4排列问题设计一个递归算法生成n个元素 r1 r2 rn 的全排列 设R r1 r2 rn 是要进行排列的n个元素 Ri R ri 集合X中元素的全排列记为perm X ri perm X 表示在全排列perm X 的每一个排列前加上前缀得到的排列 R的全排列可归纳定义如下 当n 1时 perm R r 其中r是集合R中唯一的元素 当n 1时 perm R 由 r1 perm R1 r2 perm R2 rn perm Rn 构成 第2讲递归与分治策略 第2讲递归与分治策略 include stdafx h includevoidPerm Typelist intk intm if k m for inti 0 i m i cout list i cout endl elsefor inti k i m i Swap list k list i Perm list k 1 m Swap list k list i 第2讲递归与分治策略 inlinevoidSwap Type 第2讲递归与分治策略 例5整数划分问题将正整数n表示成一系列正整数之和 n n1 n2 nk 其中n1 n2 nk 1 k 1 正整数n的这种表示称为正整数n的划分 求正整数n的不同划分个数 例如正整数6有如下11种不同的划分 6 5 1 4 2 4 1 1 3 3 3 2 1 3 1 1 1 2 2 2 2 2 1 1 2 1 1 1 1 1 1 1 1 1 1 第2讲递归与分治策略 例5整数划分问题前面的几个例子中 问题本身都具有比较明显的递归关系 因而容易用递归函数直接求解 在本例中 如果设p n 为正整数n的划分数 则难以找到递归关系 因此考虑增加一个自变量 将最大加数n1不大于m的划分个数记作q n m 可以建立q n m 的如下递归关系 第2讲递归与分治策略 include stdafx h includeintq intn intm if n 1 m 1 return0 if n 1 m 1 return1 if n m returnq n n if n m returnq n m 1 1 returnq n m 1 q n m m 第2讲递归与分治策略 intmain intargc char argv intn m cout n m q n n cout n n 的不同划分的个数等于 m endl return0 第2讲递归与分治策略 例6Hanoi塔问题设a b c是3个塔座 开始时 在塔座a上有一叠共n个圆盘 这些圆盘自下而上 由大到小地叠在一起 各圆盘从小到大编号为1 2 n 现要求将塔座a上的这一叠圆盘移到塔座b上 并仍按同样顺序叠置 在移动圆盘时应遵守以下移动规则 规则1 每次只能移动1个圆盘 规则2 任何时刻都不允许将较大的圆盘压在较小的圆盘之上 规则3 在满足移动规则1和2的前提下 可将圆盘移至a b c中任一塔座上 第2讲递归与分治策略 include stdafx h includevoidhanoi intn inta intb intc if n 0 hanoi n 1 a c b move a b cout n将第 n 号盘从第 a 号柱移到第 b 号柱 hanoi n 1 c b a 第2讲递归与分治策略 intmain intargc char argv intn cout n hanoi n 1 2 3 cout endl return0 第2讲递归与分治策略 课堂练习 1 有5个人坐在一起 问第五个人多少岁 他说比第4个人大2岁 问第4个人岁数 他说比第3个人大2岁 问第三个人 又说比第2人大两岁 问第2个人 说比第一个人大两岁 最后问第一个人 他说是10岁 请问第五个人多大 用递归算法实现 第2讲递归与分治策略 classProgram staticvoidMain string args Programp newProgram Console WriteLine p age 5 intage intn intc if n 1 return10 else c age n 1 2 returnc 第2讲递归与分治策略 课堂练习 2 猴子吃桃 海滩上有一堆桃子 五只猴子来分 第一只猴子把这堆桃子凭据分为五份 多了一个 这只猴子把多的一个扔入海中 拿走了一份 第二只猴子把剩下的桃子又平均分成五份 又多了一个 它同样把多的一个扔入海中 拿走了一份 第三 第四 第五只猴子都是这样做的 问海滩上原来最少有多少个桃子 第2讲递归与分治策略 算法设计思路 设这堆桃子有x个 第n个猴子连丢带拿共得到an个桃子 当n 2时 an 1 5 x a1 a2 an 1 1 得 an an 1 1 5an 1 即an 4 5an 1 第2讲递归与分治策略 intcount 0 intfunc intnum inttemp num 1 if temp 5 0 第2讲递归与分治策略 includevoidmain inti 4 m j k count while true count 0 m i for k 0 k 5 k j m 4 5 1 i代表下一个猴子能够看到的数 j代表当前猴子能够看到的数 m j if j 4 0 count elsebreak if count 4 printf 一开始个数为 d n j break i 4 第2讲递归与分治策略 递归小结 优点 结构清晰 可读性强 而且容易用数学归纳法来证明算法的正确性 因此它为设计算法 调试程序带来很大方便 缺点 递归算法的运行效率较低 无论是耗费的计算时间还是占用的存储空间都比非递归算法要多 第2讲递归与分治策略 递归小结 解决方法 在递归算法中消除递归调用 使其转化为非递归算法 1 采用一个用户定义的栈来模拟系统的递归调用工作栈 该方法通用性强 但本质上还是递归 只不过人工做了本来由编译器做的事情 优化效果不明显 2 用递推来实现递归函数 3 通过变换能将一些递归转化为尾递归 从而迭代求出结果 后两种方法在时空复杂度上均有较大改善 但其适用范围有限 第2讲递归与分治策略 2 2分治法的基本思想 将问题分为k个子问题 对这k个子问题分别求解 如果子问题的规模仍然不够小 则每个子问题再划分为k个子问题 如此递归的进行下去 直到问题规模足够小 很容易求出其解为止 第2讲递归与分治策略 将求出的小规模的问题的解合并为一个更大规模的问题的解 自底向上逐步求出原来问题的解 第2讲递归与分治策略 分治法的适用条件 分治法所能解决的问题一般具有以下几个特征 该问题的规模缩小到一定的程度就可以容易地解决 该问题可以分解为若干个规模较小的相同问题 即该问题具有最优子结构性质 利用该问题分解出的子问题的解可以合并为该问题的解 该问题所分解出的各个子问题是相互独立的 即子问题之间不包含公共的子问题 第2讲递归与分治策略 divide and conquer P if P n0 adhoc P 解决小规模的问题dividePintosmallersubinstancesP1 P2 Pk 分解问题for i 1 i k i yi divide and conquer Pi 递归的解各子问题returnmerge y1 yk 将各子问题的解合并为原问题的解 分治法的基本步骤 人们从大量实践中发现 在用分治法设计算法时 最好使子问题的规模大致相同 即将一个问题分成大小相等的k个子问题的处理方法是行之有效的 这种使子问题规模大致相等的做法是出自一种平衡 balancing 子问题的思想 它几乎总是比子问题规模不等的做法要好 第2讲递归与分治策略 分治法的复杂性分析 一个分治法将规模为n的问题分成k个规模为n m的子问题去解 设分解阀值n0 1 且adhoc解规模为1的问题耗费1个单位时间 再设将原问题分解为k个子问题以及用merge将k个子问题的解合并为原问题的解需用f n 个单位时间 用T n 表示该分治法解规模为 P n的问题所需的计算时间 则有 通过迭代法求得方程的解 注意 递归方程及其解只给出n等于m的方幂时T n 的值 但是如果认为T n 足够平滑 那么由n等于m的方幂时T n 的值可以估计T n 的增长速度 通常假定T n 是单调上升的 从而当mi n mi 1时 T mi T n T mi 1 第2讲递归与分治策略 第2讲递归与分治策略 当n ml时 l logmn 第2讲递归与分治策略 分析 很显然此问题分解出的子问题相互独立 即在a i 的前面或后面查找x是独立的子问题 因此满足分治法的第四个适用条件 例1二分搜索技术 给定已按升序排好序的n个元素a 0 n 1 现要在这n个元素中找出一特定元素x 分析 该问题的规模缩小到一定的程度就可以容易地解决 该问题可以分解为若干个规模较小的相同问题 分解出的子问题的解可以合并为原问题的解 分解出的各个子问题是相互独立的 第2讲递归与分治策略 二分搜索算法的基本思想 将n个元素分成个数大致相同的两半 取a n 2 与x进行比较 1 如果x a n 2 则找到x 算法终止 2 如果xa n 2 则只要在数组a的右半部继续搜索x 例1二分搜索技术 第2讲递归与分治策略 据此容易设计出二分搜索算法 BinarySearch inta intx intn 在a 0 a middle left middle 1 elseright middle 1 return 1 未找到x 第2讲递归与分治策略 算法复杂度分析 每执行一次算法的while循环 待搜索数组的大小减少一半 因此 在最坏情况下 while循环被执行了O logn 次 循环体内运算需要O 1 时间 因此整个算法在最坏情况下的计算时间复杂性为O logn 第2讲递归与分治策略 课堂练习 设a 0 n 1 是已排好序的数组 请改写二分搜索算法 使得当搜索元素x不在数组中时 返回小于x的最大元素位置i和大于x的最小元素位置j 当搜索元素在数组中时 i和j相同 均为x在数组中的位置 第2讲递归与分治策略 BinarySearch inta intx intn int 未找到x 第2讲递归与分治策略 例2大整数的乘法 请设计一个有效的算法 可以进行两个n位大整数的乘法运算 小学的方法 O n2 效率太低分治法 X Y X a2n 2 bY c2n 2 dXY ac2n ad bc 2n 2 bd a b c d 复杂度分析T n O n2 没有改进 第2讲递归与分治策略 k 4 m 2 n 2l 第2讲递归与分治策略 为了降低时间复杂度 必须减少乘法的次数 XY ac2n a c b d ac bd 2n 2 bdXY ac2n a c b d ac bd 2n 2 bd 细节问题 两个XY的复杂度都是O nlog3 但考虑到a c b d可能得到m 1位的结果 使问题的规模变大 故不选择第2种方案 例2大整数的乘法 复杂度分析T n O nlog3 O n1 59 较大的改进 第2讲递归与分治策略 k 3 m 2 n 2l 第2讲递归与分治策略 请设计一个有效的算法 可以进行两个n位大整数的乘法运算 小学的方法 O n2 效率太低分治法 O n1 59 较大的改进更快的方法 如果将大整数分成更多段 用更复杂的方式把它们组合起来 将有可能得到更优的算法 最终的 这个思想导致了快速傅利叶变换 FastFourierTransform 的产生 该方法也可以看作是一个复杂的分治算法 对于大整数乘法 它能在O nlogn 时间内解决 是否能找到线性时间的算法 目前为止还没有结果 例2大整数的乘法 第2讲递归与分治策略 例3Strassen矩阵乘法 A和B的乘积矩阵C中的元素C i j 定义为 若依此定义来计算A和B的乘积矩阵C 则每计算C的一个元素C i j 需要做n次乘法和n 1次加法 因此 算出矩阵C的n2个元素所需的计算时间为O n3 传统方法 O n3 第2讲递归与分治策略 使用与上例类似的技术 将矩阵A B和C中每一矩阵都分块成4个大小相等的子矩阵 由此可将方程C AB重写为 由此可得 分治法 复杂度分析T n O n3 例3Strassen矩阵乘法 第2讲递归与分治策略 k 8 m 2 n 2l 第2讲递归与分治策略 为了降低时间复杂度 必须减少乘法的次数 复杂度分析T n O nlog7 O n2 81 较大的改进 第2讲递归与分治策略 k 7 m 2 n 2l 第2讲递归与分治策略 传统方法 O n3 分治法 O n2 81 更快的方法 Hopcroft和Kerr已经证明 1971 计算2个 矩阵的乘积 7次乘法是必要的 因此 要想进一步改进矩阵乘法的时间复杂性 就不能再基于计算2 2矩阵的7次乘法这样的方法了 或许应当研究 或 矩阵的更好算法 在Strassen之后又有许多算法改进了矩阵乘法的计算时间复杂性 目前最好的计算时间上界是O n2 376 是否能找到O n2 的算法 例3Strassen矩阵乘法 第2讲递归与分治策略 例4合并排序 基本思想 将待排序元素分成大小大致相同的2个子集合 分别对2个子集合进行排序 最终将排好序的子集合合并成为所要求的排好序的集合 MergeSort inta intleft intright if left right 至少有2个元素inti left right 2 取中点mergeSort a left i mergeSort a i 1 right merge a b left i right 合并到数组bcopy a b left right 复制回数组a 复杂度分析T n O nlogn 渐进意义下的最优算法 第2讲递归与分治策略 k 2 m 2 n 2l 第2讲递归与分治策略 64 算法mergeSort的实现 第2讲递归与分治策略 合并排序算法复杂度 最坏时间复杂度 O nlogn 平均时间复杂度 O nlogn 辅助空间 O n 稳定性 稳定 第2讲递归与分治策略 例5快速排序 在快速排序中 记录的比较和交换是从两端向中间进行的 关键字较大的记录一次就能交换到后面单元 关键字较小的记录一次就能交换到前面单元 记录每次移动的距离较大 因而总的比较和移动次数较少 快速排序是对气泡排序的一种改进方法 它是由C A R Hoare于1962年提出的 第2讲递归与分治策略 例5快速排序 第2讲递归与分治策略 qSort intp intr if p r intq partition p r 以a p 为基准元素将a p r 划分成3段a p q 1 a q 和a q 1 r 使得a p q 1 中任何元素小于等于a q a q 1 r 中任何元素大于a q 下标q在划分过程中确定 qSort p q 1 对左半段排序qSort q 1 r 对右半段排序 第2讲递归与分治策略 partition intp intr inti p intj r 1 intx a p 将x的元素交换到右边区域while true while a i x if i j break swap a i j a p a j a j x returnj 初始序列 j 5 7 5 2 6 8 i 5 6 5 2 7 8 j 5 2 5 6 7 8 i 完成 5 2 5 6 7 8 第2讲递归与分治策略 最坏时间复杂度 O n2 平均时间复杂度 O nlogn 最好时间复杂度 O nlogn 辅助空间 O n 或O logn 稳定性 不稳定 快速排序算法复杂度 第2讲递归与分治策略 例6循环赛日程表 设计一个满足以下要求的比赛日程表 1 每个选手必须与其他n 1个选手各赛一次 2 每个选手一天只能赛一次 3 循环赛一共进行n 1天 按分治策略 将所有的选手分为两半 n个选手的比赛日程表就可以通过为n 2个选手设计的

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论