什么是递归调用
递归调用是一种特殊的嵌套调用,是某个函数调用自己或者是调用其他函数后再次调用自己的,只要函数之间互相调用能产生循环的则一定是递归调用,递归调用一种解决方案,一种是逻辑思想,将一个大工作分为逐渐减小的小工作。
递归函数特点:
1、函数要直接或间接调用自身。
2、要有递归终止条件检查,即递归终止的条件被满足后,则不再调用自身函数。
3、如果不满足递归终止的条件,则调用涉及递归调用的表达式。在调用函数自身时,有关终止条件的参数要发生变化,而且需向递归终止的方向变化。
扩展资料:
递归调用的过程:
递归调用之前的语句是从上到下的,函数调用之后的语句呢是从下到上的,因为后面的语句要等最下层或者最里面最后调用的那个函数执行之后不再调用了开始执行,然后返回上一层的时候再执行上一层函数调用后面的语句。并且特别注意的是,每次函数返回后直接就是函数调用后面的语句。
递归其实就是利用了函数调用的一些特点,很巧妙的不断调用自己,把一个很大的问题分成了很多部分,让每一个函数解决一部分,并且上一层的结果编译器给我们保留了起来,返回的时候还能用。
所以递归调用一定要是每深入一层都会把问题变得越来越小,而且最后能解决,不然就会无限制的调用自己,形成一个无限的循环,最后造成栈的溢出,最后程序崩溃。
参考资料来源:百度百科-递归调用
什么是递归调用,详细点
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,把它转换为字符并打印它,前导零被删除*/
#include <stdio.h>
int binary_to_ascii( unsigned int value)
{
unsigned int quotient;
quotient = value / 10;
if( quotient != 0)
binary_to_ascii( quotient);
putchar ( value % 10 + '0' );
}
递归是如何帮助我们以正确的顺序打印这些字符呢?下面是这个函数的工作流程。
1. 将参数值除以10
2. 如果quotient的值为非零,调用binary-to-ascii打印quotient当前值的各位数字
3. 接着,打印步骤1中除法运算的余数
注意在第2个步骤中,我们需要打印的是quotient当前值的各位数字。我们所面临的问题和最初的问题完全相同,只是变量quotient的值变小了。我们用刚刚编写的函数(把整数转换为各个数字字符并打印出来)来解决这个问题。由于quotient的值越来越小,所以递归最终会终止。
一旦你理解了递归,阅读递归函数最容易的方法不是纠缠于它的执行过程,而是相信递归函数会顺利完成它的任务。如果你的每个步骤正确无误,你的限制条件设置正确,并且每次调用之后更接近限制条件,递归函数总是能正确的完成任务。
但是,为了理解递归的工作原理,你需要追踪递归调用的执行过程,所以让我们来进行这项工作。追踪一个递归函数的执行过程的关键是理解函数中所声明的变量是如何存储的。当函数被调用时,它的变量的空间是创建于运行时堆栈上的。以前调用的函数的变量扔保留在堆栈上,但他们被新函数的变量所掩盖,因此是不能被访问的。
当递归函数调用自身时,情况于是如此。每进行一次新的调用,都将创建一批变量,他们将掩盖递归函数前一次调用所创建的变量。当我追踪一个递归函数的执行过程时,必须把分数不同次调用的变量区分开来,以避免混淆。
什么叫做嵌套调用?什么叫做递归调用
嵌套调用:
所谓嵌套调用就是在一个函数中调用其他函数的过程叫做函数的嵌套。C++中函数的定义是平行的,除了main()以外,都可以互相调用。函数不可以嵌套定义,但可以嵌套调用。比如函数1调用了函数2,函数2调用了函数3,这便形成了函数的嵌套调用。
递归调用:
在调用一个函数的过程中又直接或间接第调用该函数本身的这一现象,叫做函数的递归调用。
递归可以分为直接递归和间接递归调用。直接递归调用时在调用函数的过程中又调用该函数本身;间接递归调用是在调用f1()函数的过程中调用f2()函数,而f2()函数中又需要调用f1()。
递归方法是从结果出发,归纳出后一结果与前一结果直到初值为止存在的关系,要求通过分析得到:初值+递归函数,然后设计一个函数,这个函数不断使用下一级值调用自身,直到结果已知处。设计递归函数一般选择控制结构。
递归调用的递归详解
一个函数的运行期间调用另一个函数时,在运行被调用函数之前,系统需要完成3件事情:
(1)将所有的实参、返回地址等信息传递给被调用函数保存;
(2)为被调用函数的局部变量分配存储区;
(3)将控制转移到被调函数的入口。 而从被调用函数返回调用函数之前,系统也应完成3件工作:
(1)保存被调函数的计算结果;
(2)释放被调函数的数据区;
(3)依照被调函数保存的返回地址将控制转移到调用函数。当有多个函数构成嵌套调用时,按照后调用先返回的原则。 所有递归函数的结构都是类似的。
(1)函数要直接或间接调用自身。
(2)要有递归终止条件检查,即递归终止的条件被满足后,则不再调用自身函数。
(3)如果不满足递归终止的条件,则调用涉及递归调用的表达式。在调用函数自身时,有关终止条件的参数要发生变化,而且需向递归终止的方向变化。 函数的调用原则和数据结构栈的实现是相一致。也说明函数调用是通过栈实现的。
直接递归调用和间接递归调用区别
1、区别就是直接递归调用调用的是函数本身而间接递归调用调用的是其他函数。例如:在函数a(或过程)中直接引用(调用)函数a本身就是直接递归调用。在函数a(或过程)中调用另外一个函数b,而该函数b又引用(调用)了函数a就是间接递归调用。
2、直接递归是在A函数中嵌套使用A函数然后有一个停止该函数的条件;间接递归是在A函数中调用B函数,然后在B函数中调用A函数,实现递归。
扩展资料
递归调用就是在当前的函数中调用当前的函数并传给相应的参数,这是一个动作,这一动作是层层进行的,直到满足一般情况的的时候,才停止递归调用,开始从最后一个递归调用返回。
递归函数特点:
1、函数要直接或间接调用自身。
2、要有递归终止条件检查,即递归终止的条件被满足后,则不再调用自身函数。
3、如果不满足递归终止的条件,则调用涉及递归调用的表达式。在调用函数自身时,有关终止条件的参数要发生变化,而且需向递归终止的方向变化。
递归调用
首先原代码中的fun函数要么改为void返回类型,要么在*s=1前腰加上return否者程序编译会出错。
fun中有指针变量,可以算是一个全局变量,故,在分析的时候只需要分析在递归的最后一共有几个满足fun(1,&f)或fun(0,&f)的函数。每一个fun(0||1,&f)加1。
例如fun(2,&f)则结果为fun(1,&f)+fun(0,&f)=2。fun(3,&f)结果为=(fun(2,&f)+fun(1,&f))=3.fun(4,&f)=fun(3,&f)+fun(2,&f)=5.fun(5,&f)=fun(4,&f)+fun(3,&f)=8. fun(6,&f)=fun(5,&f)fun(4,&f)=8+5=13