文章目录
算法分析与设计
第2章 递归与分治策略
一、为什么提出分治法
有时候要求解的问题的【问题规模】太大了,直接解决过于困难
那不如我们把它分为许多个【子问题】,这些【子问题】与原问题很相似
【子问题】与【原问题】具有相同的性质
即 【原问题的解】 = 子问题1 + 子问题2 + 子问题3 + 。。。。。。
在【分治法】中常用的解决问题的技术是【递归技术】
二、递归是什么?
2.1 递归的概念
在【定义自身】的同时,又【直接】\【间接】的调用自己
2.2 递归的特点
- 描述简洁
- 结构清晰简单
- 容易证明算法的正确性
2.3 递归中应该注意什么问题呢?
要有中止条件
递归的算法会出现自身调用自身的情况,如果没有终止条件,那就会一直调用自身,无法停止
所谓的“简单问题”或者“小问题” 是指离中止条件更近的问题,且其解法与“大问题”相同。
2.4 如果编写递归算法呢?
举个例子:求:f(n) = n!
首先告知编写递归函数的步骤【递推】【回归】,接下来让我们感性的认识这两个概念
【递归】
要求 n! —》
就是求 n * (n-1) ! —》
就是求 (n-1)! = (n-1) * (n-2)! -----》
。。。 ----》
就是求 2 ! = 2 * 1!
这里 1!= 1 也就是终止条件
【回归】
已知 1! = 1
那就知道 2 ! = 2 * 1! = 2 * 1
那就知道 3! = 3 * 2!= 3 * 2
.。。。。。
就知道 (n-1) ! = (n-1) * (n-2)!
就知道 n! = n * (n-1)!
2.5 递归的适用情况?
-
我们已经知道了【递归是什么】,如何写【递归函数】的步骤
但是在什么情况下才应该用【递归】呢?
- 问题的定义是递归的
如斐波那契数列
F(n) = 1 n=0, 1
F(n-1) + F(n-2) n >1
- 递归定义的【数据结构】
链表、二叉树。。。
2.6 举个例子
-
汉诺塔问题
现在有三根柱子,标号为X,Y,Z,X柱子上从下到上按金字塔状叠放着n个不同大小的圆盘,现 在把所有盘子一个一个移动到柱子Z上,并且每次移动同一根柱子上都不能出现大盘子在小盘子上方,请问至少需要多少次移动,设移动次数为H(n)。
-
分析
n 【盘子数量】
n=1 A–>C 一次
n=2 A–>B A–>C B—>C 三次
n=3 七次【过程略 0.0】
n很大很大 写不出来了
我们这时候就可以用【递归】来解决这个问题
-
过程
当n=1时,将 编号为1的圆盘 从X柱子直接移到柱子Z上。
当n>1时,需要利用柱子Y作为辅助柱子,设法将n-1个较小的盘子按规则移到柱子Y中,然后将编号为n的盘子从X柱子移到Z柱子,最后将n-1个较小的盘子移到Z柱子中。
void Hanoi(int n,int X,int Y,int Z) {//通过Y,把n个盘子从 X-->Z //MOVE(n,a,b) 移动n 从a --》 b if(n==1) MOVE(1,X,Z) else { Hanoi(n-1,X,Z,Y); MOVE(1,X,Z); Hanoi(n-1,Y,X,Z); } }