什么是递归函数

什么是递归函数
什么是递归函数

1.什么是递归函数(recursive function)

递归函数即自调用函数,在函数体内部直接或间接地自己调用自己,即函数的嵌套调用是函数本身。

例如,下面的程序为求n!:

long fact(int n)

{

if(n==1)

return1;

return fact(n-1)*n;//出现函数自调用

}

2.函数调用机制的说明

任何函数之间不能嵌套定义,调用函数与被调用函数之间相互独立(彼此可以调用)。发生函数调用时,被调函数中保护了调用函数的运行环境和返回地址,使得调用函数的状态可以在被调函数运行返回后完全恢复,而且该状态与被调函数无关。

被调函数运行的代码虽是同一个函数的代码体,但由于调用点,调用时状态,返回点的不同,可以看作是函数的一个副本,与调用函数的代码无关,所以函数的代码是独立的。被调函数运行的栈空间独立于调用函数的栈空间,所以与调用函数之间的数据也是无关的。函数之间靠参数传递和返回值来联系,函数看作为黑盒。

这种机制决定了C/C++允许函数递归调用。

3.递归调用的形式

递归调用有直接递归调用和间接递归调用两种形式。

直接递归即在函数中出现调用函数本身。

例如,下面的代码求斐波那契数列第n项。斐波那契数列的第一和第二项是1,后面每一项是前二项之和,即1,1,2,3,5,8,13,...。代码中采用直接递归调用:

long fib(int x)

{

if(x>2)

return(fib(x-1)+fib(x-2));//直接递归

else

return1;

}

间接递归调用是指函数中调用了其他函数,而该其他函数却又调用了本函数。例如,下面的代码定义两个函数,它们构成了间接递归调用:

int fnl(int a)

{

int b;

b=fn2(a+1);//间接递归

//...

}

int fn2(int s)

{

int c;

c=fnl(s-1); //间接递归

//...

}

上例中,fn1()函数调用了fn2()函数,而fn2()函数又调用了fn1()函数。

4.递归的条件

(1)须有完成函数任务的语句。

例如,下面的代码定义了一个递归函数:

#include

void count(int val) //递归函数可以没有返回值

