关于递归算法
一、递归概述
1.在了解本文之前需要准备什么知识
在了解递归之前,需要掌握数据结构中的栈数据结构,因为递归调用和栈的原理息息相关,如果你还不会栈的话,可以观看我的栈入门基础,附上链接: 栈基础入门
2.递归的基本介绍
1)递归的概念
简单来说,递归就是方法【函数】自身调用自身,每一次调用的时候传入的参数都是不一样的,或者换一种说法,递归就是方法【函数】不断进行压栈的过程。
2)如何理解递归
递归顾名思义,我们可以将其分为两部分去理解:
- 递出去
什么叫做递出去呢?因为方法的递归调用其实就是进行压栈【push】操作,方法每执行自己一次,都会压栈一次,直到最终达到递归结束的条件,此时就不会在进行压栈了,就要开始“归回来了”。 - 归回来
归回来就是递出去的时候达到了结束递归的条件,此时处于栈顶的方法会逐渐弹出【pop】,栈顶每结束【弹出】一个方法,就会返回到上一个调用它的方法,这个方法弹栈的过程就是“归回来”。
3.递归在内存中的模型
我们以java虚拟机(简称JVM)为例,讲解递出去与归回来的内存模型:在JVM中,有一个区域叫做栈区,所有方法(包括main方法)的执行都是在栈区中单独开辟一个独属于该方法的栈空间,整个方法在栈区中进行压栈操作,我们以如下代码为例画图讲解。
public class no_01_递归的概念 {
public static void main(String[] args) {
//调用方法m,传入一个3
m(3);
}
public static void m(int n){
//递归结束的条件:参数n等于0时方法结束
if (n == 0)
return;
//递归调用,参数应该逐渐向递归结束的条件靠近
m(n - 1);
}
}
4.递归需要注意的事项
1)每一个方法执行的时候都会在栈区开辟一块独属于该方法的栈帧(栈空间),然后这块独立空间在栈区进行压栈操作,main方法是第一个被执行的方法,所以main方法总是第一个压栈。
2)当一个方法执行完毕后,或者遇到return,该方法就会结束,遵循谁调用,就将结果返回给谁的原则。
3)如果方法中的参数是引用数据类型的变量【比如数组】,那么递归调用的时候,所有方法共享同一个对象。
4)递归的时候必须要有结束递归的条件,这一点非常重要!!!否则会出现死递归,也就是递出去就回不来了,此时会发生栈溢出错误。
5)递归的时候必须向结束递归的条件靠近,否则也会发生栈溢出。
6)因为栈区空间是有限的,所以即使在向递归结束的条件靠近,也有可能出现栈溢出,因为递归太深了。
二.递归的基本使用
1.递归打印数字
1)题目介绍
1.题目:给你一个数字n = 5,并将n打印出来,n逐渐递减1,当n == 3时,结束打印。
2.要求:使用递归
3.结果: 5 4
2)思路分析
1.递归结束的条件为:n == 3
2.将当前的n输出
3.调用递归:递归时每一次传入的参数要减1
3)代码实现
public class 递归打印 {
public static void main(String[] args) {
print(5);
}
public static void print(int n){
//递归结束的条件
if (n == 3)
return;
//打印当前的n
System.out.println("n = " + n);
//递归调用,参数递减1
print(n - 1);
}
}
2.递归求阶乘
1)题目介绍
1.题目:使用递归求解n的阶乘(n >= 0)
2.要求:使用递归求解
2)思路分析
1.首先判断传入参数n是否为0或者是1,如果是直接返回n即可
2.递归结束的条件应该为:当n逐渐递减为1的时候,结束递归(此步骤可以和上一步重合,因为上一步也是判断n是否为1,为1就直接返回n)
3.让当前的n与下一次自身调用的返回值累乘
3)代码实现
public class 递归阶乘 {
public static void main(String[] args) {
int result = getFactorial(4);
System.out.println(result);
}
public static int getFactorial(int n){ //4
//1.判断n的值是否为0或1,如果是直接返回n
if (n == 1 || n == 0)
return n;
else//2.递归调用,让当前的n与下一次调用的返回值相乘
return n * getFactorial(n - 1);
}
}
三、递归小结
1.理清楚递出去【方法压栈】,与归回来【方法弹栈】的含义。
2.知道方法结束后返回的位置是在上一级调用该方法的地方。
3.找准递归结束的条件,避免死递归【一直压栈,没有返回,栈溢出】
4.递归的应用途径非常广泛,比如
1)迷宫问题
2)八皇后问题
3)归并排序算法
4)快速排序算法
5)二分查找算法
6)分支算法
等等许多经典的算法与面试题都会用到递归,所以掌握好递归算法是非常有必要性的!