认识递归
前言
递归算法是一种直接或间接地调用自身的算法。在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于理解.
递归的分类:
递归分为两种,直接递归和间接递归。
直接递归称为方法自身调用自己。
递归:
递归(英语:Recursion),又译为递回,在数学与计算机科学中,是指在函数的定义中使用函数自身的方法。
与循环(迭代)的区别:
递归:无限调用自身这个函数,每次调用总会改变一个关键字变量,直到这个关键字变量到达边界时候,不再调用。
循环:从开始到结束,一般注重过程。能用递归实现的循环不一定能。 注重循环结束条件和循环过程,而这个结束条件不容易表达(也就是循环不好写)
只注重循环的次数,不注重循环的开hi和结束条件(循环更不好写)
递归思想:有去(再次调用)有回(结果)
递归满足两个条件:
- 有反复执行自身
- 有跳出自身调用的条件(递归出口)
递归算法的应用:
例题一:阶乘
n! = n * (n-1) * (n-2) * …* 1(n>0)
//阶乘
@Test
public void factorialTest(){
System.out.println(factorial(3));
}
public int factorial(int i){
int sum=0;
if (i==0){
return 1;
}else {
return sum=i*factorial( i-1);
}
}
例题二:汉诺塔问题
汉诺塔问题就是:有ABC三根柱子,A柱子上从上到下摞了很多体积依次递增的圆盘,如果将圆盘从A移动到C柱子,且依然保持从上到下依次递增。
public class HanioTest {
public static void main(String[] args) {
int n = 4;
char a = ‘A’,b = ‘B’,c = ‘C’;
hanio(n,a,b,c);
}/** * * @param n 一共需要移动的盘子 * @param a 盘子移动的起始柱子 * @param b 借助的柱子 * @param c 盘子需要移动到的目标柱子 */ public static void hanio(int n,char a, char b, char c){ //只有一个盘子的时候,就直接从A移到C if(n == 1){ move(n,a,c); }else{ //三步曲,注意观察,a,b,c三个的位置变化 //1.把 n-1 个盘子看成一个整体,借助 C 从 A 移动到 B hanio(n-1,a,c,b); //2.把第 n 个盘子从 A 移动到 C move(n,a,c); //3.再把 n-1 盘子整体,借助 A 从 B 移动到 C hanio(n-1,b,a,c); } } public static void move(int n , char a, char b){ System.out.println("把第"+ n +"个盘子从"+ a +"移到"+ b); } }
运行结果:
> 把第1个盘子从A移到B
> 把第2个盘子从A移到C
> 把第1个盘子从B移到C
> 把第3个盘子从A移到B
> 把第1个盘子从C移到A
> 把第2个盘子从C移到B
> 把第1个盘子从A移到B
> 把第4个盘子从A移到C
> 把第1个盘子从B移到C
> 把第2个盘子从B移到A
> 把第1个盘子从C移到A
> 把第3个盘子从B移到C
> 把第1个盘子从A移到B
> 把第2个盘子从A移到C
> 把第1个盘子从B移到C
例题三:全排列
从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。
如1,2,3三个元素的全排列为:
1,2,3
1,3,2
2,1,3
2,3,1
3,1,2
3,2,1
思路:
三个数的全排列:{1,2,3}
第一步:把1放在零位置,剩下的交换{1,2,3,}、{1,3,2}
第二步:还原后把2放在零位置,剩下的交换{2,1,3}、{2,3,1}
第三步:还原后把3放在零位置,剩下的交换{3,1,2}、{3,2,1}
总结就是:m个数先取一个,让剩余的m-1个数全排列。每一步结束后还原原来的状态。