栈有一个很重要的应用:在程序设计语言中实现了递归。
那么什么是递归呢?当你往镜子前面一站,镜子里面就有一个你的像。但你试过两面镜子一起照吗?如果A、B两面镜子相互面对面放着,你往中间一站,嘿嘿,两面镜子里都有你的千百个“化身”。为什么会有这么奇妙的现象呢?原来,A镜子里有B镜子的像,B镜子里也有A镜子的像,这样反反复复,就会产生一连串的“像中像”。这是一种递归现象。
我们先来看 个经典的递归例子:斐被那契数列Fibonacci。 为了说明这个数列,这位斐老还举了 个很形象的例子。
说如果兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来。假设所有兔都不死,那么一年以后可以繁殖多少对兔子呢?
我们拿新出生的一对小兔子分析一下:第一个月小兔子没有繁殖能力,所以还是一对;两个月后,生下一对小兔子数共有两对;三个月以后,老兔子又生下一对,因为小兔子还没有繁殖能力,所以一共是三对……依次类推可以列出下表。
表中数字1,1,2,3,5,8,13……构成了一个序列。这个数列有个十分明显的特点,那是:前面相邻两项之和,构成了后一项。
可以发现,编号①的一对兔子经过6个月就变成了8对兔子了。如果我们用数学函数来定义:
先考虑一下,如果我们要实现这样的数列用常规的迭代的办法如何实现?假设我们需要打印出前 40 位的斐波那契列数。
代码如下:
int main ()
{
int i;
int a[40];
a[0]=0;
a[1]=1;
printf("%d",a[0]);
printf("%d",a[1]);
for(i = 2;i < 40; i++)
{
a[i]= a[i-1] + a[i-2];
printf("%d",a[i]);
}
return 0;
}
如果用递归来实现,还可以更简单。
斐波那契的递归函数代码如下:
int Fbi (int i)
{
if( i < 2 )
return i == 0 ? 0 : 1 ;
return Fbi(i - 1) + Fbi (i - 2) ; /*这里 Fbi 函数自己,它在调用自己 */
}
int main()
{
int i;
for (in t i = 0 ; i < 40 ; i++ )
printf ("%d", Fbi(i)) ;
return 0;
}
怎么样,相比较迭代的代码,是不是干净很多。嘿嘿,不过要弄懂它得费点脑子。
函数怎么可以自己调用自己?听起来有些难以理解,不过你可以不要把一个递归函数中调用自己的函数看作是在调用自己,而就当它是在调另一个函数。只不过,这个函数和自己长得一样而已。
我们来模拟代码中的Fbi(i)函数当i=5的执行过程,如下图所示:
我们把一个直接调用自己或通过一系列的调用语句间接的调用自己的函数,叫做递归函数。
当然,每个递归定义必须至少有一个条件,满足时递归不在进行,即不再引用自身而是返回值退出。