C函数递推递归_第1页
C函数递推递归_第2页
C函数递推递归_第3页
C函数递推递归_第4页
C函数递推递归_第5页
已阅读5页,还剩72页未读 继续免费阅读

下载本文档

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

文档简介

1、C函数递推递归第九讲函数、递推、递归递推递推是计算机数值计算中的一个重要算法。思路:通过数学推导,将复杂的运算化解为假设干重复的简单运算,以充分发挥计算机长于重复运算的特点;递推法特点:从一个的事实出发,按一定规律推 出下一个事实,再从这个新的事实出发,再向下 推出一个新的事实。2第九讲函数、递推、递归递推举例1例: (猴子吃桃问题)猴子第1天摘下假设干桃子,当即吃了一半,还不过瘾, 又多吃了一个。第2天早上又将剩下的桃子吃掉一半, 又多吃了一个。以后每天早上都吃了前一天剩下的一 半另加一个。到第10天早上想再吃时,就只剩下一个 桃子了。问第1天猴子共摘了多少桃子?3第九讲函数、递推、递归解题

2、思路:假设用 S(i)表示第 i天没吃之前的桃子数目;那么S(1) 即为第 1天所摘的桃子数;S(10) = S(9) * 1/2 1第10 天没吃之前的桃子数S(2)=S(1)* 1/2 1第2天没吃之前的桃子数S(3)=S(2)* 1/2-1第3天没吃之前的桃子数S(9)=S(8)* 1/2- 1第9天没吃之前的桃子数4第九讲函数、递推、递归一般形式:S(i) = S(i-1) * 1/2 1,i = 2, 3, , 10;这个公式可用于知第 1 天没吃之前的桃子数推算第 2 天 没吃之前的,再推算第 3天没吃之前的,.。现在要求的是 第 1 天没吃之前的。能否倒过来,先知 第 10 天没

3、吃之前的 的再反推第 9天没吃之的,直到第 1 天没吃之前的。为 此将上式改写为:S(i-1) = 2 * (S(i) + 1), i = 10, 9, 8, 25第九讲函数、递推、递归程序:大连理工大学 盘锦校区根底教学部 6第九讲函数、递推、递归分析:一般形式:S(i-1) = 2 * (S(i) + 1), i = 10, 9, 8, 2;初始:s2 = 1 ;/ S(10) = 1i = 9s1 = 2 * (s2 + 1) ;s2 =s1 ;s1 = 2 * (s2 + 1) ;s2 =s1 ;s1 = 2 * (s2 + 1) ;s2 =s1 ;/ S(9) = 2 * (S(10

4、) + 1)/s2 = s1 = S(9)/ S(8) = 2 * (S(9) + 1)/s2 = s1 = S(8)/ S(7) = 2 * (S(8) + 1)/s2 = s1 = S(7)i = 8i = 7i = 6s1 = 2 * (s2 + 1) ;s2 =s1 ;/ S(6) = 2 * (S(7) + 1)/s2 = s1 = S(6)7第九讲函数、递推、递归i = 5s1 = 2 * (s2 + 1) ;s2 =s1 ;/ S(5) = 2 * (S(6) + 1)/s2 = s1 = S(5)/ S(4) = 2 * (S(5) + 1)/s2 = s1 = S(4)/ S

5、(3) = 2 * (S(4) + 1)/s2 = s1 = S(3)/ S(2) = 2 * (S(3) + 1)/s2 = s1 = S(2)/ S(1) = 2 * (S(2) + 1)/s2 = s1 = S(1)i = 4s1 = 2 * (s2 + 1) ;s2 =s1 ;s1 = 2 * (s2 + 1) ;s2 =s1 ;s1 = 2 * (s2 + 1) ;s2 =s1 ;s1 = 2 * (s2 + 1) ;s2 =s1 ;i = 3i = 2i = 18第九讲函数、递推、递归递推举例2递推数列 一个数列从某一项起,它的任何一项都可以用它前面的假设干项 来确定,这样的数列称

6、为递推数列,表示某项与其前面的假设干 项的关系就称为递推公式。例如自然数 1,2,,n 的阶乘就可 以形成如下数列:1!,2!,3!,,(n-1)!, n!另fact(n) 为 n 阶乘,依据后项与前项的关系可以写出递推公式:fact(n) = n * fact(n-1) (通项公式)fact(1) = 1边界条件9第九讲函数、递推、递归递推算例3递推算法程序实现: 有了通项公式和边界条件后,采用循环构造,从边界条件出 发,利用通项公式通过假设干步递推过程就可以求出结果;例:王小二自称刀工不错,有人放一张大的煎饼在砧板上,问他:“饼不许离开砧板,切 100 刀最多能分成多少块?10第九讲函数、

