我们先看一个经典的斐波那契数列(Fibonacci)。

应用题:兔子出生两个月就可以生兔子,每对兔子每月生一队兔子,假设兔子不死,一年后共多少对兔子?

1 2 3 4 5 6 7 8 9 10 11 12
兔子对数 1 1 2 3 5 8 13 21 34 55 89 144

数学函数定义就是:

大话数据结构 第四章 栈与队列 栈 栈的应用---递归

我们先用常规的迭代实现前几位的斐波那契数列。

大话数据结构 第四章 栈与队列 栈 栈的应用---递归

使用递归来实现:

大话数据结构 第四章 栈与队列 栈 栈的应用---递归

递归的代码干净很多。

递归定义

我们把一个直接调用自己或通过一系列的调用语句间接调用自己的函数,称做递归函数。

每个递归定义必须至少有一个条件,满足时递归不再进行,即不再引用自身而是返回值退出。

迭代和递归的区别是:

迭代使用的是循环结构,递归使用的是选择结构。

递归能使程序的结构更清晰、更简洁、更容易让人理解,从而减少读懂代码的时间。但是大量的递归调用会建立函数的副本,会耗费大量的时间和内存。迭代则不需要反复调用函数和占用额外的内存。

我们说了这么多递归的内容,和栈有什么关系。这得从计算机系统的内部说起。

前面我们已经看到递归是如何执行它的前行和退回阶段的。递归过程退回的顺序是它前行顺序的逆序。在退回过程中,可能要执行某些动作,包括恢复在前行过程中存储起来的某些数据。

这种存储某些数据,并在后面又以存储的逆序恢复这些数据,以提供之后使用的需求,显然很符合栈这样的数据结构,因此,编译器使用栈实现递归就没什么惊讶了。

简单地说,就是在前行阶段,对于每一层递归,函数的局部变量、参数值以及返回地址都被压入栈中。在退回阶段,位于栈顶的局部变量、参数值和返回地址被弹出,用于返回调用层次中执行代码的其余部分,也就是恢复了调用的状态。

对于高级语言,这样的递归问题是不需要用户来管理这个栈,一切都由系统代劳。

相关文章: