参考大佬博客
1.递归的理解
递归就是自己调用自己的一个过程,我们不必去纠结每一级干了什么,我们只需要关注某一级的实现即可,因为每一级都是相同的!!!
递归可以看做是循环的简化版, 递归的本质可以看做就是循环
比如一个方法A,一直调用自己,这时所有的方法会在一个栈中,当某一个满足了终止条件时,最后一次调用的方法即栈顶的方法会执行完毕然后出栈
,将结果返回给调用它的方法,即此时的栈顶方法一直下去最终第一个A方法执行完毕栈空,程序结束
2.递归三部曲
根据上面的递归的理解,总结出解决递归问题的三个步骤
- 找整个递归的终止条件:递归应该在什么时候结束?
- 找返回值:应该给上一级返回什么信息?
- 本级递归应该做什么:在这一级递归中,应该完成什么任务?
3.递归的经典应用
3.1求和
问题:编写一个方法,传入一个整数n 求1到n的和
要求:使用递归
这个问题我们最简单的可以使用for循环,直接加即可
我们使用递归解决这个问题,求1到n的和,也就是n到1的和
- 第一步-找递归的终止条件,递归
最先执行完毕的是最后的操作
,即最后会完成n+(n-1)
,当n=1的时候,这时无需递归,直接返回1即可 - 第二步-找返回值,我们求n到1的和,肯定希望返回 n+(n-1到1的和)
- 第三步-本级递归做什么:本级递归就是将n和n-1之前的数相加,然后返回给上一级
就是 每一级做的事就是将n+ n后面的所有数的和
然后返回
n n-1 n-2 ... 1
代码实现
public int sum(int n){
//终止条件
if (n==1){
return 1;
//每一级做的事,这个数+他前面的数的和并返回
}else {
return n+sum(n-1);
}
}
3.2阶乘
传入一个整数n,求n到1的阶乘
跟3.1类似
public int jc(){
//到1结束
if(n==1){
return 1;
//每一层做的事就是将这一层的数*前面数的乘积返回
}else{
return n*jc(n-1);
}
}
3.3斐波那契数列
给定一个整数n,求斐波那契数列的第n项
斐波那契数列,除前两项外,其余每一项都等于它的前两项的和
0 1 1 2 3 5 8 13 21 ...
三部曲
我们要求第n项,需要求n-1 和 n-2项 。。。。
找终止条件
:因为前两项不符合,所以当递归到n=0 或者n=1时直接返回对应的0 或 1即可
返回值即这个方法的作用是什么
: 作用就是求第n项的的值
每一级该干什么
:每一级应该将这一项的前两项的和加起来返回给上一级
public int fib(int n){
if(n==0) return 0;
if(n==0) return 0;
//每一级干的事就是将n的前两项的和相加
else return fib(n-1) + fib(n-2);
}
3.4遍历链表
一般的遍历链表都是循环,这里我们使用递归试一试
找终止条件
:当走到null的时候返回
返回值即这个方法的作用是什么
:输出每一个节点的值
每一级该干什么
:输出这一当前节点的值
public void showData2(ListNode head) {
if (head == null) {
return;
}
System.out.println(head.val);
showData2(head.next);
}
3.5反转链表
3.6交换链表中的节点
3.7删除链表中的重复元素
3.7项目应用:组装三级分类
在谷粒商城的项目中的组装三级分类时使用了递归
模拟三级分类进行组装
定义一个实体,判断一个person实例是不是有父分类,就看它的dadId,如果dadId为0,说明这个实例是以及分类,其他实例的dadId等于某一个实例的id
public class Person {
//主键
private Integer id;
//父分类id
private Integer dadId;
//子分类
private List<Person> sons;
}
代码实现
三部曲
1、终止条件 当到最后一级分类时,他没有子分类,就会终止
2、返回值 :返回值代表某一级分类的下一级分类
3、每一级该干什么:现在有一级分类,先找到它的所有二级分类,然后找到所有二级分类的子分类并设置进去,最后返回这个二级分类
//创建一些实例,然后使用一个List装起来,
List<Person> persons = new ArrayList();
@Test
public void 模拟三级分类() {
// 先找到所有的一级分类
List<Person> collect = persons.stream().filter(p -> p.getDadId() == 0).collect(Collectors.toList());
//遍历所有的一级分类 为每一个一级分类设置上二级分类 二级分类设置上一级分类
List<Person> collect1 = collect.stream().peek(p -> p.setSons(get(persons, p))).collect(Collectors.toList());
}
//递归方法 为一个分类设置上它的所有子分类
private List<Person> get(List<Person> persons, Person root) {
//终止条件 当某一个分类没有父分类时结束
if (root.getDadId() == null) {
return null;
}
//先找到这个节点的所有子分类 即root的所有子分类
List<Person> tmp = persons.stream().filter(person -> root.getId().equals(person.getDadId())).collect(Collectors.toList());
//将这个节点的子分类的子分类设置到子分类中
//即找到root的所有子分类的子分类,并设置到属性中
List<Person> res = tmp.stream().peek(person -> person.setSons(get(persons, person))).collect(Collectors.toList());
return res;
}