连续两次递归调用的粗浅分析

本文将从两个简单代码出发,对具有连续两次递归调用的程序进行粗浅分析,试图从堆栈的角度对其进行解释。

首先,什么是递归函数?

在数学与计算机科学中,递归(Recursion)是指在函数的定义中使用函数自身的方法。实际上,递归,顾名思义,其包含了两个意思:递 和 归,这正是递归思想的精华所在。

正如上面所描述的场景,递归就是有去(递去)有回(归来),如下图所示。“有去”是指:递归问题必须可以分解为若干个规模较小,与原问题形式相同的子问题,这些子问题可以用相同的解题思路来解决;“有回”是指 : 这些问题的演化过程是一个从大到小,由近及远的过程,并且会有一个明确的终点(临界点),一旦到达了这个临界点,就不用再往更小、更远的地方走下去。最后,从这个临界点开始,原路返回到原点,原问题解决。

 由此可看出,对于递归函数的程序编写角度而言,有两个关键点必须紧紧抓住。

(1)递归出口:即递归的结束条件,到何时不再递归调用下去,开始归来。

(2)递归式子:当前函数结果与准备调用的函数结果之间的关系,如求阶乘函数Factorial(N)=N*Factorial(N-1)。

理解完递归后,先来看第一个程序。

#include <stdio.h>
void rec(int N);
int main()
{
	rec(11);
	return 0;
 } 

void rec(int N) {
	if (N>0){
		rec(N - 10);//rec1
		rec(N - 1);//rec2
	}
	printf("%d\n",N);  //此时的打印就相当于出栈 
	printf("*******\n");
	return; 
}

打印结果为:

-9
*******
0
*******
1
*******
0
*******
-1
*******
-2
*******
-3
*******
-4
*******
-5
*******
-6
*******
-7
*******
-8
*******
-9
*******
0
*******
1
*******
2
*******
3
*******
4
*******
5
*******
6
*******
7
*******
8
*******
9
*******
10
*******
11
*******

 

 第一步:先将N=11压栈,明显满足递归条件,故进行rec1的递归压栈,当N=-9时不满足递归条件就开始出栈;

第二步:rec1开始出栈时,栈顶元素为-9,故N=-9出栈。此时栈顶为N=1,满足递归条件,按照代码顺序执行,则rec1出栈操作中断,转而执行rec2的入栈操作,递归之后N=0(N-1)入栈,很明显N=0不满足递归条件故0出栈,也就是说rec2递归结束开始出栈(即0出栈)。

第三步:前面提到,在中断rec1出栈操作后才执行rec2的递归入栈操作的,因此在rec2结束之后转回来接着执行rec1的出栈操作,即当前栈顶N=1出栈。

第四步:当前栈顶N=11,满足递归条件,按照代码顺序执行rec2的入栈操作,一次递归后N=10。此时仍然满足递归条件,故按照代码顺序执行rec1入栈,递归后N=0入栈。很明显N=0不满足递归条件故0出栈。

第五步:当前栈顶N=10,满足递归条件,按照代码顺序执行rec2的入栈操作,以此类推。

下面是出入栈的部分过程

 且看第二个程序。


#include <stdio.h>

void fun(int n)
{
	n--;
	
	if ( 0 == n ) //跳出递归的条件 
	{
		printf("end\n");
		return ;//出栈 
	}

	printf("fun --> %d\n" ,n);//fun函数的值
	fun(n);//fun1
	fun(n);//fun2
	//printf("fun --> %d\n" ,n);
}

int main()
{
	fun(5);
	
}

打印结果为:

fun --> 4
fun --> 3
fun --> 2
fun --> 1
end
end
fun --> 1
end
end
fun --> 2
fun --> 1
end
end
fun --> 1
end
end
fun --> 3
fun --> 2
fun --> 1
end
end
fun --> 1
end
end
fun --> 2
fun --> 1
end
end
fun --> 1
end
end
 

第一步:输入5入栈,则fun1递归4,故第一次递归输出 4 3 2 1并入栈,最后栈顶为n=0(1--)。此时明显n=0满足递归出口条件,结束fun1递归开始出栈,即0出栈。

第二步:此时n=1,按照代码顺序执行fun2,即中断fun1出栈操作开始执行fun2。fun2递归得到n=0,即栈顶为0,明显满足递归出口条件,结束fun2递归开始出栈,即0出栈。

第三步:此时栈顶为n=1。继续fun1出栈操作,即1出栈。此时n=2,按照代码顺序执行fun2,即中断fun1出栈开始执行fun2。注意,此时n=2,n--后得到n=1,按照代码顺序执行fun1,n=1、n=0入栈,得到栈顶为n=0。

第四步:n=0满足递归出口条件,结束fun1递归开始出栈,即0出栈。此时栈顶为n=1,按照代码顺序执行fun2,即中断fun1出栈开始执行fun2。fun2递归得到n=0,结束fun2递归且n=0出栈。

第五步:继续fun1出栈,即n=1、n=2出栈。此时栈顶为n=3,则继续中断fun1出栈操作开始执行fun2。

第六步:以此类推。

下面是出入栈的部分过程:

以上只是一些粗浅思考,真正理解递归的堆栈过程还是回归到程序调试上,一步一步调试查看变量。 

  • 27
    点赞
  • 85
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xuuyann

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值