7、递推、递归分析:切一刀切二刀切三刀切四刀令 q(n) 表示切 n刀能分成的块数,由上图可知q(1) = 1 + 1 = 2q(2) = 1 + 1 + 2 = 4q(3) = 1 + 1 + 2 + 3 = 7q(4) = 1 + 1 + 2 + 3 + 4 = 1111第九讲函数、递推、递归分析:切一刀切二刀切三刀切四刀在切法上是让每两条线都有交点。用归纳法可得出q(n) = q(n-1) + nq(0) = 1 (边界条件)12第九讲函数、递推、递归递推算例3参考程序:13第九讲函数、递推、递归递归递归算法在可计算理论中占有重要地位,它是算法设计的有力工具,对于拓展编程思路非常有用。就递归

8、算法而言不涉及高深数学知识,只不过初学者建立起递 归概念不太容易。看一个简单的例子:14第九讲函数、递推、递归递归有5 个人坐在一起,问第 5 个人多少岁? 他说比第 4个人大两岁。问第4 个人岁数,他说比第 3 个人大两岁。问第 3个人,又说比第 2个人大两岁。问第 2个人,说比第 1个人大两岁。最后问第 1个人,他说是 10岁。请问第 5 个人多大?解题思路: 假设用 age(i)表示第 i个人的岁数,那么借助循环构造采用递推方法求解!age(5)=age(4)+2;age(4)age(3)=age(3)age(2)+2;2;age(2)=age(1)+2;age(1)=10;15第九讲函

9、数、递推、递归一般形式:age(n) = 10age(n) = age(n-1) + 2( n = 1 )( n 2 )16第九讲函数、递推、递归分析:上述求解是从求解目标出发,即将第 n 个人的年龄表示第 (n-1) 个人的年龄,再回溯到第 n-2个人的年龄 直 到第 1 个人的年龄;回溯阶段然后,采用递推方法,从第 1 个人的年龄推算第 2 个人的年龄,在推算第 3个人的年龄,直到推算出第 5个人的 年龄;递推阶段这是一个递归问题,对它的求解可以分成 回溯 和 递推 两 个阶段;显而易见,如果不希望递归过程无限制的进展下去, 必须有一个完毕递归过程的条件;如:age(1) = 1017第九

10、讲函数、递推、递归计算年龄函数:int age(int n)int c;if( n = 1)c = 10; else c = age(n - 1) + 2; return c;18第九讲函数、递推、递归递归调用在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归recursive调用;C+允许函数的递归调用; 例:int f(int x)int y, z; z = f(y);return 2 * z;19第九讲函数、递推、递归递归调用直接调用间接调用注意:上述两种情况都是无终止的自身调用;显然, 程序中不应该出现这种无终止的调用,而只应出现 有限次的,有终止的递归调用;可以用

11、if语句控制, 实现递归调用完毕;20第九讲函数、递推、递归递归函数包含递归调用的函数,称为递归函数;计算年龄函数:int age(int n)int c;if( n = 1)c = 10; else c = age(n - 1) + 2; return c;21第九讲函数、递推、递归递归函数计算年龄递归函数执行过程:age(5)=age(4)+2/c= age(4) + 2=age(3)+2+2/c= age(3) + 2=age(2)+2+2+ 2/c = age(2) +2=age(1)+2+2+ 2+2;/ c = 10;22第九讲函数、递推、递归计算年龄程序23第九讲函数、递推、递归

12、递归算例2用递归方法计算 n!算法思路:假设 n = 10, 那么 n! = 10 * 9!定义函数 fact(n) 表示计算 n!的函数,那么有fact(n)=n* fact(n-1),n1fact(n)=1,n=0,n=1;24第九讲函数、递推、递归递归算例2阶乘计算递归函数:iinntt ffaacctt(iinntt nn)int c;if(cn=n= *0 f|anct=(n=-11); c = 1; reelstuern c;c = n * fact(n-1);return c;完毕递归条件25第九讲函数、递推、递归递归算例3用递归函数计算组合数:C(m,n),即从 m 个数中取

13、n 个数的组合数;C(m,n) = C(m-1, n) + C(m-1,n-1); C(m,n) = 0, m 0, n 10 ) return -1; if(n = 10) c = 1; elsec = 2 * (count(n+1) + 1); return c;33第九讲函数、递推、递归递归方法递归实现:在时间和空间上的开销比较大;但符合人们的思路,程序容易理解;递归函数: 只须写出递归公式和递归完毕条件即边 界条件,即可很容易写出递归函数;34第九讲函数、递推、递归局部变量和全局变量一个程序可以包括假设干个源程序文件文件模块; 每个源程序文件又包括假设干个函数; 在每个函数中和函数外都

