栈有一个很重要的应用:在程序设计语言中讲了递归。那么什么是递归呢?当你往镜子前面一站,镜子里面就有一个你的像。但你试过两面镜子一起照吗?如果A、B两面镜子互相面对面放着,你往中间一站,嘿,两面镜子都有你的千百个“化身”,为什么会有这么奇妙的现象呢?原来,A镜子里有B镜子的像,B镜子里也有A镜子的像,这样反反复复,就会产生一连串的“像中像”。这是一种递归现象。我们先来看一个经典的递归例子:斐波那契数列(Fibonacci)。为了说明这个数列,这位斐老还举了一个很形象的例子。
一、 栈的应用——递归
在高级语言中,调用自己和其他函数并没有本质的不同。我们把一个直接调用自己或通过一系列的调用语句间接地调用自己的函数,称做递归函数。
函数怎么可以自己调用自己?听起来有些难以理解,不过你可以不要把一个递归函数中调用自己的函数看做是在调用自己,而就当它是在调用另一个函数。只不过,这个函数和自己长得一样而已。当然,写递归程序最怕的就是陷入永不结束的无穷递归中,所以,每个递归都需要一个退出递归的条件。递归使用的是选择结构。递归能使程序的结构更清晰、更简洁、更容易让人理解,从而减少读懂代码的时间。但是大量的递归调用会建立函数的副本,会消耗大量的时间和内存。那么我们讲了那么多递归的内容,和栈有什么关系呢?程序设计基础阶段我们已经了解了递归是如何执行它的前行和退回的。递归过程退回的顺序是它前行顺序的逆序。显然这符合栈的存储方式。简单的说,就是在前行阶段,对于每一层递归,函数的局部变量、参数值以及返回地址都被压如栈中。在退回阶段,位于栈顶的局部变量、参数值和返回地址被弹出,用于返回调用层次中执行代码的其余部分,也就是恢复了调用的状态。当然,对于现在的高级语言,这样的递归问题是不需要用户来管理这个栈的,一切都由系统代劳就可以了。
- 1. ACM算法:n的阶乘
n的阶乘意思是:从一乘到n,是一个连续的乘法问题。其中n是自然数。
实现如下:
int fun(int n) { if(n==1) { return 1; } else { return fun(n-1)*n; } }
- 2. ACM算法:斐波那契数列实现
说如果兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来。假设所有兔都不死,那么一年以后可以繁殖多少对兔子呢?
我们拿新出生的一对小兔子分析一下:第一个月小兔子没有繁殖能力,所以还是一对,两个月后,生下一对小兔子数共有两对;三个月后,老兔子又生下一对,因为小兔子还没有繁殖能力,所以一共是三对····依次类推。
那么很简单就推出1,1,2,3,5,8,13····构成了一个序列。这个数列有个十分明显的特点,那是:前面相邻两项之和,构成了后一项。
int fun(int n)//计算斐波那契数列第n项的值 { if(n==1||n==2) { return 1; } else { return fun(n-1)+fun(n-2); } }
- 3. ACM算法:n的k次幂
int fun(int n,int k) { if(k==1) { return n; } else { return fun(n,k-1)*n; } }
- 4. ACM算法:字符串逆转
void strReverse(char s[],int len) { if(len==1) { printf(“%c”,s[0]); } else { printf(“%c”,s[len-1]); strReverse(