关于递归的理解
关于递归,相信很多人最初接触的就是斐波那契数列的计算。那么这里就先不讲解斐波那契数列,先举一个简单的例子来想一想生活中的递归。
假设情人节马上到了,你收到女朋友送来的礼物,礼物是一个非常漂亮的盒子。你怀着激动的心情去拆盒子,但是第一个盒子打开里面也装着一个盒子,然后你又打开第二个盒子,发现里面又是一个盒子。嘿嘿,是不是感觉心态有点崩,最后就这样你打开了很多个盒子才找到礼物,发现里面是一个zippo打火机,开心至极。
实际上,这个找打火机的过程就引入了我们今天的主题。为了找到打火机有两种算法供你选择:
- 方法一:
- 创建需要查找的盒子堆
- 只要盒子堆不为空就打开盒子
- 如果里面仍然是盒子就放入盒子堆;如果是打火机就说明礼物找到
- 接下来检查盒子堆是否为空,如果不为空则继续打开;如果为空说明礼物找到
- 方法二:
- 直接打开盒子,如果里面是盒子就继续打开;如果是打火机则礼物已找到
- 如果上一步得到的结果是盒子就重复上一步操作,直至找到礼物
这两种方法都可以找到打火机,但是我们可以发现第二种方式显得更加清晰一些,使人更容易理解,这种方式就是递归;而第一种方式实际上就是循环,循环的优点就是使程序的性能更高,具体原因稍后解释。
在使用递归最重要的一点就是一定要先找到递归的终止条件,也就是怎么样才能让程序终止,如果不能做到这一点,这个程序将会变成死循环。
比如我们求3!
`int test(int i)
{
if(1 == i)
return 1;
else
return i * test(i - 1);
}
int main(void)
{
int ret = 0;
ret = test(3);
printf(“ret = %d”, ret);
return 0;
}
在test函数中斜体部分就是递归终止条件,如果不写这个条件将成为死循环。
下面我们来根据代码具体说一下递归的过程(即使用调用栈的过程):
代码 | 调用栈情况 |
---|
test(3); 3入栈
if(1 == i) -
i * test(i - 1); 2入栈
if(1 == i) -
i * test(i - 1); 1入栈
if(1 == i) 返回1
此时还有3个test函数未调用结束,现在开始调用返回:
当第一个test调用结束 1出栈返回1
当第二个test调用结束 2出栈 返回1*2
当第三个test调用结束 3出栈返回2*3
所以最后的结果就是6
总的来说,整个过程也就相当于入栈出栈的过程。如果还不太清楚,可以找相关习题练习,加深理解。