14、可以定义变量。这些在不同地方定义的变量是否都在程序的全部范围 内有效?如果不是,他们的有效范围是什么呢?35第九讲函数、递推、递归局部变量和全局变量局部变量在一个函数内部定义的变量是内部变量,它只在 本函数范围内有效,换句话说只有在本函数内才能使 用它们,在此函数之外是不能使用这些变量的。同样 的,在复合语句中定义的变量只在复合语句内范围内 有效。36第九讲函数、递推、递归float f1(int a)/函数f1int b,c;char f2(intint i,j;int main( )int m,n;int p,q;b、c有效a有效x, int y) i、j有效/函数f2x、y有效/主函数p

15、、q在复合语句中有效m、n有效37第九讲函数、递推、递归a也只在f1函数中有效。其他函数不能调用。大连理工大学 盘锦校区根底教学部说明:(1) 主函数main中定义的变量(m,n)也只在主函数 中有效,不会因为在主函数中定义而在整个文件或 程序中有效。主函数也不能使用其他函数中定义的 变量。(2) 不同函数中可以使用同名的变量,它们代表不 同的对象,互不干扰。例如,在f1函数中定义了变量 b和c,倘假设在f2函数中也定义变量b和c,它们在内存 中占不同的单元,不会混淆。(3) 可以在一个函数内的复合语句中定义变量,这 些变量只在本复合语句中有效,这种复合语句也称 为分程序或程序块。(4) 形式

16、参数也是局部变量。例如f1函数中的形参38第九讲函数、递推、递归(5) 在函数声明中出现的参数名,其作用范围只在本 行的括号内。实际上,编译系统对函数声明中的变量 名是忽略的,即使在调用函数时也没有为它们分配存储单元。 例如int max(int a,int b);int max(int x,inty) coutxyendl;coutabendl;/函数声明中出现a、b/函数定义,形参是x、y/合法,x、y在函数体中有效/非法,a、b在函数体中无效编译时认为max函数体中的a和b未经定义。39第九讲函数、递推、递归全局变量程序的编译单位是源程序文件.cpp,一个源文 件可以包含一个或假设干个函

17、数。在函数内定义的变量是局部变量,而在函数之外定 义的变量是外部变量,称为全局变量(global variable,也称全程变量)。全局变量的有效范围为从定义变量的位置开场到 根源文件完毕。如40第九讲函数、递推、递归int p=1,q=5;/全局变量float f/定义函数f11(a)int a;围全局变量c1、c2的作用范围(int a)intb,c;charc1,c2;charf2 (int x, inty)/定义函数f2inti,j;main( )/主函数intm,n;41第九讲函数、递推、递归p、q、c1、c2都是全局变量,但它们的作用范围不 同,在main函数和f2函数中可以使用全

18、局变量p、q、 c1、c2,但在函数f1中只能使用全局变量p、q,而 不能使用c1和c2。在一个函数中既可以使用本函数中的局部变量,又 可以使用有效的全局变量。说明:(1) 设全局变量的作用是增加函数间数据联系的渠 道。(2) 建议不在必要时不要使用全局变量,因为: 全局变量在程序的全部执行过程中都占用存储单元,而不是仅在需要时才开辟单元。42第九讲函数、递推、递归 在程序设计中,在划分模块时要求模块的内聚性强、与其他模块的耦合性弱。即模块的功能要单 一不要把许多互不相干的功能放到一个模块中, 与其他模块的相互影响要尽量少,而用全局变量是 不符合这个原那么的。一般要求把程序中的函数做成一个封闭

19、体,除 了可以通过“实参形参的渠道与外界发生联 系外,没有其他渠道。这样的程序移植性好,可读性强。43第九讲函数、递推、递归大连理工大学 盘锦校区根底教学部 44 使用全局变量过多,会降低程序的清晰性。在各个函数执行时都可能改变全局变量的值,程序容易 出错。因此,要限制使用全局变量。(3) 如果在同一个源文件中,全局变量与局部变量 同名,那么在局部变量的作用范围内,全局变量被屏 蔽,即它不起作用。变量的有效范围称为变量的作用域(scope)。归纳起 来,变量有4种不同的作用域: 文件作用域(file scope)、函数作用域(function scope)、块作用域 (block scope)

