1、递归概述
-
递归,顾名思义,有递有归才叫递归。
-
若一个对象部分地包含它自己,或用它自己给自己定义,则称这个对象是递归的;
-
若一个过程直接地或间接地调用自己,则称这个过程是递归的过程。
-
说白了,递归就是一个函数:在函数中,调用函数自身,我们把这样的函数叫做递归函数。
-
递归的基本思想是"自己调用自己”
2、递归过程
\quad \quad 递归过程可以理解为递的过程和归的过程,即入栈出栈过程。
- 下图为计算3的阶乘的具体递归调用过程
- 红线为递即入栈过程
- 蓝线为归即出栈过程
2.1 “递”
- 递的过程,就是从调用到找到调用方法内部终止条件的过程。
- 相当于入栈过程:每次调用时,就需要记录当前参数值以及终止位置即挂起的代码位置并入栈。
- 入栈:
2.2 “归”
- 归的过程,就是从终止条件开始,当执行完最里面的方法时候,返回调用方法的调用方法的过程。
- 出栈:
- 每一次递归调用时,需要为过程中使用的参数、局部变量等另外分配存储空间。
- 层层向下递归,退出时的次序正好相反
- 因此,每次递归调用需分配的空间形成递归工作记录,按后先进的栈组织。
3、递归的适用条件
1、问题可以分解成多个子问题来解决,后续的情况可以由前面的状态推出。
2、该问题和子问题的解决思路相同
3、该问题有终止条件,找到终止条件之后就开始进行“归”的过程。
4、递归程序
4.1 三要素
1、 递归语句
- 递归语句即递推公式
- 写递归公式最重要的一点就是找到该问题和子问题的关系,怎么找到之间存在的关系呢?我们只想最后一层与上一层的关系,比如如果我想知道当前队伍的位置,所以我要之前前一个人的位置,然后 +1 就是我的位置了。对于他在什么位置,我丝毫不用关系,而是让递归去解决他的位置。我们可以写出递推公式如下:
// f(n) 代表当前我在队伍中的位置
// f(n-1) 代表我前边那个人的位置
// 递推公式
f(n) = f(n-1) + 1
2、递归出口即递归终止条件
- 递推公式我们很轻松的写出来了,但是没有终止条件的递推公式会永远的执行下去的,所以我们要有一个终止条件终止程序的运行。那么怎么找到终止条件呢?
- 所谓的终止条件就是已知的条件,比如上述的排队打饭的例子中,第一个人正在窗口打饭,他的前边是没有人的,所以他是第一个。第一个人的位置为 1,我们应该怎么表示呢?
// 终止条件
f(1) = 1;
3、递归次数
- 要求递归次数是有限的
4.2 完整的递归程序代码
function f(n){
// 终止条件
if(n == 1) retun 1;
// 递推公式
return f(n-1) + 1;
}
5、递归特点
5.1 优点
- 编程精炼,逻辑清楚,逼近数学递推公式,可读性好
5.2 缺点
-
实现效率低:自己调用自己,每次都会分配内存来保存参数值。导致时间和内存消耗。从而降低效率。
-
内存大量使用可能会导致内存溢出风险。