文章目录
- 1 递归的概念
- 2 递归算法
- 3 递归数据结构
- 4 递归实现
- 5 递归与循环差别
1 递归的概念
- 递归是指在定义自身的同时又出现了对自身的调用。
- 如果一个函数在其定义体内直接调用自己,则称直接递归函数;
- 如果一个函数经过一系列的中间调用语句,通过其它函数间接调用自己,则称间接递归函数。
说明递归定义的一个例子是斐波那契级数。它的定义可递归表示成:
2 递归算法
根据斐波那契级数的递归定义,我们可以很自然地写出计算Fib的递归算法。为了便于在表达式中直接引用,我们把它设计成一个函数过程,用C语言描述如下:
long Fib(long n)
{if(n<=1)return n;else return Fib(n-2)+Fib(n-1);
}
函数Fib(n)中又调用了函数Fib(n-1)和Fib(n-2)。这种在函数体内调用自己的做法称为递归调用。包含递归调用的函数称为递归函数。
递归模型不能循环定义,必须满足以下三个条件!
(1) 递归必须得有一个明确的终止条件;
(2) 该函数所处理的问题规模必须在递减;
(3) 这个转化必须是可解的。
递归的精髓在于能否将原始问题转化为属性相同但规模较小的问题
递归求解的思想 :
3 递归数据结构
- 数据结构原则上都可以采用递归的方法来定义,但是习惯上,许多数据结构并不采用递归方式,而是直接定义,如线性表、字符串和一维数组等。
其原因是:这些数据结构直接定义更自然、更直截了当。
- 对于广义表和树,通常给出的是它们的递归定义。使用递归方式定义的数据结构常称为递归数据结构。
4 递归实现
当多个函数嵌套调用时,由于函数的运行规则是:后调用先返回,因此各函数占有的存储管理应实行“栈式管理”
当一个函数在运行期间调用另一个函数时,在运行该被调用函数之前,需先完成三件事:
- 将所有的实在参数、返回地址等信息传递给被调用函数保存;
- 为被调用函数的局部变量分配存储区;
- 将控制转移到被调用函数的入口。
而从被调用函数返回调用函数之前,应该完成:
- 保存被调函数的计算结果;
- 释放被调函数的数据区;
- 依照被调函数保存的返回地址将控制转移到调用函数。
- 一个递归函数的运行过程类似于多个函数的嵌套调用,差别仅在于“调用函数和被调用函数是同一个函数”。
- 为了保证“每一层的递归调用”都是对“本层”的数据进行操作,在执行递归函数的过程中需要一个“递归工作栈”。
递归工作栈的作用是:
- 将递归调用时的实在参数和函数返回地址传递给下一层执行的递归函数;
- 保存本层的参数和局部变量,以便从下一层返回时重新使用它们。
递归算法优缺点分析:
递归算法的优点是明显的:程序结构简洁而清晰,且易于分析,因而许多高级语言都提供了递归机制。
但递归函数也有明显缺点,它往往既费时又费空间。
如何将递归算法转换成非递归算法??
通常借助栈来实现
比如二叉树的先中后序遍历递归与非递归实现,非递归算法就是借助栈实现!
5 递归与循环差别
递归 | 循环 |
---|---|
易于理解 | 不易理解 |
速度慢 | 速度快 |
存储空间大 | 存储空间小 |
分别用递归和循环的方式来求1+2+3+……+100的值。
采用递归:
long sum( int n)
{ if( n == 1) return 1; else return n + sum( n – 1 ); }
采用循环:
long sum(int n)
{long s=0; int i; for(i=0;i<=n;i++)s+=i; return s;
}