递归算法
- 递归的概念:
直接或间接地调用自身的算法称为递归算法。 - 递归的要素包括:
递归表达式和递归结束条件。
阶乘函数
求某个数的阶乘:
- 递归表达式:
n!= n * (n-1)! - 递归结束条件:
n=0时 0!=1 - 实现代码
public class Blog {
public static void main(String[] args) {
//测试:
System.out.println("3的阶乘:"+factorial(3));
System.out.println("6的阶乘:"+factorial(6));
}
public static int factorial(int n){
//递归结束条件:
if (n == 0)
return 1;
//递归表达式:
return n*factorial(n-1);
}
}
- 图解:
Fibonacci(斐波拉契)数列
- Fibonacci数列:无穷数列1,1,2,3,5,8,13,21,34,55,…
- 递归定义式:第n个等于前两个的和
Fibonacci数列相关例题:
一只超级青蛙一次可以跳上1级台阶,也可以跳上2级级台阶。请问,该青蛙跳上一个n级的台阶总共有多少种跳法?
n=0时,fibonacci(0)=1,n=1时,fibonacci(1)=1,n=2时,fibonacci(2)=2,n=3时,fibonacci(3)=3,n=4时,fibonacci(4)=5…fibonacci(n)=fibonacci(n-1)+fibonacci(n-2)斐波拉契数列
public class Blog {
public static void main(String[] args) {
//测试:
System.out.println("4阶台阶:"+fibonacci(4));
System.out.println("6阶台阶:"+fibonacci(6));
}
public static int fibonacci(int n){
if (n == 0 || n == 1)
return 1;
return fibonacci(n-1)+fibonacci(n-2);
}
}
全排列
对一个数组R里面的n个元素进行排列,输出所有的组合。
分析:
n = 1时,perm(R)= (r),r时唯一的元素
n > 1时,perm(R)= r1perm(R1)+r2perm(R3)+…+rn perm(Rn)。每个数依次做第K个
public class Blog {
public static void main(String[] args) {
//测试:
Object[] n = {1,2,3};
Object[] c = {'a','b','c'};
perm(n,0,2);
perm(c,0,2);
}
public static void perm(Object[] n,int k,int m){
if (k == m){
//排列到最后一个
for (int i = 0; i <= m; i++) {
System.out.print(n[i]);
}
System.out.println();
}else {
//还有多个元素,递归产生排列
for (int i = k; i <= m; i++) {
//交换 第i个做第k个
swap(n,k,i);
//定了第k个,其他的做k+1个
perm(n,k+1,m);
//交换回来
swap(n,k,i);
}
}
}
//交换
public static void swap(Object[] n,int k,int i){
Object object = n[k];
n[k] = n[i];
n[i] = object;
}
}
整数划分
一个整数n的划分,最大划分数为m。
总共4种情况:
第一种:整数n = 1的划分,或者最大划分数为1的话,都只有一种。
第二种:整数n小于最大划分数m时,division(n,m)= division(n,n)
第三种:整数n等于最大划分数m时,division(n,m)= division(n,n)=division(n,m)= division(n,n-1)+1
第四种:整数n大于最大划分数m时,division(n,m)= division(n,m-1)+division(n-m,m)
//整数划分
public class Blog {
public static void main(String[] args) {
//测试:
System.out.println(division(6,6));
}
public static int division(int n,int m){
//q(n,m)
// m==1和n==1时
if (m == 1 || n == 1)
return 1;
//n<m时,q(n,m)=q(n,n)
if (n < m)
return division(n,n);
//n==m时,q(n,m)=q(n,n)=q(n,n-1)+1
if (n == m)
return division(n,n-1)+1;
//n>m>1时 q(n,m)=q(n,m-1)+q(n-m,m)
if (n > m && m >1)
return division(n,m-1)+division(n-m,m);
return 0;
}
}
汉诺塔问题
汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
后来,这个传说就演变为汉诺塔游戏,玩法如下:
1.有三根杆子A,B,C。A杆上有若干碟子
2.每次移动一块碟子,小的只能叠在大的上面
3.把所有碟子从A杆全部移到C杆上
使用递归编写一个程序实现汉诺塔问题,要求在输入圆盘数量之后,输出圆盘的移动步骤,输出格式示例如下:
第1步:1号盘从A柱移至B柱
第2步:2号盘从A柱移至C柱
public class Blog {
static int flag;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextInt()){
int n = scanner.nextInt();
flag = 0;
hanoi(n,'A','B','C');
System.out.println();
}
}
public static void hanoi(int n, char x, char y, char z) {
if (n == 1) {
++flag;
System.out.println("第" + flag + "步:" + n + "号盘从" + x + "柱移至" + z + "柱");
} else {
hanoi(n - 1, x, z, y);
++flag;
System.out.println("第" + flag + "步:" + n + "号盘从" + x + "柱移至" + z + "柱");
hanoi(n - 1, y, x, z);
}
}
}
测试:
3
第1步:1号盘从A柱移至C柱
第2步:2号盘从A柱移至B柱
第3步:1号盘从C柱移至B柱
第4步:3号盘从A柱移至C柱
第5步:1号盘从B柱移至A柱
第6步:2号盘从B柱移至C柱
第7步:1号盘从A柱移至C柱