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

上传人:daj****de 文档编号:168288400 上传时间:2022-11-09 格式:DOCX 页数:6 大小:11.33KB
返回 下载 相关 举报
递归调用详解分析递归调用的详细过程_第1页
第1页 / 共6页
递归调用详解分析递归调用的详细过程_第2页
第2页 / 共6页
递归调用详解分析递归调用的详细过程_第3页
第3页 / 共6页
点击查看更多>>
资源描述
递归调用详解,分析递归调用的详细过程2009年 05 月 23 日 星期六 22:52 一、栈在说函数递归的时候,顺便说一下栈的概念。栈是一个后进先出的压入(push)和弹出(pop)式数据结构。在程序运行时, 系统每次向栈中压入一个对象,然后栈指针向下移动一个位置。当系统从栈中弹 出一个对象时,最近进栈的对象将被弹出。然后栈指针向上移动一个位置。程序 员经常利用栈这种数据结构来处理那些最适合用后进先出逻辑来描述的编程问 题。这里讨论的程序中的栈在每个程序中都是存在的,它不需要程序员编写代码 去维护,而是由运行是系统自动处理。所谓的系统自动维护,实际上就是编译器 所产生的程序代码。尽管在源代码中看不到它们,但程序员应该对此有所了解。再来看看程序中的栈是如何工作的。当一个函数(调用者)调用另一个函数 (被调用者)时,运行时系统将把调用者的所有实参和返回地址压入到栈中,栈指 针将移到合适的位置来容纳这些数据。最后进栈的是调用者的返回地址。当被调 用者开始执行时,系统把被调用者的自变量压入到栈中,并把栈指针再向下移, 以保证有足够的空间存储被调用者声明的所有自变量。当调用者把实参压入栈 后,被调用者就在栈中以自变量的形式建立了形参。被调用者内部的其他自变量 也是存放在栈中的。由于这些进栈操作,栈指针已经移动所有这些局部变量之下。 但是被调用者记录了它刚开始执行时的初始栈指针,以他为参考,用正或负的偏 移值来访问栈中的变量。当被调用者准备返回时,系统弹出栈中所有的自变量, 这时栈指针移动了被调用者刚开始执行时的位置。接着被调用者返回,系统从栈 中弹出返回地址,调用者就可以继续执行了。当调用者继续执行时,系统还将从 栈中弹出调用者的实参,于是栈指针回到了调用发生前的位置。可能刚开始学的人看不太懂上面的讲解,栈涉及到指针问题,具体可以看 看一些数据结构的书。要想学好编程语言,数据结构是一定要学的。二、递归递归,是函数实现的一个很重要的环节,很多程序中都或多或少的使用了 递归函数。递归的意思就是函数自己调用自己本身,或者在自己函数调用的下级 函数中调用自己。递归之所以能实现,是因为函数的每个执行过程都在栈中有自己的形参和 局部变量的拷贝,这些拷贝和函数的其他执行过程毫不相干。这种机制是当代大 多数程序设计语言实现子程序结构的基础,是使得递归成为可能。假定某个调用 函数调用了一个被调用函数,再假定被调用函数又反过来调用了调用函数。这第 二个调用就被称为调用函数的递归,因为它发生在调用函数的当前执行过程运行 完毕之前。而且,因为这个原先的调用函数、现在的被调用函数在栈中较低的位 置有它独立的一组参数和自变量,原先的参数和变量将不受影响,所以递归能正 常工作。程序遍历执行这些函数的过程就被称为递归下降。程序员需保证递归函数不会随意改变静态变量和全局变量的值,以避免在 递归下降过程中的上层函数出错。程序员还必须确保有一个终止条件来结束递归 下降过程,并且返回到顶层。例如这样的程序就是递归:void a(int);main()int num=5;a(num);void a(int num)if(num=0) return; printf(%d,num); a(-num);在函数a()里面又调用了自己,也就是自己调用本身,这样就是递归。那 么有些人可能要想,这不是死循环吗?所以在递归函数中,一定要有ret urn语 句,没有return语句的递归函数是死循环。我们分析上面的例子,先调用a(5),然后输出5,再在函数中调用本身a(4), 接着回到函数起点,输出4,,一直到调用a(0),这时发现已经满足if条 件,不在调用而是返回了,所以这个递归一共进行了 5次。如果没有这个ret urn, 肯定是死循环的。虽然递归不难理解,但是很多在在使用递归函数的时候,问题多多。这里 面一般有两个原因:一是如何往下递归,也就是不知道怎么取一个变量递归下去; 二是不知道怎么终止递归,经常弄个死循环出来。下面看几个例子:1.求1+2+100的和先分析一下。第一递归变量的问题,从题目上看应该取1,2,100 这些变量的值作为递归的条件;第二就是如何终止的问题,从题目上看应该是当 数为100的时候就不能往下加了。那么我们试着写一下程序。int add(int);main()int num=1,sn; sn=add(num); printf(%dn,sn);getch();int add(int num)static int sn;sn+=num;if(num=100) return sn;add(+num);分析一下程序:前调用add(l),然后在子函数中把这个1加到sn上面。 接着调用add(2),再把sn加2上来。这样一直到100,到了 100的时候,先加 上来,然后发现满足了 if条件,这时返回sn的值,也就是1+2+100的值 了。这里有一个问题一定要注意,就是 static int sn;有些人就不明白,为什么要使用static类型修饰符,为什么不使用int sn=0; ?如果使用int sn=0;这样的语句,在每次调用函数add()的时候,sn的 值都是赋值为0,也就是第一步虽然加了 1上来,可是第二次调用的时候,sn又 回到了 0。我们前面说了,static能保证本次初始化的值是上次执行后的值,这 样也就保证了前面想加的结果不会丢失。如果你修改为int sn=0,最后结果一 定是最后的100这个值而不是5050。2.求数列 s(n)=s(n-1)+s(n-2)的第 n 项。其中 s(1)=s(2)=1。可以看出,终止条件一定是s(1)=s(2)=1。递归下降的参数一定是n。int a(int);main()int n,s;scanf(%d,&n);s=a(n);printf(%dn,s);getch();int a(int n)if(n3) return 1; return a(n-1)+a(n-2);这个题目主要说明的是,在函数中,不一定只有一个 return 语句,可以有 很多,但是每次对归的时候只有一个起作用。题目不难理解,这儿不分析了。说了这些递归,其实它和函数的调用没有大的区别,主要就是一个终止条 件要选好。递归函数很多时候都能用循环来处理。main()int n=20,array20;int i;for(i=0;in;i+)if(i2) arrayi=1;else arrayi=arrayi-1+arrayi-2;printf(%dn,array19);getch();上面的程序就是实现一模一样的功能的。但是它有一个缺陷,就是 n 的值 不是通过键盘输入来得到。如果想通过键盘来得到n可以这样: main()int n,i;int s1=1,s2=1,temp scanf(%d,&n);for(i=3;i=n;i+) temp=s2; s2+=s1;s1=temp;printf(%dn,s2); getch();但是在某些场合,使用递归比使用循环要简单的多。而且有些题目,一看就知道应该使用递归而不是循环来处理。
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 办公文档 > 解决方案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!