5 函数(递归部分)
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
17
很显然这是一种递归解法。 很显然这是一种递归解法。它将问题分解成若干 同样类型的小问题, 同样类型的小问题,移动一个盘子的简单操作 就是终止条件。 就是终止条件。
18
A
B
C
A
B
C
Байду номын сангаас
将n个圆盘从A柱移到C柱的递归解法: 个圆盘从A柱移到C柱的递归解法: 柱上面的从上往下数的( 个圆盘移到B 柱上, 1 . 将 A 柱上面的从上往下数的 ( n-1) 个圆盘移到 B 柱上 , 中 间通过C柱为辅助。这是一个( 个圆盘的问题; 间通过C柱为辅助。这是一个(n-1)个圆盘的问题; 2. 将A柱上的最后一个圆盘,直接移到C柱上; 柱上的最后一个圆盘,直接移到C柱上; 3.再将B 柱上的 (n-1)个圆盘移到C柱上, 中间以A柱为辅助。 再将B 个圆盘移到C柱上,中间以A柱为辅助。 再将 柱上的( 这又是一个( 个圆盘的问题。 这又是一个(n-1)个圆盘的问题。 以上步骤将移动n个圆盘的问题转化为移动 b, int c) 以上步骤将移动 void move (int n, int a, int (n-1)个圆盘的 函数接口设计: 个圆盘的问题转化为移动 函数接口设计: 个圆盘的问题转化为移动( - ) 问题。 个盘子从 柱移动到c柱 问题。同理,我们可以继续把( - ) 功能: 同理,我们可以继续把(n-1)个圆盘的问题转化 个盘子从a柱移动到 功能:将n个盘子从 柱移动到 柱,中间借助于 b柱。 柱 为(n- 要移动的盘子数; ……,直到最后变成1个圆盘的 参数: -2)个圆盘的问题,……,直到最后变成 个圆盘的 参数:n:要移动的盘子数;a:源柱, b:辅助的柱 子, : )个圆盘的问题, :源柱, : 问题, 问题 这时候,问题就很容易解决了( c:目标柱 : ,这时候,问题就很容易解决了(直接移动就可以 了)。
10
2.递归过程 递归过程
• 在回归阶段,当获得最简单情况的解后,逐级 在回归阶段,当获得最简单情况的解后, 返回,依次得到稍复杂问题的解 。如在得到 返回, f(1)的解后,又依次得到 的解后, 的解后 又依次得到f(2)、f(3)…直到 、 …直到f(6)的 的 值。
11
3.递归程序设计 递归程序设计
12
3.递归程序设计 递归程序设计
一般来说,递归需要有边界条件、 一般来说,递归需要有边界条件、递归前进段和 递归返回段。当边界条件不满足时,递归前进; 递归返回段。当边界条件不满足时,递归前进;当 边界条件满足时,递归返回。 边界条件满足时,递归返回。 如何设计递归算法: 如何设计递归算法 1)对所求解的问题、要计算的函数书写出其递归 )对所求解的问题、 定义;注意一定要有终止条件和操作。 定义;注意一定要有终止条件和操作。 2)正确地设计参数。 )正确地设计参数。 注意:递归算法最外层肯定采用的是选择结构! 注意:递归算法最外层肯定采用的是选择结构!为 什么? 什么?
15
三、递归问题举例
一、汉诺塔问题 传说印度布拉马圣殿( 传说印度布拉马圣殿(Temple of Brahma)的教 ) 士们有一黄铜烧铸的平台, 士们有一黄铜烧铸的平台,上立三根金刚石柱 柱上堆放了64个金盘子 子。A柱上堆放了 个金盘子,每个盘子都比 柱上堆放了 个金盘子, 其下面的盘子略小一些。 其下面的盘子略小一些。当教士们将盘子全部 柱移到C柱以后 从A柱移到 柱以后,世界就到了末日。当然, 柱移到 柱以后,世界就到了末日。当然, 这个问题还有一些特定的条件, 这个问题还有一些特定的条件,那就是在柱子 之间只能移动一个盘子并且任何时候大盘子都 只能移动一个盘子并且 之间只能移动一个盘子并且任何时候大盘子都 不能放到小盘子上。教士们当然还在忙碌着, 不能放到小盘子上。教士们当然还在忙碌着, 因为这需要2 次移动。 因为这需要 64-1次移动。如果一次移动需要一 次移动 秒钟,那么全部操作需要5000亿年以上时间。 亿年以上时间。 秒钟,那么全部操作需要 亿年以上时间
16
同理,移动 个盘子的问题又可简化成移动 个盘子,移动4个盘 个盘子的问题又可简化成移动4个盘子 同理,移动5个盘子的问题又可简化成移动 个盘子,移动 个盘 这样,问题就简化成仅仅将5个盘子从 个盘子从A柱 这样,问题就简化成仅仅将 个盘子从 柱 子的问题又可简化成移动3个盘子 子的问题又可简化成移动 个盘子 ……这一过程反复进行下去 这一过程反复进行下去 移到B柱 再从B柱移到 柱移到C柱 移到 柱,再从 柱移到 柱。 直到只剩下一个盘子时将其移动 。
当n>=3 >
long fib(long n) 请分析该问题是否可以用递归算法解决? 请分析该问题是否可以用递归算法解决? { 若可以,请写出该递归算法。 若可以,请写出该递归算法。 if(n==1 || n==2) return n; else return fib(n-2)+fib(n-1); }
A(…) { … A(…); … } } A(…) { … B(…); … }
7
B(…) { … A(…); …
2.递归过程 递归过程
• 求f(6)的 ( ) 递归调用过程? 递归调用过程?
int f(int); main() { printf(“6!=%d”,f(6)); system(“pause”); } int f(int n) { if(n==0) return 1; else return n*f(n-1); }
函数--递归 第五章 函数 递归
1
提纲
1. 递归的概念 2. 递归过程 3. 递归程序设计
2
1.递归的概念 递归的概念
例:编写一个函数fac,计算阶乘 编写一个函数 ,计算阶乘n! 按过去的设计思想,该函数可以写成: 按过去的设计思想,该函数可以写成: int fac(int n) { int i,p; p=1; for(i=2;i<=n;i++) p=p*i; return p; }
• 什么样的问题可以用递归解决? 什么样的问题可以用递归解决? 如果解决问题的方法是把该问题分解成小的子 问题, 问题,并且这些小的子问题可以用同样的算法 解决, 解决,当分解到可以解决的比较简单的子问题 时分解过程即终止,那么就可以用递归。 时分解过程即终止,那么就可以用递归。 递归的思想就是将一个问题先转化为与原问题 性质相同、但规模小一级的新问题, 性质相同、但规模小一级的新问题,然后再重 复这样的转化, 复这样的转化,直到问题的规模减小到我们很 容易解决为止。 容易解决为止。
13
求斐波那契数列的第n项 例3:用函数 求斐波那契数列的第 项。斐波那契数 :用函数fib求斐波那契数列的第 列为: 、 、 、 、 、 函数fib定义如下 定义如下: 列为:0、1、1、2、3、…… 。函数 定义如下:
fib(n) = 0 当n=1 = 1 当n=2 = fib(n-2)+fib(n-1)
8
递归深度 0(主程序) 1 2 3 4 5 6
f(n) f(6) f(6)=6×f(5) f(5)=5×f(4) f(4)=4×f(3) f(3)=3×f(2) f(2)=2×f(1) f(1)=1×f(0) f(0)=1 (返回) [递推阶段]
2.递归过程 递归过程
6×120=720 5×24=120 4×6=24 3×2=6 2×1=2 1×1=1
1、问题分析(为简单起见,假设A柱上只有 个盘子) 、问题分析(为简单起见,假设 柱上只有 个盘子) 柱上只有6个盘子
A B C
欲将6个盘子从A柱移到 个盘子从A 欲将6个盘子从A柱移到C柱,只需先将上面5个盘子从A 个盘子从 柱移到C柱 只需先将上面5个盘子从 柱移到B柱 然后将最下面的盘子从A柱移到 柱移到C柱 柱移到 柱,然后将最下面的盘子从 柱移到 柱,最后 柱上的5个盘子从 柱移到C柱 将B柱上的 个盘子从 柱移到 柱。 柱上的 个盘子从B柱移到 A B C
根据以上数学 定义,函数f能 定义,函数 能 否写成右边所 示?函数能否 调用自身? 调用自身?
int f(int n) { if(n==0) return 1; else return n*f(n-1); }
答案是肯定 的。C系统 系统 会保证调用 过程的正确 性,这就是 递归! 递归!
4
int f(int n) { if(n==0) 递归的定义: 递归的定义: return 1; 从程序书写来看,在定义一个函数时, 从程序书写来看,在定义一个函数时,若在定 else return 义它的内部又出现对它本身的调用, n*f(n-1); 义它的内部又出现对它本身的调用,则称该函数 是递归的或递归定义的。 int 是递归的或递归定义的。 } f(int n) { 从函数动态运行来看,当调用一个函数A时 从函数动态运行来看,当调用一个函数 时, if(n==0) 在进入函数A且还没有退出(返回)之前,又再 在进入函数 且还没有退出(返回)之前, 且还没有退出 return 一次由于调用A本身而再一次进入函数 本身而再一次进入函数A, 一次由于调用 本身而再一次进入函数 1;,则称 else 之为函数A的递归调用 的递归调用。 之为函数 的递归调用。 return n*f(n-1); }
请画出求fib(3)的递归调用过程图示 的递归调用过程图示 请画出求
14
3.递归程序设计 递归程序设计
• 每求一项数,需要递归调用2次该函数;计算 每求一项数,需要递归调用 次该函数 次该函数; 斐波那契数列第30项的递归调用次数是 的30 斐波那契数列第 项的递归调用次数是2的 项的递归调用次数是 次方(大约10亿次 亿次!) 次方(大约 亿次!) • 可见递归的思想特别符合人们的思维习惯,便 可见递归的思想特别符合人们的思维习惯, 于问题解决和编程实现。 于问题解决和编程实现。但递归的程序设计方 法比较占用系统资源,效率也较低。 法比较占用系统资源,效率也较低。 • 课下请改写 函数,该用非递归方式实现 课下请改写fib函数 函数, long fib(long), 计算斐波那契数列第 项。 计算斐波那契数列第n项
6
1.递归的概念 递归的概念
递归可以分为直接递归和间接递归两种。 递归可以分为直接递归和间接递归两种。 直接递归:函数体里面发生对自己的调用; 直接递归:函数体里面发生对自己的调用; 间接递归:函数A调用函数B 而函数B 间接递归:函数A调用函数B,而函数B又直接或 间接地调用函数A 间接地调用函数A。
3
1.递归的概念 递归的概念
现在换一个角度考虑, !不仅是1× × × 现在换一个角度考虑,n!不仅是 ×2×3×…×n, 还可以定义成: 还可以定义成: 设 f(n)=n! 1 当n=0 =
n! = 则 f(n) = 1 当n=0 = n×(n-1)! 当n>0 × - > n×f (n-1) 当n>0 > × -
9
[回归阶段]
2.递归过程 递归过程
可见,递归算法的执行过程分递推和回归两个阶段。 可见,递归算法的执行过程分递推和回归两个阶段 递推 两个阶段 当递推时,并没有求值的计算操作, 当递推时,并没有求值的计算操作,实际的计算操 作是在回归过程实现的。 作是在回归过程实现的。 递推阶段是个不断简化问题的阶段: 递推阶段是个不断简化问题的阶段:把对较复杂问 规模为n) 题(规模为 )的求解转化为比原问题简单一些的问 规模小于n) 例如对fib(6)的求解转化 题(规模小于 )的求解 。例如对 的求解转化 的求解, 的求解转化为fib(4)的求 为fib(5)的求解, 对fib(5)的求解转化为 的求解 的求解转化为 的求 直到转化为对fib(0)的求解。 的求解。 解…直到转化为对 的求解 当递推到最简单的不用再简化的问题时,递推终止。 当递推到最简单的不用再简化的问题时,递推终止。 函数中, = 的情况 的情况。 如f函数中,n=0的情况。 函数中
5
1.递归的概念 递归的概念
次幂。 例2:求x的n次幂。函数 : 的 次幂
x
n
可定义如下: 可定义如下:
x
n
1 = x *x
n −1
当n=0 = 当n>0 >
float power(float x,int n) , { if(n==0) return 1; else return x*power(x, n-1); }