递归概述
- 递归是一种函数编程形式,让函数通过自己调用自己,将一个大任务拆分成小任务在每次的递归中进行处理,每个任务的处理具有相似的过程。
- 函数在递归调用的过程中会形成函数调用栈,每个栈帧中存放一个子任务,在满足终止条件时结束递归调用。
递归的条件
- 1、递归终止条件:
这是递归的边界条件,当满足这个条件时,递归将停止,并返回结果 - 2、递推关系:
总体的任务和每次递归处理的小任务之间是总体和部分的关系,并且总体和部分的解决方式是相同的,只是规模更小。 - 3、递推公式:
这是将总体任务拆分为部分小任务的公式和规则,也是递归函数的核心。
递归的核心要点
- 1、递归返回值:
递归的最终返回值是当递归函数达到其终止条件时所返回的值。在递归函数中,终止条件是一个或一组条件,当它们满足时,函数不再进行递归调用,而是直接返回一个值。这个返回值随后会逐层向上传递,最终成为整个递归调用的结果。
如果在递归过程中对上一层递归返回值进行了递归计算,则整个返回值不是条件终止时的值,而是计算之后的总体值。
例如: 下面的函数递归最终返回终止条件时的值,也就是永远返回1,变量p接收这个值。这个返回值在递归出栈时会传递到每一层中。也就是p的值在入栈结束达到终止条件时被赋值为1,后续p的值永远是1不会发生改变,因为在出栈的过程中并没有对p进行操作,p会在出栈时传递到每一层。
static int sum(int n) {
if (n==1) {
return 1;
}
int p = sum(n - 1);
return p;
}
例如: 下面的函数在递归的时候,对上一层返回的值都进行了叠加计算,所以返回值是最终的计算结果。
static int sum(int n) {
if (n==1) {
return 1;
}
return n + sum(n - 1);
}
- 2、递归的参数
递归函数的参数,随着递归函数也会压入栈中,在每一个栈层都有一个确定的值。会被访问两次,分别是入栈和出栈的时候。栈的先进后出原则,入栈和出栈的执行顺序是相反的。
例如: 下面这个方法详细的展示了递归的过程中参数的值
public static void printLevel(int n){
/*栈方法局部变量,每个栈方法相互不影响*/
boolean isDouble=false;
/*入栈结束开始出栈条件,也就是递归返回条件*/
if(n<0) {
System.out.println("------------- 入栈结束,开始出栈 -------------"+n);
return ;
}
/*****************************1、入栈执行的操作 -start*****************************/
System.out.println("递归入栈 "+n);
if(n%2==0){
isDouble=true;
}
if(isDouble){
System.out.println("偶数");
}
if(!isDouble){
System.out.println("奇数");
}
/*****************************1、入栈执行的操作 -end*****************************/
/*****************************2、递归调用,压栈 -start*****************************/
printLevel(n-1);
/*****************************2、递归调用,压栈 -end*****************************/
/*****************************3、出栈执行的操作 -start*****************************/
System.out.println("递归出栈 "+n);
if(isDouble){
System.out.println("偶数");
}
if(!isDouble){
System.out.println("奇数");
}
/*****************************3、出栈执行的操作 -end*****************************/
}
输出结果:
递归入栈 5
奇数
递归入栈 4
偶数
递归入栈 3
奇数
递归入栈 2
偶数
递归入栈 1
奇数
递归入栈 0
偶数
------------- 入栈结束,开始出栈 ------------- -1
递归出栈 0
偶数
递归出栈 1
奇数
递归出栈 2
偶数
递归出栈 3
奇数
递归出栈 4
偶数
递归出栈 5
奇数