{ if(val>1)

count(val-1);、

cout<<"ok:" <<<=""此语句完成函数任务="" />

该函数的任务是在输出设备上显示"ok:整数值”。

(2)—个确定是否能避免递归调用的测试

例如,上例的代码中,语句"if(val>1)"便是—个测试,如果不满足条件,就不进行递归调用。

(3)一个递归调用语句。

该递归调用语句的参数应该逐渐逼近不满足条件,以至最后断绝递归。

例如,上面的代码中,语句“if(val>1)”便是一个递归调用,参数在渐渐变小,这种发展趋势能使测试"if(val>1)”最终不满足。

(4)先测试,后递归调用。

在递归函数定义中,必须先测试,后递归调用。也就是说,递归调用是有条件的,满足了条件后,才可以递归。

例如,下面的代码无条件调用函数自己,造成无限制递归,终将使栈空间溢出:

#include

void count(int val)

{

count(val-1);//无限制递归

if(val>1) //该语句无法到达

cout <<"ok: " <<}

5.消去递归

大多数递归函数都能用非递归函数来代替。例如,下面的代码求两个整数a,b的最大公约数,用递归和非递归函数分别定义之:

long gcdt(int a,int b) //递归版

{

if(a%b==0)

return b;

return gcdl(b,a%b);

}

long gcd2(int a,int b) //非递归版

{

int temp;

while(b!=0)

{

temp=a%b;

a=b;

b=temp;

}

return a;

}

思考:将求n!的递归函数非递归化。

6.递归的评价

递归的目的是简化程序设计,使程序易读。

但递归增加了系统开销。时间上,执行调用与返回的额外工作要占用CPU时间。空间上,随着每递归一次,栈内存就多占用一截。

相应的非递归函数虽然效率高,但却比较难编程,而且相对来说可读性差。

现代程序设计的目标主要是可读性好。随着计算机硬件性能的不断提高,程序在更多的场合优先考虑可读而不是高效,所以,鼓励用递归函数实现程序思想。

递归调用详解,分析递归调用的详细过程

递归调用详解,分析递归调用的详细过程 2009年05月23日星期六 22:52 一、栈 在说函数递归的时候,顺便说一下栈的概念。 栈是一个后进先出的压入(push)和弹出(pop)式数据结构。在程序运行时,系统每次向栈中压入一个对象,然后栈指针向下移动一个位置。当系统从栈中弹出一个对象时,最近进栈的对象将被弹出。然后栈指针向上移动一个位置。程序员经常利用栈这种数据结构来处理那些最适合用后进先出逻辑来描述的编程问题。这里讨论的程序中的栈在每个程序中都是存在的,它不需要程序员编写代码去维护,而是由运行是系统自动处理。所谓的系统自动维护,实际上就是编译器所产生的程序代码。尽管在源代码中看不到它们,但程序员应该对此有所了解。 再来看看程序中的栈是如何工作的。当一个函数(调用者)调用另一个函数(被调用者)时,运行时系统将把调用者的所有实参和返回地址压入到栈中,栈指针将移到合适的位置来容纳这些数据。最后进栈的是调用者的返回地址。当被调用者开始执行时,系统把被调用者的自变量压入到栈中,并把栈指针再向下移,以保证有足够的空间存储被调用者声明的所有自变量。当调用者把实参压入栈后,被调用者就在栈中以自变量的形式建立了形参。被调用者内部的其他自变量也是存放在栈中的。由于这些进栈操作,栈指针已经移动所有这些局部变量之下。但是被调用者记录了它刚开始执行时的初始栈指针,以他为参考,用正或负的偏移值来访问栈中的变量。当被调用者准备返回时,系统弹出栈中所有的自变量,这时栈指针移动了被调用者刚开始执行时的位置。接着被调用者返回,系统从栈中弹出返回地址,调用者就可以继续执行了。当调用者继续执行时,系统还将从栈中弹出调用者的实参,于是栈指针回到了调用发生前的位置。 可能刚开始学的人看不太懂上面的讲解,栈涉及到指针问题,具体可以看看一些数据结构的书。要想学好编程语言,数据结构是一定要学的。 二、递归 递归,是函数实现的一个很重要的环节,很多程序中都或多或少的使用了递归函数。递归的意思就是函数自己调用自己本身,或者在自己函数调用的下级

递归算法详解

递 归 冯文科 一、递归的基本概念。 一个函数、概念或数学结构,如果在其定义或说明内部直接或间接地出现对其本身的引 用,或者是为了描述问题的某一状态,必须要用至它的上一状态,而描述上一状态,又必须用到它的上一状态……这种用自己来定义自己的方法,称之为递归或递归定义。在程序设计中,函数直接或间接调用自己,就被称为递归调用。 二、递归的最简单应用:通过各项关系及初值求数列的某一项。 在数学中,有这样一种数列,很难求出它的通项公式,但数列中各项间关系却很简单,于是人们想出另一种办法来描述这种数列:通过初值及n a 与前面临近几项之间的关系。 要使用这样的描述方式,至少要提供两个信息:一是最前面几项的数值,一是数列间各项的关系。 比如阶乘数列 1、2、6、24、120、720…… 如果用上面的方式来描述它,应该是: ???>==-1 ,1,11n na n a n n 如果需要写一个函数来求n a 的值,那么可以很容易地写成这样:

这就是递归函数的最简单形式,从中可以明显看出递归函数都有的一个特点:先处理一 些特殊情况——这也是递归函数的第一个出口,再处理递归关系——这形成递归函数的第二个出口。 递归函数的执行过程总是先通过递归关系不断地缩小问题的规模,直到简单到可以作为 特殊情况处理而得出直接的结果,再通过递归关系逐层返回到原来的数据规模,最终得出问题的解。 以上面求阶乘数列的函数)(n f 为例。如在求)3(f 时,由于3不是特殊值,因此需要计 算)2(*3f ,但)2(f 是对它自己的调用,于是再计算)2(f ,2也不是特殊值,需要计算 )1(*2f ,需要知道)1(f 的值,再计算)1(f ,1是特殊值,于是直接得出1)1(=f ,返回上 一步,得2)1(*2)2(==f f ,再返回上一步,得62*3)2(*3)3(===f f ,从而得最终解。 用图解来说明,就是 下面再看一个稍复杂点的例子。 【例1】数列}{n a 的前几项为

递归算法详解完整版

递归算法详解标准化管理处编码[BBX968T-XBB8968-NNJ668-MM9N]

递归 冯文科一、递归的基本概念。 一个函数、概念或数学结构,如果在其定义或说明内部直接或间接地出现对其本身的引用,或者是为了描述问题的某一状态,必须要用至它的上一状态,而描述上一状态,又必须用到它的上一状态……这种用自己来定义自己的方法,称之为递归或递归定义。在程序设计中,函数直接或间接调用自己,就被称为递归调用。 二、递归的最简单应用:通过各项关系及初值求数列的某一项。 在数学中,有这样一种数列,很难求出它的通项公式,但数列中各项间关系却很简 a与前面临近几项之间的关单,于是人们想出另一种办法来描述这种数列:通过初值及 n 系。 要使用这样的描述方式,至少要提供两个信息:一是最前面几项的数值,一是数列间各项的关系。 比如阶乘数列 1、2、6、24、120、720…… 如果用上面的方式来描述它,应该是: a的值,那么可以很容易地写成这样: 如果需要写一个函数来求 n

这就是递归函数的最简单形式,从中可以明显看出递归函数都有的一个特点:先处理一些特殊情况——这也是递归函数的第一个出口,再处理递归关系——这形成递归函数的第二个出口。 递归函数的执行过程总是先通过递归关系不断地缩小问题的规模,直到简单到可以作为特殊情况处理而得出直接的结果,再通过递归关系逐层返回到原来的数据规模,最终得出问题的解。 以上面求阶乘数列的函数) f为例。如在求)3(f时,由于3不是特殊值,因此需 (n 要计算)2( 3f,但)2(f是对它自己的调用,于是再计算)2(f,2也不是特殊值,需要计 * 算)1( f,返回 )1(= 2f,需要知道)1(f的值,再计算)1(f,1是特殊值,于是直接得出1 * 上一步,得2 3 * )2( )3(= = f,从而得最终 =f )1( 3 2 * * )2(= =f 2 f,再返回上一步,得6 解。 用图解来说明,就是

(重要)递归(含代码执行过程解释)

递归算法详细分析-> C阅读(17418) C通过运行时堆栈支持递归函数的实现。递归函数就是直接或间接调用自身的函数。 许多教科书都把计算机阶乘和菲波那契数列用来说明递归,非常不幸我们可爱的著名的老潭老师的《C语言程序设计》一书中就是从阶乘的计算开始的函数递归。导致读过这本经书的同学们,看到阶乘计算第一个想法就是递归。但是在阶乘的计算里,递归并没有提供任何优越之处。在菲波那契数列中,它的效率更是低的非常恐怖。 这里有一个简单的程序,可用于说明递归。程序的目的是把一个整数从二进制形式转换为可打印的字符形式。例如:给出一个值4267,我们需要依次产生字符‘4’,‘2’,‘6’,和‘7’。就如在printf函数中使用了%d格式码,它就会执行类似处理。 我们采用的策略是把这个值反复除以10,并打印各个余数。例如,4267 除10的余数是7,但是我们不能直接打印这个余数。我们需要打印的是机器字符集中表示数字‘7’的值。在ASCII码中,字符‘7’的值是55,所以我们需要在余数上加上48来获得正确的字符,但是,使用字符常量而不是整型常量可以提高程序的可移植性。‘0’的ASCII码是48,所以我们用余数加上‘0’,所以有下面的关系: ‘0’+ 0 =‘0’ ‘0’+ 1 =‘1’ ‘0’+ 2 =‘2’ ... 从这些关系中,我们很容易看出在余数上加上‘0’就可以产生对应字符的代码。接着就打印出余数。下一步再取商的值,4267/10等于426。然后用这个值重复上述步骤。 这种处理方法存在的唯一问题是它产生的数字次序正好相反,它们是逆向打印的。所以在我们的程序中使用递归来修正这个问题。 我们这个程序中的函数是递归性质的,因为它包含了一个对自身的调用。乍一看,函数似乎永远不会终止。当函数调用时,它将调用自身,第2次调用还将调用自身,以此类推,似乎永远调用下去。这也是我们在刚接触递归时最想不明白的事情。但是,事实上并不会出现这种情况。 这个程序的递归实现了某种类型的螺旋状while循环。while循环在循环体每次执行时必须取得某种进展,逐步迫近循环终止条件。递归函数也是如此,它在每次递归调用后必须越来越接近某种限制条件。当递归函数符合这个限制条件时,它便不在调用自身。

深入理解递归函数.docx

深入理解递归函数 刚开始接触编程对递归调用都是比较头痛,很多年前我也会一样。昨天晩上睡觉突然想起了谭浩强C语言的汉诺塔递归调用,记得当吋是在高中的时候,我表姐在上大学,她把谭浩强的C语言给了我,只看书不实践,现在想起来效果还真差。其中递归调用汉诺塔看了好久都没有整明白,直到上大学学习C语言也还没有搞明白,当学到递归调用了,我就去问老师,老是说回去看看,下周告诉我。谁知到老师真的很忙,下周也没有结果。后来自己什么吋候明白的也忘记了。 刚开始接触递归都会告诉你,递归占用资源,使程序复杂,最好不要使用;还有人说,如果这个人一来就是用递归,我肯定不会聘用他。但是我认为这些观点太片面。递归算法的目的降低程序的复杂度,解放大脑负担,让大脑更加专注于问题本身。程序的性能跟递归没有什么关系,更重要的时算法本身,我们会在稍后讲解一下同i种算法同样是递归,性能的差异巨大。设计模式中,很多模式都存在递归。 刚开始接触递归的,往往都会在里面打圈圈,自己越绕越晕,觉得递归太复杂。其实看待递归的时候,也是要分层面看待,不要把自己的大脑当做是电脑,可以绕很多的圈圈,有人说人的大脑同时能处理7个左右的变量,绕一圈就多几个变量,能绕几圈啊。呵呵。找到一个算法,在编写算法的吋候,只考虑一次递归所做的事情,如果遇到到递归调用函数的时候,把他当做一个函数整体考虑,他能完成他要完成的事情,要相信他,也要相信自己。我们所在的层面就是算法的层面,或者一次执行的层面。如果在算法层面和递归调用层面来回穿插的思考,读懂递归算法将非常困难,递归的复杂度就在于压栈会导致大量的变量需要存储,对我们的大脑来说负担太重,但是对汁算机来说是小意思,相对来说算法层面往往很简单,所以我们一定要站在算法层面考虑问题,而不是递归层面。 下面来看我如何一步一步实现汉诺塔:(VS2010C#控制台程序) [csharp] view plaincopyprint^C 1.class Program 2?{ 3?static void Main(string[] args) 4.<

C语言函数递归[1]

递归,作为C语言最经典的算法之一,是一种非常有用的程序设计方法。虽然用递归算法编写的程序结构清晰,具有很好的可读性,还往往使某些看起来不易解决的问题变得容易解决。但在递归函数中,由于存在着自调用过程,程序控制反复进入其自身,使程序的分析设计有一定困难,致使很多初学者往往对递归迷惑不解,也在这上面花了不少的时间,却收效甚微。那么,究竟什么是递归?怎么实现递归呢? 所谓递归,简而言之就是在调用一个函数的过程中又直接或间接地调用该函数本身,以实现层次数据结构的查询和访问。在函数中直接调用函数本身,称为直接递归调用。在函数中调用其它函数,其它函数又调用原函数,这就构成了函数自身的间接调用,称为间接递归调用。 而采用递归方法来解决问题,必须符合以下三个条件: 1、可以把要解决的问题转化为一个新问题,而这个新的问题的解决方法仍与原来的解决方法相同,只是所处理的对象有规律地递增或递减。 说明:解决问题的方法相同,调用函数的参数每次不同(有规律的递增或递减),如果没有规律也就不能适用递归调用。 2、可以应用这个转化过程使问题得到解决。 说明:使用其他的办法比较麻烦或很难解决,而使用递归的方法可以很好地解决问题 3、必定要有一个明确的结束递归的条件。 说明:一定要能够在适当的地方结束递归调用。不然可能导致系统崩溃。 好知道是这样以后;我们来写一个众多教材上的程序:使用递归的方法求n!。 当n>1时,求n!的问题可以转化为n*(n-1)!的新问题。比如n=4: 第一部分:4*3*2*1 n*(n-1)! 第二部分:3*2*1 (n-1)(n-2)! 第三部分:2*1 (n-2)(n-3)! 第四部分:1 (n-4)! 4-4=0,得到值1,结束递归。 我给的源程序如下: #include int fac(int n) {int c; printf("now the number is %d ",n); getchar(); if(n==1 || n==0) c=1; else c=n*fac(n-1); printf("now the number is %d and the %d! is %d",n,n,c); getchar();

什么是递归函数

1.什么是递归函数(recursive function) 递归函数即自调用函数,在函数体内部直接或间接地自己调用自己,即函数的嵌套调用是函数本身。 例如,下面的程序为求n!: long fact(int n) { if(n==1) return1; return fact(n-1)*n;//出现函数自调用 } 2.函数调用机制的说明 任何函数之间不能嵌套定义,调用函数与被调用函数之间相互独立(彼此可以调用)。发生函数调用时,被调函数中保护了调用函数的运行环境和返回地址,使得调用函数的状态可以在被调函数运行返回后完全恢复,而且该状态与被调函数无关。 被调函数运行的代码虽是同一个函数的代码体,但由于调用点,调用时状态,返回点的不同,可以看作是函数的一个副本,与调用函数的代码无关,所以函数的代码是独立的。被调函数运行的栈空间独立于调用函数的栈空间,所以与调用函数之间的数据也是无关的。函数之间靠参数传递和返回值来联系,函数看作为黑盒。 这种机制决定了C/C++允许函数递归调用。 3.递归调用的形式 递归调用有直接递归调用和间接递归调用两种形式。 直接递归即在函数中出现调用函数本身。 例如,下面的代码求斐波那契数列第n项。斐波那契数列的第一和第二项是1,后面每一项是前二项之和,即1,1,2,3,5,8,13,...。代码中采用直接递归调用: long fib(int x) { if(x>2) return(fib(x-1)+fib(x-2));//直接递归 else return1; } 间接递归调用是指函数中调用了其他函数,而该其他函数却又调用了本函数。例如,下面的代码定义两个函数,它们构成了间接递归调用: int fnl(int a) { int b; b=fn2(a+1);//间接递归 //...

递归算法详解

递归算法详解 C通过运行时堆栈支持递归函数的实现。递归函数就是直接或间接调用自身的函数。 许多教科书都把计算机阶乘和菲波那契数列用来说明递归,非常不幸我们可爱的著名的老潭老师的《C语言程序设计》一书中就是从阶乘的计算开始的函数递归。导致读过这本经书的同学们,看到阶乘计算第一个想法就是递归。但是在阶乘的计算里,递归并没有提供任何优越之处。在菲波那契数列中,它的效率更是低的非常恐怖。 这里有一个简单的程序,可用于说明递归。程序的目的是把一个整数从二进制形式转换为可打印的字符形式。例如:给出一个值4267,我们需要依次产生字符‘4’,‘2’,‘6’,和‘7’。就如在printf函数中使用了%d格式码,它就会执行类似处理。 我们采用的策略是把这个值反复除以10,并打印各个余数。例如,4267除10的余数是7,但是我们不能直接打印这个余数。我们需要打印的是机器字符集中表示数字‘7’的值。在ASCII码中,字符‘7’的值是55,所以我们需要在余数上加上48来获得正确的字符,但是,使用字符常量而不是整型常量可以提高程序的可移植性。‘0’的ASCII码是48,所以我们用余数加上‘0’,所以有下面的关系: ‘0’+ 0 =‘0’ ‘0’+ 1 =‘1’ ‘0’+ 2 =‘2’ ... 从这些关系中,我们很容易看出在余数上加上‘0’就可以产生对应字符的代码。接着就打印出余数。下一步再取商的值,4267/10等于426。然后用这个值重复上述步骤。 这种处理方法存在的唯一问题是它产生的数字次序正好相反,它们是逆向打印的。所以在我们的程序中使用递归来修正这个问题。 我们这个程序中的函数是递归性质的,因为它包含了一个对自身的调用。乍一看,函数似乎永远不会终止。当函数调用时,它将调用自身,第2次调用还将调用自身,以此类推,似乎永远调用下去。这也是我们在刚接触递归时最想不明白的事情。但是,事实上并不会出现这种情况。 这个程序的递归实现了某种类型的螺旋状while循环。while循环在循环体每次执行时必须取得某种进展,逐步迫近循环终止条件。递归函数也是如此,它在每次递归调用后必须越来越接近某种限制条件。当递归函数符合这个限制条件时,它便不在调用自身。 在程序中,递归函数的限制条件就是变量quotient为零。在每次递归调用之前,我们都把quotient除以10,所以每递归调用一次,它的值就越来越接近零。当它最终变成零时,递归便告终止。 /*接受一个整型值(无符号0,把它转换为字符并打印它,前导零被删除*/

递归练习题(新、选)

递归程序设计 1.计算最大约数gcd(m,n)可用递归形式定义如下:若m%n等于0,则gcd(m,n)等于n 否则,gcd(m,n)等于gcd(n,m%n)。 #include using namespace std; int gcd(int m, int n){ if (m%n == 0)return n; else return gcd(n, m%n); } int main(){ int m, n; cout << "m="; cin >> m; cout << "n="; cin >> n; cout <>m>>n; if(m==0)break; cout <<"gcd="< using namespace std; int gcd(int m, int n) { if (m%n == 0) return n;

else return gcd(n , m %n ); } int main(){ int m, n; cout << "n="; cin >> n; cout << "m="; cin >> m; cout << gcd(m, n); system("pause"); return 0; }。 2.编写一递归函数,计算下面的级数: i i m 1......31211)(++++= #include using namespace std; double f(double i ){ if (i == 1)return 1; else return (1/i *f(i -1)); } int main(){ int i; cout << "i="; cin >> i; cout << f(i); system("pause"); return 0; }3.27.2017 double k4(double n ) {if (n ==1)return 1; else return (1/n +k4(n -1));} int main() {double n,m; while (1){ cin>>n; if (n==0)break ; cout <<"k4="<

C语言入门教程12(函数递归)

一、栈 在说函数递归的时候,顺便说一下栈的概念。 栈是一个后进先出的压入(push)和弹出(pop)式数据结构。在程序运行时,系统每次向栈中压入一个对象,然后栈指针向下移动一个位置。当系统从栈中弹出一个对象时,最近进栈的对象将被弹出。然后栈指针向上移动一个位置。程序员经常利用栈这种数据结构来处理那些最适合用后进先出逻辑来描述的编程问题。这里讨论的程序中的栈在每个程序中都是存在的,它不需要程序员编写代码去维护,而是由运行是系统自动处理。所谓的系统自动维护,实际上就是编译器所产生的程序代码。尽管在源代码中看不到它们,但程序员应该对此有所了解。 再来看看程序中的栈是如何工作的。当一个函数(调用者)调用另一个函数(被调用者)时,运行时系统将把调用者的所有实参和返回地址压入到栈中,栈指针将移到合适的位置来容纳这些数据。最后进栈的是调用者的返回地址。当被调用者开始执行时,系统把被调用者的自变量压入到栈中,并把栈指针再向下移,以保证有足够的空间存储被调用者声明的所有自变量。当调用者把实参压入栈后,被调用者就在栈中以自变量的形式建立了形参。被调用者内部的其他自变量也是存放在栈中的。由于这些进栈操作,栈指针已经移动所有这些局部变量之下。但是被调用者记录了它刚开始执行时的初始栈指针,以他为参考,用正或负的偏移值来访问栈中的变量。当被调用者准备返回时,系统弹出栈中所有的自变量,这时栈指针移动了被调用者刚开始执行时的位置。接着被调用者返回,系统从栈中弹出返回地址,调用者就可以继续执行了。当调用者继续执行时,系统还将从栈中弹出调用者的实参,于是栈指针回到了调用发生前的位置。 可能刚开始学的人看不太懂上面的讲解,栈涉及到指针问题,具体可以看看一些数据结构的书。要想学好编程语言,数据结构是一定要学的。 二、递归 递归,是函数实现的一个很重要的环节,很多程序中都或多或少的使用了递归函数。递归的意思就是函数自己调用自己本身,或者在自己函数调用的下级函数中调用自己。 递归之所以能实现,是因为函数的每个执行过程都在栈中有自己的形参和局部变量的拷贝,这些拷贝和函数的其他执行过程毫不相干。这种机制是当代大多数程序设计语言实现子程序结构的基础,是使得递归成为可能。假定某个调用函数调用了一个被调用函数,再假定被调用函数又反过来调用了调用函数。这第二个调用就被称为调用函数的递归,因为它发生在调用函数的当前执行过程运行完毕之前。而且,因为这个原先的调用函数、现在的被调用函数在栈中较低的位置有它独立的一组参数和自变量,原先的参数和变量将不受影响,所以递归能正常工作。程序遍历执行这些函数的过程就被称为递归下降。程序员需保证递归函数不会随意改变静态变量和全局变量的值,以避免在递归下降过程中的上层函数出错。程序员还必须确保有一个终止条件来结束递归下降过程,并且返回到顶层。 例如这样的程序就是递归: void a(int); main() { int num=5; a(num);

用递归法解决问题

3.5用递归法解决问题 【教材分析】 “用递归法解决问题”是《算法与程序设计》第三章第5节的内容,学业水平测试对本节内容也达到了B级要求,本节内容是在学习了VB基础知识中的三种基本结构,并且学习了数组、用解析法和穷举法解决问题等算法。本节先后介绍了“什么是递归法”、“自定义函数”、以及应用自定义函数结合递归算法来解决问题实例。通过本节内容的学习可以培养学生分析和分解问题的能力。从教材的结构上看“自定义函数”和“递归算法”是独立的,可以分别讲解,但在使用时两者是相辅相成的。 【学情分析】 这节课的教学对象是高中二年级学生,已经学习了算法与程序设计VB中的一些基础知识,初步了解了算法的概念。特点是在学习循环结构的过程中,学生已经积累了一些“递归”和“穷举”的算法。但是学生对函数尤其是“自定义函数”非常陌生,而“自定义函数”和“递归法”是本册的学习重点,也是以后编程的重点。学习本节内容学生可以充分体会递归算法的思想过程,扩大原来的知识面,进一步认识程序设计的功能,进一步激发学生学习算法与程序设计的兴趣。 【教学目标】 1.知识与技能: 理解什么是递归法,会用递归法的思想分析和解决问题 理解什么是自定义函数,能应用自定义函数实现递归算法的编程 2.过程与方法 学生通过思考、探究,体验递归算法和发现问题与解决问题的步骤 3.情感态度与价值观 在建立数学模型中培养学生的抽象思维能力,培养学生多维度思考问题和解决能力。 树立多学科整合的思想意识,能够用联系的观点解决问题。 【教学重点】 理解什么是递归算法,学会用递归法的思想分析问题。 理解自定义函数的概念。 【教学难点】 用自定义函数和递归算法编写程序解决问题 【教学方法及策略】

41-递归函数 recursion

递归函数 recursion 函数直接或间接的调用自身 示例: ##函数直接调用自身 import time def story(): time.sleep(1) print("从前有座山") print("山上有座庙") print("庙里有个老和尚讲故事:") story() story() ##函数间接调用自身 def fa(): fb() def fb(): fa() fa() print("递归结束") #打印不出,因为到达不了print 递归说明: 1.递归一定要有控制递归的层数,当符合某一条件时,要终止递归 2.几乎所有的递归都能用while循环代替 控制递归的层数示例: def fx(n): print("递归进去第",n,"层") if n==3: return fx(n+1) print("递归退出",n,"层") fx(1)

print("程序结束") ## 递归进去第 1 层 递归进去第 2 层 递归进去第 3 层 递归退出 2 层 递归退出 1 层 程序结束 递归的优缺点: 优点: 递归可以把问题简单化,让思路更为清晰,代码更简洁 缺点: 递归因系统环境影响大,当递归深度太大时,可能会得到不可预知的结果 递归函数的实现方法: 先假设函数已经实现 示例: #求和 1+2+3+4.....+100 的和 def mysum(x): print(x) if x<=1: #设置递归的终止点 return 1 return x+mysum(x-1) v=mysum(100) print(v) #5050 ##最大函数递归深度为1000 练习: 编写程序用递归用阶乘: def myfac(x):

数据结构递归

递归函数 递归函数就是直接或者间接调用自身的函数。 C语言通过运行时堆栈来支持递归的实现的。 递归问题的特点: 1、能将一个问题转变成一个新问题,而新问题与原问题的解法相同或类同,不同的仅是处理的对象,且这些处理对象是变化有规律的 2、可以通过上述转化而使问题简化。 3、必须有一个明确的递归出口。 求解递归问题算法的一般形式: void P (参数表) { if (递归结束条件)可直接求解步骤;-----基本项 else P(较小的参数);------归纳项 } 典型递归的例子: long Fact ( long n ) { if ( n == 0) return 1;//基本项 else return n * Fact (n-1); //归纳项 } 举例:将一个十进制数转化为八进制数。 例:(1348)10 = (2504)8 运算过程中: 1348/8=168 1348%8=4 168/8=21 168%8=0 21/8=2 21%8=5 2/8=0 2%8=2 求解过程是一个反复进行整除和求余的过程。 而得到余数的顺序和八进制数本身是相反的顺序。 #include void conversion(int n) { if (n==0) return ; else { conversion(n/8); //调用自身,但是参数逐步变小 cout<

为了理解递归的工作原理,我们需要追踪递归的执行过程。 当在一个函数的运行期间调用另一个函数时,在运行被调用函数之前,系统需要完成3件事: (1)将实参,主调用函数返回地址等传递给被调用函数保存; (2)为被调用函数的局部变量分配存储区; (3)将控制转移到被调用函数的入口; 从被调用函数返回主调用函数之前,系统也完成3件工作: (1)保存被调用函数的计算结果; (2)释放被调用函数的数据区; (3)依照被调用函数保存的主调用函数返回地址将控制转移到调用函数; 当有多个函数构成嵌套调用时,按照“后调用先返回”的原则,递归函数之间的信息传递和控制转移必须通过“运行时堆栈”来实现。即系统将整个程序运行时所需要的数据空间安排在一个栈中,每当调用一个函数时,就为它分配一个存储区,每当从一个函数退出时,就释放它的存储区。 到这里这个递归函数彻底返回到其他函数调用它的地点,这时候把打印出来的字符一个接一个拼在一起就能看到正确的结果:2504

递归原理讲解

程序函数递归原理讲解 一、栈 在说函数递归的时候,顺便说一下栈的概念。 栈是一个后进先出的压入(push)和弹出(pop)式数据结构。在程序运行时,系统每次向栈中压入一个对象,然后栈指针向下移动一个位置。当系统从栈中弹出一个对象时,最近进栈的对象将被弹出。然后栈指针向上移动一个位置。程序员经常利用栈这种数据结构来处理那些最适合用后进先出逻辑来描述的编程问题。这里讨论的程序中的栈在每个程序中都是存在的,它不需要程序员编写代码去维护,而是由运行是系统自动处理。所谓的系统自动维护,实际上就是编译器所产生的程序代码。尽管在源代码中看不到它们,但程序员应该对此有所了解。 再来看看程序中的栈是如何工作的。当一个函数(调用者)调用另一个函数(被调用者)时,运行时系统将把调用者的所有实参和返回地址压入到栈中,栈指针将移到合适的位置来容纳这些数据。最后进栈的是调用者的返回地址。当被调用者开始执行时,系统把被调用者的自变量压入到栈中,并把栈指针再向下移,以保证有足够的空间存储被调用者声明的所有自变量。当调用者把实参压入栈后,被调用者就在栈中以自变量的形式建立了形参。被调用者内部的其他自变量也是存放在栈中的。由于这些进栈操作,栈指针已经移动所有这些局部变量之下。但是被调用者记录了它刚开始执行时的初始栈指针,以他为参考,用正或负的偏移值来访问栈中的变量。当被调用者准备返回时,系统弹出栈中所有的自变量,这时栈指针移动了被调

用者刚开始执行时的位置。接着被调用者返回,系统从栈中弹出返回地址,调用者就可以继续执行了。当调用者继续执行时,系统还将从栈中弹出调用者的实参,于是栈指针回到了调用发生前的位置。 可能刚开始学的人看不太懂上面的讲解,栈涉及到指针问题,具体可以看看一些数据结构的书。要想学好编程语言,数据结构是一定要学的。 二、递归 递归,是函数实现的一个很重要的环节,很多程序中都或多或少的使用了递归函数。递归的意思就是函数自己调用自己本身,或者在自己函数调用的下级函数中调用自己。 递归之所以能实现,是因为函数的每个执行过程都在栈中有自己的形参和局部变量的拷贝,这些拷贝和函数的其他执行过程毫不相干。这种机制是当代大多数程序设计语言实现子程序结构的基础,是使得递归成为可能。假定某个调用函数调用了一个被调用函数,再假定被调用函数又反过来调用了调用函数。这第二个调用就被称为调用函数的递归,因为它发生在调用函数的当前执行过程运行完毕之前。而且,因为这个原先的调用函数、现在的被调用函数在栈中较低的位置有它独立的一组参数和自变量,原先的参数和变量将不受影响,所以递归能正常工作。程序遍历执行这些函数的过程就被称为递归下降。 程序员需保证递归函数不会随意改变静态变量和全局变量的值,以避免在递归下降过程中的上层函数出错。程序员还必须确保有一个终止条件来结束递归下降过程,并且返回到顶层。

递归题目

例题 计算n的阶乘 #include int factorial(int n) { int result; if (n<0) //判断例外 { printf("输入错误!\n"); return 0; } else if (n==0 || n==1) { result = 1; //回推墙 } else { result = factorial(n-1) * n; //递推关系,这个数与上一个数之间的关系。 } return result; } int main(){ int n = 5; //输入数字5,计算5的阶乘 printf("%d的阶乘=%d",n,factorial(n)); return 0; } 程序在计算5的阶乘的时候,先执行递推,当n=1或者n=0的时候返回1,再回推将计算并返回。由此可以看出递归函数必须有结束条件。 递归函数特点: 1. 每一级函数调用时都有自己的变量,但是函数代码并不会得到复制,如计算5的阶乘时每递推一次变量都不同; 2. 每次调用都会有一次返回,如计算5的阶乘时每递推一次都返回进行下一次; 3. 递归函数中,位于递归调用前的语句和各级被调用函数具有相同的执行顺序; 4. 递归函数中,位于递归调用后的语句的执行顺序和各个被调用函数的顺序相反; 5. 递归函数中必须有终止语句。 一句话总结递归:自我调用且有完成状态。 例题 小明为了学好英语,需要每天记单词,第一天记1个,第二天记2个依次类推,请用代码完

成,算出小明第10天开始的时候会了多少个单词? 分析: 回推墙是“第一天记1个” 递推关系是“第n天记的单词= 第n-1天记的单词数量+n" #include /* 定义获取单词数量的函数*/ int getWordNumber(n) { if(n == 1) { return 1; //回推墙 } else{ return getWordNumber(n-1)+n ; //递推关系 } } int main() { int num = getWordNumber(10); //获取会了的单词数量 printf("小明第10天记了:%d个单词。\n", num); return 0; } 例题 有5个人坐在一起,问第5个人多少岁?他说比第4个人大2岁。问第4个人岁数,他说比第3个人大2岁。问第3个人,又说比第2人大两岁。问第2个人,说比第1个人大两岁。最后问第1个人,他说是10岁。请问第5个人多大? 程序分析: 利用递归的方法,递归分为回推和递推两个阶段。要想知道第5个人岁数,需知道第4人的岁数,依次类推,推到第1人(10岁),再往回推。 #include /* * 请使用递归函数完成本题 * 小编已将正确代码放在左侧任务的“不知道怎么办”里 * 小编希望各位童鞋独立完成哦~ */ //定义一个函数,传送人员序号进去,返回该序号员工的年龄。 int getAge(numPeople) { //定义返回的年龄 int age;

函数递归调用讲解

函数递归调用讲解 一、函数调用与返回流程: 在一个函数中调用另一个函数时,程序控制即转入到被调用的函数中,在函数代码执行完成后,返回到主函数中的调用处继续执行主函数中的后续代码。见以下的程序: #include "Stdio.h" #include "Conio.h" int sub(int x) { int z; ...... return z; } int main(void) { ....... y=sub(x); ....... getch(); return 0; } 当主函数执行到y=sub(x)时,将变量x的值作为参数传递到函数sub的形式参数x中,程序控制转入到sub函数中;执行函数sub中的代码,遇到return z时,将变量z的值作为函数的结果值返回,程序控制转回到主函数main中继续执行其后的代码。如下图所示: 如果在函数sub中又调用了其他的函数如fun,则形成了函数的嵌套调用。

从上图中可以看到,函数调用是逐级调用、逐级返回的。即从函数fun中只能返回到函数sub中,而不能直接返回到函数main中。 二、递归调用 如果一个函数调用了这个函数自己,则形成递归调用。递归调用是一种特殊的嵌套调用,在调用与返回的流程上与函数嵌套调用没有区别。但由于函数调用自己,因此在理解上有一定的难度。 例:使用函数递归调用计算n!。阶乘计算的递推公式为: 0!=1,1!=1……n!=n*(n-1)! #include "Stdio.h" #include "Conio.h" int fun(int n) { int f; if(n==1||n==0) f=1; else f=n*fun(n-1); return f; } int main(void) { int x,p; scanf("%d",&x); p=fun(x); printf("%d",p); getch(); return 0; } 下图示出了当输入x=3时,函数调用与返回的情形。注意:在每一次调用函数fun时,变量n的值都是不同的。

相关文档
最新文档