什么是递归
任何调用自身的函数成为递归。递归是从跟数学领域借鉴过来的一种有用的技术,递归代码通常比迭代代码更加简洁易懂。
实例
以阶乘喂例,其递归定义如下:
n!=1 n=0
n!=n*(n-1)! n>0
复制代码
代码实现:
public static void main(String[] args) {
int fact = Fact(5);
System.out.println(fact);
}
static int Fact(int n){
if (n==1){
return 1;
}
if (n==0){
return 1;
}
return n*Fact(n-1);
}
复制代码
递归可视化
每次递归调用都在内存中生成一个新的函数副本,一旦函数结束,这些副本就从内存中删除。
递归与迭代
递归:
- 当达到基本情形时,递归终止
- 每次递归都需要额外的空间用于栈帧开销
- 如果无穷递归(没有出口),程序会堆栈溢出
- 某些问题用递归更容易解决
迭代:
- 当循环条件为假时,迭代终止
- 每次迭代不需要额外空间
- 出现死循环后程序会一直循环执行
- 求解问题可能没有递归那样显而易见
递归算法的经典用例
- 斐波那契数列、阶乘
- 归并排序、快速排序
- 二分查找
- 树的遍历
- 图的遍历:深度+广度
- 动态规划
- 分治算法
- 汉诺塔
- 回溯算法
相关问题
- 汉诺塔谜题 算法:
- 将源柱最上面的n-1个圆盘移动到辅助柱上
- 将第n个圆盘从源柱移到目的柱。
- 将辅助柱的n-1个圆盘一刀目的柱
- 圆柱最上面的n-1个圆盘移动到辅助柱又可以看成一个新问题,然后以同样的方式解决。
/**
* @param n 第几个圆盘
* @param frompeg 源柱
* @param topeg 目标柱
* @param auxpeg 辅助柱
*/
void TowersOfHanoi(int n,char frompeg,char topeg,char auxpeg){
/**
* 如果只有一个圆盘,直接移动并返回
*/
if (n == 1){
System.out.println("move disk 1 from peg"+frompeg+"to peg"+topeg);
}
/**
* 利用C柱做辅助,将A最上面的n-1个圆盘移动到B
*/
TowersOfHanoi(n-1,frompeg,auxpeg,topeg);
/**
* 将剩下的圆盘从A移动到C
*/
System.out.println("move disk from peg"+frompeg+"to peg"+topeg);
/**
* 利用A做辅助,将B上的n-1个圆盘移动到C
*/
TowersOfHanoi(n-1,auxpeg,topeg,frompeg);
}
复制代码
- 给定一个数组,用递归方法判定数组中的元素是否是有序的。
int isArrayInSortedOrder(int[] a,int index){
if (a.length == 1){
return 1;
}
return a[index-1]<=a[index-2]?0:isArrayInSortedOrder(a,index-1);
}
复制代码
什么是回溯
回溯是一种采用分治策略进行穷举搜索的方法。
回溯经典用例
- 二进制串
- 生成k进制串
- 背包问题
- 广义字符串
- 哈密顿回路
- 图着色问题
相关问题
- 生成所有n位长的字符串。假设A[0..n-1]是一个大小为n的数组。
static void Binary(int n){
if (n<1){
Arrays.stream(A).forEach(s-> System.out.print(s+" "));
}else {
A[n - 1] = 0;
Binary(n - 1);
A[n - 1] = 1;
Binary(n - 1);
}
}
复制代码
根据问题规模减小和递归求解主定理可以求得时间复杂度为2^n