c语言递归算法.ppt
《c语言递归算法.ppt》由会员分享,可在线阅读,更多相关《c语言递归算法.ppt(116页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、1第第八章八章 递归算法递归算法1 13 32 2基本概念基本概念基于回溯策略的递归基于回溯策略的递归基于分治策略的递归基于分治策略的递归 2从前有座山,山上有座庙,庙里有一个老和尚从前有座山,山上有座庙,庙里有一个老和尚和一个小和尚,老和尚正在给小和尚讲故事。和一个小和尚,老和尚正在给小和尚讲故事。讲的是什么故事呢?他说,从前讲的是什么故事呢?他说,从前3Recursion-See Recursion.In order to understand recursion,one must first understand recursion.4C语言允许嵌套地调用函数,也就是说,在调用语言允许嵌
2、套地调用函数,也就是说,在调用一个函数的过程中,又去调用另一个函数一个函数的过程中,又去调用另一个函数。函数的嵌套调用函数的嵌套调用void main()study_english();void study_english()reading();listening();writing()void listening()5函数的嵌套调用有一个特例,即递归调用,也就函数的嵌套调用有一个特例,即递归调用,也就是说,在调用一个函数的过程中,又出现了直接是说,在调用一个函数的过程中,又出现了直接或间接地去调用该函数本身或间接地去调用该函数本身。void tell_story()int old_monk,
3、young_monk;tell_story();/tell_story 函数的递归调用函数的递归调用函数的递归调用函数的递归调用?6void tell_story()static int old_monk,young_monk;old_monk=old_monk+1;/年年龄大了一大了一岁 young_monk=young_monk+1;if(old_monk=60)/递归形式形式 tell_story();else printf(对不起,已退休!不起,已退休!);/递归边界界7在语法上(简单)在语法上(简单)J递归即为普通的函数调用。递归即为普通的函数调用。在算法上(难)在算法上(难)J如何
4、找到递归形式?如何找到递归形式?J如何找到递归边界?如何找到递归边界?如何编写递归程序?如何编写递归程序?8递归算法的类型递归算法的类型递归算法可以分为两种类型:递归算法可以分为两种类型:基于分治策略的递归算法;基于分治策略的递归算法;基于回溯策略的递归算法。基于回溯策略的递归算法。9第第八章八章 递归算法递归算法1 13 32 2基本概念基本概念基于回溯策略的递归基于回溯策略的递归基于分治策略的递归基于分治策略的递归 10分而治之(分而治之(divide-and-conquer)的算法)的算法设计思想:设计思想:1.Divide:把问题划分为若干个子问题;:把问题划分为若干个子问题;2.Co
5、nquer:以:以同样的方式同样的方式分别去处理各分别去处理各个子问题;个子问题;3.Combine:把各个子问题的处理结果综:把各个子问题的处理结果综合起来,形成最终的处理结果。合起来,形成最终的处理结果。8.2.1 分而治之分而治之11玛特露什卡玛特露什卡12调用调用调用调用调用调用调用调用调用调用调用调用13如何编写基于分治策略的递归程序?如何编写基于分治策略的递归程序?J在算法分析上,要建立分治递归的思维在算法分析上,要建立分治递归的思维方式。方式。J在编程实现上,要建立在编程实现上,要建立递归信心递归信心(To turst the recursion,Jerry Cain,stanf
6、ord)。)。14如何建立分治递归的思维方式?如何建立分治递归的思维方式?J基本原则:基本原则:目标驱动目标驱动!J计算计算n!:n!=n*(n-1)!,且,且1!=1。递归形式递归形式递归边界递归边界15调用调用调用调用fact(3)fact(2)fact(1)16void main()int n;printf(请输入一个整数:入一个整数:);scanf(%d,&n);printf(%d!=%d n,n,fact(n);int fact(int n)if(n =1)return(1);else return(n*fact(n-1);请输入一个整数:入一个整数:33!=617调用和返回的递归示
7、意图调用和返回的递归示意图18如何建立递归信心?如何建立递归信心?J函数的递归调用到底是如何进行的呢?函数的递归调用到底是如何进行的呢?在递归调用时,执行的是不是相同的代在递归调用时,执行的是不是相同的代码?访问的是不是相同的数据?如果是码?访问的是不是相同的数据?如果是的话,那么大家会不会相互干扰、相互的话,那么大家会不会相互干扰、相互妨碍?妨碍?19main的栈帧的栈帧m3void main()int m;printf(请输入一个整数:入一个整数:);scanf(%d,&m);printf(%d!=%dn,m,fact(m);int fact(int n)if(n=1)return(1);
8、else return(n*fact(n-1);3nfact的栈帧的栈帧2nfact的栈帧的栈帧1nfact的栈帧的栈帧208.2.2 寻找最大值寻找最大值问题描述:问题描述:给定一个整型数组给定一个整型数组a,找出其中的最大,找出其中的最大值。值。如何设计相应的如何设计相应的递归算法递归算法?21如何来设计相应的递归算法?如何来设计相应的递归算法?目标:目标:maxa0,a1,an-1可分解为:可分解为:maxa0,maxa1,an-1另外已知另外已知maxx x这就是递归算法的这就是递归算法的递归形式递归形式和和递归边界递归边界,据,据此可以编写出相应的递归函数。此可以编写出相应的递归函数
9、。22int Max(int a,int first,int n)int max;if(first=n-1)return afirst;max=Max(a,first+1,n);if(max R)return(-1);mid=(L+R)/2;if(x=bmid)return mid;else if(x bmid)return bsearch(b,x,L,mid-1);else return bsearch(b,x,mid+1,R);338.2.4 汉诺汉诺(Hanoi)(Hanoi)塔问题塔问题相传在古印度相传在古印度Bramah庙中,有位僧人整天把三根柱子庙中,有位僧人整天把三根柱子上的金盘
10、倒来倒去,原来他是想把上的金盘倒来倒去,原来他是想把64个一个比一个小的个一个比一个小的金盘从一根柱子上移到另一根柱子上去。移动过程中遵金盘从一根柱子上移到另一根柱子上去。移动过程中遵守以下规则:每次只允许移动一只盘,且大盘不得落在守以下规则:每次只允许移动一只盘,且大盘不得落在小盘上(简单吗?若每秒移动一只盘子,需小盘上(简单吗?若每秒移动一只盘子,需5800亿年亿年)ABC34怎样编写这种程序?思路上还是先从最简单的情况分析怎样编写这种程序?思路上还是先从最简单的情况分析起,搬一搬看,慢慢理出思路。起,搬一搬看,慢慢理出思路。1、在、在A柱上只有一只盘子,假定盘号为柱上只有一只盘子,假定盘
11、号为1,这时只需将该盘直接从这时只需将该盘直接从A搬至搬至C,记为,记为 move from A to CABC1352、在、在A柱上有二只盘子,柱上有二只盘子,1为小盘为小盘2为大盘。为大盘。分三步进行:分三步进行:ABC21move from A to B;move from A to C;move form B to C;363、在、在A柱上有柱上有3只盘子,从小到大分别为只盘子,从小到大分别为1号,号,2号,号,3号。号。怎么移?怎么移?ABC213分七步!分七步!37 分三步进行:分三步进行:move 2 discs from A to B using C;move from A t
12、o C;move 2 discs from B to C using A;ABC213384、在、在A柱上有柱上有 n 个盘子个盘子,从小到大分别为从小到大分别为1号、号、2号、号、3 号、号、n号。号。第第 1 步:将步:将1号、号、2号、号、n-1号盘作为一个整体,号盘作为一个整体,在在C的帮助下,从的帮助下,从A移至移至B;第第 2 步:将步:将n号盘从号盘从A移至移至C;第第 3 步:再将步:再将1号、号、2号、号、n-1号盘作为一个整号盘作为一个整 体,在体,在A的帮助下,从的帮助下,从B移至移至C;这三步记为:这三步记为:move n-1 discs from A to B usi
13、ng C;move 1 discs from A to C;move n-1 discs from B to C using A;递归形式!形式!39定义函数定义函数move(int n,char L,char M,char R);表示表示move n discs from L to R using M;如果如果 n=1,即表示,即表示move from L to R;移移动的是的是谁?40#include void move(int n,char L,char M,char R);void main()int n;printf(请输入一个整数:入一个整数:);scanf(%d,&n);mov
14、e(n,A,B,C);41/L:Left post,M:Middle post,R:Right postvoid move(int n,char L,char M,char R)if(n =1)printf(move#1 from%c to%cn,L,R);else move(n-1,L,R,M);printf(move#%d from%c to%cn,n,L,R);move(n-1,M,L,R);42请输入一个整数:入一个整数:3move#1 from A to Cmove#2 from A to Bmove#1 from C to Bmove#3 from A to Cmove#1 fro
15、m B to Amove#2 from B to Cmove#1 from A to C一次运行结果一次运行结果438.2.5 青蛙过河青蛙过河 一条小溪尺寸不大,青蛙可以从左岸跳到右岸,在左岸有一一条小溪尺寸不大,青蛙可以从左岸跳到右岸,在左岸有一石柱石柱L,面积只容得下一只青蛙落脚,同样右岸也有一石柱,面积只容得下一只青蛙落脚,同样右岸也有一石柱R,面积也只容得下一只青蛙落脚。有一队青蛙从尺寸上一个比一个面积也只容得下一只青蛙落脚。有一队青蛙从尺寸上一个比一个小。我们将青蛙从小到大,用小。我们将青蛙从小到大,用1,2,n编号。规定初始时这编号。规定初始时这队青蛙只能趴在左岸的石头队青蛙只能
16、趴在左岸的石头L上,按编号一个落一个,小的落在上,按编号一个落一个,小的落在大的上面。不允许大的在小的上面。在小溪中有大的上面。不允许大的在小的上面。在小溪中有S根石柱,有根石柱,有y片片荷叶,规定溪中的柱子上允许一只青蛙落脚,如有多只同样要求荷叶,规定溪中的柱子上允许一只青蛙落脚,如有多只同样要求按编号一个落一个,大的在下,小的在上,而且必须编号相邻。按编号一个落一个,大的在下,小的在上,而且必须编号相邻。对于荷叶只允许一只青蛙落脚,不允许多只在其上。对于右岸的对于荷叶只允许一只青蛙落脚,不允许多只在其上。对于右岸的石柱石柱R,与左岸的石柱,与左岸的石柱L一样允许多个青蛙落脚,但须一个落一一
17、样允许多个青蛙落脚,但须一个落一个,小的在上,大的在下,且编号相邻。当青蛙从左岸的个,小的在上,大的在下,且编号相邻。当青蛙从左岸的L上跳上跳走后就不允许再跳回来;同样,从左岸走后就不允许再跳回来;同样,从左岸L上跳至右岸上跳至右岸R,或从溪,或从溪中荷叶或溪中石柱跳至右岸中荷叶或溪中石柱跳至右岸R上的青蛙也不允许再离开。问在已上的青蛙也不允许再离开。问在已知溪中有知溪中有S根石柱和根石柱和y片荷叶的情况下,最多能跳过多少只青蛙?片荷叶的情况下,最多能跳过多少只青蛙?44这题看起来较难,但是如果我们认真分析,理这题看起来较难,但是如果我们认真分析,理出思路,就可化难为易。出思路,就可化难为易。
18、思路:思路:1、简化问题,探索规律。先从个别再到一般,要善、简化问题,探索规律。先从个别再到一般,要善于对多个因素作分解,孤立出一个一个因素来分析于对多个因素作分解,孤立出一个一个因素来分析,化难为易。,化难为易。2.定义函数定义函数 Jump(S,y)最多可跳过河的青蛙数最多可跳过河的青蛙数 其中:其中:S 河中柱子数河中柱子数 y 荷叶数荷叶数45 2 说明:河中有一片荷叶,可以过两只青蛙,起始时说明:河中有一片荷叶,可以过两只青蛙,起始时 L 上有上有两只青蛙,两只青蛙,1#在在 2#上面。上面。第一步:第一步:1#跳到荷叶上;跳到荷叶上;第二步:第二步:2#从从 L 直接跳至直接跳至
19、R 上;上;第三步:第三步:1#再从荷叶跳至再从荷叶跳至 R 上。上。如下图:如下图:3.先看先看简单情况,河中无柱子:情况,河中无柱子:S=0,Jump(0,y)当当 y=1 时,Jump(0,1)=;463 说明:河中有两片荷叶时,可以过说明:河中有两片荷叶时,可以过 3 只青蛙。起始时:只青蛙。起始时:1#,2#,3#3只青蛙落在只青蛙落在 L 上,上,第一步:第一步:1#从从 L 跳至叶跳至叶 1上,上,第二步:第二步:2#从从 L 跳至叶跳至叶 2上,上,第三步:第三步:3#从从 L 直接跳至直接跳至 R 上,上,第四步:第四步:2#从叶从叶 2 跳至跳至 R 上,上,第五步:第五步
20、:1#从叶从叶 1 跳至跳至 R 上,上,采用归纳法:采用归纳法:Jump(0,y)=当当 y=2 时,Jump(0,2)=;y+1;意思是:在河中没有石柱的情况意思是:在河中没有石柱的情况下,过河的青蛙数仅取决于荷叶下,过河的青蛙数仅取决于荷叶数,数目是荷叶数数,数目是荷叶数+1。47再看再看Jump(S,y)Jump(S,y)先看一个最简单情况:先看一个最简单情况:S=1,y=1。从图上看出需要从图上看出需要 步,跳过步,跳过 只青蛙。只青蛙。9 4 9 4 1#1#青蛙从青蛙从 L L Y Y;2#2#青蛙从青蛙从 L L S S;1#1#青蛙从青蛙从 Y Y S S;3#3#青蛙从青蛙
21、从 L L Y Y;4#4#青蛙从青蛙从 L L R R;3#3#青蛙从青蛙从 Y Y R R;1#1#青蛙从青蛙从 S S Y Y;2#2#青蛙从青蛙从 S S R R;1#1#青蛙从青蛙从 Y Y R R;48对于对于S=1,y=1的情形,从另外一个角度来分析的情形,从另外一个角度来分析若没有石柱若没有石柱S S,最多可过,最多可过 y+1y+1=2 2 只青蛙。只青蛙。有了石柱有了石柱S后,最多可过后,最多可过 2*2=4 只青蛙。只青蛙。步骤步骤1 1:1#1#和和2#2#从从 L L S S;步骤步骤2 2:3#3#和和4#4#从从 L L R R;步骤步骤3 3:1#1#和和2#2
22、#从从 S S R R;YSLR:1#,2#:3#,4#:1#,2#YYY49对于对于S=1,y 1的情形的情形若没有石柱若没有石柱S S,最多可过,最多可过 y+1y+1 只青蛙。只青蛙。有了石柱有了石柱S后,最多可过后,最多可过 2*(y+1)只青蛙。只青蛙。步骤步骤1 1:前前y+1y+1只只 从从 L L S S;步骤步骤2 2:后后y+1y+1只只 从从 L L R R;步骤步骤3 3:前前y+1y+1只只 从从 S S R R;YSLR:前前y+1只只:后后y+1只只:前前y+1只只YYY50对于对于S=2,y 1的情形的情形若只有石柱若只有石柱S1,最多可过,最多可过 2*(y+
23、1)2*(y+1)只青蛙。只青蛙。有了石柱有了石柱S2后,最多可过后,最多可过 只青蛙。只青蛙。YS1LR4*(y+1)S2步骤步骤1 1:前前2*(y+1)只只 从从 L L S2 S2;步骤步骤2 2:后后2*(y+1)只只 从从 L L R R;步骤步骤3 3:前前2*(y+1)只只 从从 S2 S2 R R;Y,S1Y,S1Y,S151采用归纳法,可得出如下的递归形式:采用归纳法,可得出如下的递归形式:Jump(S,y)=2*Jump(S-1,y);意思是:先让一半的青蛙利用意思是:先让一半的青蛙利用y片荷叶和片荷叶和S-1根石柱,落在河中剩下的那根石柱上;根石柱,落在河中剩下的那根石
24、柱上;然后让另一半的青蛙利用然后让另一半的青蛙利用y片荷叶和片荷叶和S-1根根石柱,落在右岸的石柱,落在右岸的R上面;最后再让先前上面;最后再让先前的一半青蛙,利用的一半青蛙,利用y片荷叶和片荷叶和S-1根石柱,根石柱,落在右岸的落在右岸的R上面。上面。递归边界:递归边界:Jump(0,y)=y+152void main()int S,y;printf(请输入石柱和荷叶的数目:入石柱和荷叶的数目:);scanf(%d%d,&S,&y);printf(最多最多有有%d 只青蛙只青蛙过河河n,Jump(S,y);int Jump(int S,int y)if(S =0)return(y+1);re
25、turn(2*Jump(S-1,y);538.2.6 快速排序快速排序快速排序的基本思路:快速排序的基本思路:1 1、在数组、在数组a a中,有一段待排序的数据,下标从中,有一段待排序的数据,下标从l l到到r r。2 2、取、取alal放在变量放在变量valuevalue中,通过由右、左两边对中,通过由右、左两边对valuevalue的取值的比较,为的取值的比较,为valuevalue选择应该排定的位置选择应该排定的位置。这时要将比。这时要将比valuevalue大的数放右边,比它小的数放大的数放右边,比它小的数放左边。当左边。当valuevalue到达最终位置后(如下标到达最终位置后(如下
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 语言 递归 算法
限制150内