20、和函数原型作用域(functionprototype scope)。文件作用域是全局的,其他三者是局部的。第九讲函数、递推、递归变量的存储类别已介绍了变量的一种属性作用域,作用域是从 空间的角度来分析的,分为全局变量和局部变量。变量还有另一种属性存储期(storage duration,也称生命期)。存储期是指变量在内存中 的存在时间。这是从变量值存在的时间角度来分析 的。存储期可以分为静态存储期(static storage duration)和动态存储期(dynamic storage duration)。这是由变量的静态存储方式和动态存储 方式决定的。45第九讲函数、递推、递归存储方式静

21、态存储方式是指在程序运行期间,系统对变量分配固定的存储空间。动态存储方式那么是在程序运行期间,系统对变量动 态地分配存储空间。46第九讲函数、递推、递归存储方式先看一下内存中的供用户使用的存储空间的情况。这个存储空间可以分为三局部,即:(1) 程序区(2) 静态存储区(3) 动态存储区47第九讲函数、递推、递归静态存储区数据分别存放在静态存储区和动态存储区中。全局变量全部存放在静态存储区中,在程序开场执行 时给全局变量分配存储单元,程序执行完毕就释放这 些空间。在程序执行过程中它们占据固定的存储单元,而不是 动态地进展分配和释放。48第九讲函数、递推、递归动态存储区在动态存储区中存放以下数据:

22、函数形式参数。在调用函数时给形参分配存储空间。函数中的自动变量未加static声明的局部变量, 详见后面的介绍。函数调用时的现场保护和返回地址等。 对以上这些数据,在函数调用开场时分配动态存储空 间,函数完毕时释放这些空间。在程序执行过程中,这种分配和释放是动态的,如果在一个程序中两次调用同一函数,那么要进展两次分配和释放,而两次分配给此函数中局部变量的存储空间地址可能是不一样的。49第九讲函数、递推、递归50大连理工大学 盘锦校区根底教学部如果在一个程序中包含假设干个函数,每个函数中的 局部变量的存储期并不等于整个程序的执行周期,它 只是整个程序执行周期的一局部。根据函数调用的情况,系统对局

23、部变量动态地分配和释放存储空间。在C+中变量除了有数据类型的属性之外,还有存 储类别(storage class) 的属性。存储类别指的是数 据在内存中存储的方法。存储方法分为静态存储和动 态存储两大类。具体包含4种:自动的(auto)、静态的 (static)、存放器的(register)和外部的(extern)。根据变量的存储类别,可以知道变量的作用域和存储期。第九讲函数、递推、递归自动变量函数中的局部变量,如果不用关键字static加以声明,编译系统对它们是动态地分配存储空间的。函数的形参和在函数中定义的变量(包括在复合语 句中定义的变量)都属此类。在调用该函数时,系统给形参和函数中定义

24、的变量 分配存储空间,数据存储在动态存储区中。在函数调 用完毕时就自动释放这些空间。如果是在复合语句中 定义的变量,那么在变量定义时分配存储空间,在复合 语句完毕时自动释放空间。因此这类局部变量称为自 动变量(auto variable)。51第九讲函数、递推、递归用register声明存放器变量一般情况下,变量的值是存放在内存中的。当程序中用到哪一个变量的值时,由控制器发出指令将内存中 该变量的值送到CPU中的运算器。经过运算器进展运算, 如果需要存数,再从运算器将数据送到内存存放。如图 所示。为提高执行效率,C+允许将局部变量的 放在CPU中的存放器中,需要用时直接从寄 存器取出参加运算,

25、不必再到内存中去存 取。这种变量叫做存放器变量,用关键字register作声明。但是,是建议性的;值52第九讲函数、递推、递归用static声明静态局部变量有时希望函数中的局部变量的值在函数调用完毕后不 消失而保存原值,即其占用的存储单元不释放,在下 一次该函数调用时,该变量保存上一次函数调用完毕 时的值。这时就应该指定该局部变量为静态局部变量 (static local variable)。53第九讲函数、递推、递归54第九讲函数、递推、递归先后3次调用f函数时,b和c的值如书中表所示。55第九讲函数、递推、递归静态局部变量说明(1) 静态局部变量在静态存储区内分配存储单元。 在程序整个运行

26、期间都不释放。而自动变量即动 态局部变量属于动态存储类别,存储在动态存储 区空间(而不是静态存储区空间),函数调用完毕后 即释放。(2) 为静态局部变量赋初值是在编译时进展值的, 即只赋初值一次,在程序运行时它已有初值。以后 每次调用函数时不再重新赋初值而只是保存上次函 数调用完毕时的值。而为自动变量赋初值,不是在 编译时进展的,而是在函数调用时进展,每调用一 次函数重新给一次初值大连,理工相大学当盘锦校于区基执础教行学部一次赋值语句。 56第九讲函数、递推、递归(3) 如果在定义局部变量时不赋初值的话,对静态 局部变量来说,编译时自动赋初值0(对数值型变量) 或空字符(对字符型变量)。而对自

27、动变量来说,如 果不赋初值,那么它的值是一个不确定的值。这是由 于每次函数调用完毕后存储单元已释放,下次调用时又重新另分配存储单元,而所分配的单元中的值 是不确定的。(4) 虽然静态局部变量在函数调用完毕后仍然存在,但其他函数是不能引用它的,也就是说,在其他函数中它是“不可见的。57第九讲函数、递推、递归静态局部变量使用在什么情况下需要用局部静态变量呢?1. 需要保存函数上一次调用完毕时的值。例如可以用下例中的方法求!。如:int fac(int n) static int f=1;/f为静态局部变量,函数完毕/ 时f的值不释放/在f原值根底上乘以nf=f*n; return f;58第九讲函

28、数、递推、递归静态局部变量使用2. 如果初始化后,变量只被引用而不改变其值,那么这时用静态局部变量比较方便,以免每次调用时重新赋值。59第九讲函数、递推、递归用extern声明外部变量全局变量(外部变量)是在函数的外部定义的,它 的作用域为从变量的定义处开场,到本程序文件的末 尾。在此作用域内,全局变量可以为本文件中各个函 数所引用。编译时将全局变量分配在静态存储区。有时需要用extern来声明全局变量,以扩展全局变量的作用域。60第九讲函数、递推、递归在一个文件内声明全局变量提前引用声明大连理工大学 盘锦校区根底教学部61第九讲函数、递推、递归在多文件程序中声明外部变量外部变量声明分析下例:

29、 extern inta,b; int main( )couta,bendl; return0;注意: inta=3,b=4;extern 是用作变量声明,而不是变量定义。它只是对一 个已定义的外部变量作声明,以扩展其作用域。62第九讲函数、递推、递归用extern扩展全局变量的作用域,虽然能为程序设 计带来方便,但应十分慎重,因为在执行一个文件中的函数时,可能会改变了该全局变量的值,从而会影响到另一文件中的函数执行结果。63第九讲函数、递推、递归用static声明静态外部变量有时在程序设计中希望某些外部变量只限于被本文 件引用,而不能被其他文件引用。这时可以在定义 外部变量时加一个stati

30、c声明。例如: static int a=3; int main ( )extern int a;int fun (int n) a=a*n;64第九讲函数、递推、递归这种加上static声明、只能用于本文件的外部变量全局变量称为静态外部变量。这就为程序的模块化、 通用性提供了方便。如果道其他文件不需要引用本 文件的全局变量,可以对本文件中的全局变量都加上static,成为静态外部变量,以免被其他文件误用。需要指出,不要误认为用static声明的外部变量才采 用静态存储方式存放在静态存储区中,而不加 static的是动态存储存放在动态存储区。实际上, 两种形式的外部变量都用静态存储方式,只是作

31、用范围不同而已,都是在编译时分配内存的。65第九讲函数、递推、递归存储期和作用域66第九讲函数、递推、递归变量的声明和定义关于声明和定义:针对函数而言,函数的声明是函数的原型,而函数的定义是函数功能的建立;在声明局部出现的变量有两种情况:一种是需要建立 存储空间的如 int a ;另一种是不需要建立存储 空间的(extern int a );前者称为定义性声明,或简称定义;后者称为引用性声明;67第九讲函数、递推、递归为表达方便,把建立存储空间的声明称为定义;如:int a;而把不需要建立存储空间的声明称为声明;如:extern int a;68第九讲函数、递推、递归外部变量定义和外部变量声明

32、的含义是不同的。外部变量的定义只能有一次,它的位置在所有函数之外, 而同一文件中的外部变量的声明可以有屡次,它的位置 可以在函数之内,也可以在函数之外。系统根据外部变 量的定义分配存储单元。对外部变量的初始化只能在定 义时进展,而不能在声明中进展。所谓声明,其作用是 向编译系统发出一个信息,声明该变量是一个在后面定 义的外部变量,仅仅是为了提前引用该变量而作的声明。extern只用作声明,而不用于定义。69第九讲函数、递推、递归用static来声明一个变量的作用有二:(1)对局部变量用static声明,使该变量在本函数调用结 束后不释放,整个程序执行期间始终存在,使其存储 期为程序的全过程。(2)全局变量用static声明,那么该变量的作用域只限于本文件模块(即被声明的文件中)。70第九讲函数、递推、递归

温馨提示

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

评论

0/150

提交评论