JAVA 递归
方法递归调用
递归就是方法自己调用自己,每次调用时传入不同的变量.递归有助于编程者解决复杂问题,同时可以让代码变 得简洁
1.递归能够解决什么问题?
例子:
1.打印问题
public void test(int n) {
if(n>2) {
test(n-1);
}
System.out.println("n=" + n);
}
2.阶乘的执行机制
//factorial 阶乘
public int factorial(int n) {
if(n==1) {
return 1;
}else {
return factorial(n-1)*n;
}
}
2.递归的重要规则
- 执行一个方法时,就创建一个新的受到保护的独立空间(栈空间)
- 方法的局部变量是独立的,不会互相影响,比如n变量,对于基本变量类型
- 如果方法传入的是引用类型的参数,他们会共享该引用类型的数据,会相互影响
- 递归必须向退出递归的条件逼近,否则就是无限递归,出先栈溢出现象
- 当一个方法执行完毕时,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁,同时当方法执行完毕或者返回时,该方法就执行完毕了
斐波拉切数
题目:请使用递归的思路方式,求出斐波拉契数1,1,2,3,5,8,13...给你一个整数,求出它的值是多少
package Recursion_Practice;
public class RecursionExercise01 {
public static void main(String[] args) {
A a = new A();
int n = 10;
int ret = a.fibonacci(n);
if(ret != n) {
System.out.println("当n=时" + n + "对应的斐波拉契数是" + ret );
}else {
System.out.println(n+"不是斐波拉契数,要求输入的n>=1");
}
}
}
class A{
/*
* 请使用递归的思路方式,求出斐波拉契数1,1,2,3,5,8,13...给你一个整数,
* 求出它的值是多少
*
* 思路分析
* 1.当n=1时 斐波拉契数=1
* 2.当n=2时 斐波拉契数=1
* 3.当n=3时 斐波拉契数=2
* 即当n>=3时 斐波拉契数前两个数的和
* 这里就是递归的思想
*/
public int fibonacci(int n) {
if( n >= 1) {
if( n == 1 || n == 2) {
return 1;
}else {
return fibonacci(n-1) + fibonacci(n-2);
}
}else {
return -1;
}
}
}
猴子吃桃
题目:猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。第二天早上又将第一天剩下的桃子吃掉一半,有多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第 10 天早上想再吃时,发现只剩下一个桃子了。编写程序求猴子第一天摘了多少个桃子
package Recursion_Practice;
public class RecursionExercise01 {
public static void main(String[] args) {
A a = new A();
//斐波拉契数列问题
int n = 10;
int ret = a.fibonacci(n);
if(ret != -1) {
System.out.println("当n=时" + n + "对应的斐波拉契数是" + ret );
}else {
System.out.println(n+"不是斐波拉契数,要求输入的n>=1");
}
//猴子吃桃问题
int day = 1;
int peach = a.peach(day);
if(peach != -1) {
System.out.println(day+"天有" + peach + "个桃子");
}else {
System.out.println("请输入正确的天数(1~10)");
}
}
}
class A{
/*
* 请使用递归的思路方式,求出斐波拉契数1,1,2,3,5,8,13...给你一个整数,
* 求出它的值是多少
*
* 思路分析
* 1.当n=1时 斐波拉契数=1
* 2.当n=2时 斐波拉契数=1
* 3.当n=3时 斐波拉契数=2
* 即当n>=3时 斐波拉契数前两个数的和
* 这里就是递归的思想
*/
public int fibonacci(int n) {
if( n >= 1) {
if( n == 1 || n == 2) {
return 1;
}else {
return fibonacci(n-1) + fibonacci(n-2);
}
}else {
return -1;
}
}
/*
* 猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。
* 第二天早上又将第一天剩下的桃子吃掉一半,有多吃了一个。
* 以后每天早上都吃了前一天剩下的一半零一个。
* 到第 10 天早上想再吃时,发现只剩下一个桃子了。
* 编写程序求猴子第一天摘了多少个桃子
*
* 1. day=10时 有1个桃子
* 2. day=9时 有(day10+1)*2 = 4 设方程求解也是可以的得到这个关系式
* 3. day=8时 有(day9+1)*2 = 10
* 规律就是 当前天数的桃子 = (后一天的桃子 + 1) *2;
*/
//求当前天数的桃树
public int peach(int day) {
if (day == 10) {
//第十天只有一个桃
return 1;
}else if(day >=1 && day <=9){
return (peach(day+1)+1)*2;
}else {
return -1;
}
}
}
运行效果:
迷宫问题
代码如下:
package Recursion_Practice;
public class MiGong {
public static void main(String[] args) {
/*
* 思路
* 1.先创建迷宫,用二维数组表示 int map[][] = new int[8][7]
* 2.先规定 map 数组的元素值: 0表示可走的路,1表示障碍物
* 3.将最上面的一行和最下面的一行,全部设置为1
*/
Tool tool = new Tool();
int map[][] = new int[8][7];
//把行和列外面那一圈都设为障碍物
tool.setBar(map);
tool.printMap(map);
tool.findWay(map, 1, 1);
System.out.println("\n === 找路情况如下");
tool.printMap(map);
}
}
class Tool{
//输出当前地图
public void printMap(int map[][]) {
//当前地图情况
System.out.println("==当前地图情况==");
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[i].length; j++) {
System.out.print(map[i][j]+" ");
}
System.out.println();
}
}
//设置障碍物
public void setBar(int map[][]) {
for (int i = 0; i < 7 ; i++) {
map[0][i] = 1;
map[7][i] = 1;
map[i][0] = 1;
map[i][6] = 1;
}
map[3][1] = 1;
map[3][2] = 1;
}
/*
* 使用递归回溯的思想来解决老鼠出迷宫
*
* 1.findWay 方法就是专门来找出迷宫的路径
* 2.如果找到,就返回true,否则返回false
* 3.map 就是二维数组,即表示迷宫
* 4.i,j 就是老鼠的位置,初始化的位置为(1,1)
* 5.因为是递归的找路,所以我们规定 map 数组的各个值的含义
* 0表是可以走
* 1表示障碍物
* 2表是可以走
* 3表示走过,但是死路
* 6.当map[6][5] = 2时 就说明找到通路了,否则就继续找
* 7.先确定老鼠找路的策略 下->右->上->左
*
*/
public boolean findWay(int map[][],int i, int j) {
if(map[6][5] == 2 ) {
//说明已经找到路了
return true;
}else {
if(map[i][j] == 0) {
//当前这个位置0,说明可以走
//我们假定可以走通
map[i][j] =2;
//使用找路的策略,来确定该位置是否真的可以走通
//下->右->上->左
if(findWay(map,i+1,j)) {//先向下走
return true;
}else if(findWay(map,i,j+1)) {//向右走
return true;
}else if(findWay(map,i-1,j)) {//向上走
return true;
}else if(findWay(map,i,j-1)) {//向左走
return true;
}else {
map[i][j] = 3;//3表示走过但是死路,表示走不通
return false;
}
}else {
//map[i][j] = 1|| map[i][j] =2 || map[i][j] =3
//这些点都是不能走的 return false即可
return false;
}
}
}
}
汉罗塔
package Recursion_Practice;
public class HannoiTower {
public static void main(String[] args) {
Tower tower= new Tower();
tower.move(5, 'A', 'B', 'C');
}
}
class Tower{
/*
* num表示要移动的个数
* a,b,c分别表示A、B、C柱
* 思路:
* 令总共有n个盘子
* 1.先把n-1个盘子移动到辅助用的柱子上 b
* 2.然后把最下面的那个盘子移动到 c 柱子上去
* 3.再把b柱子上的盘子移到c柱子上去
*/
public void move(int num, char a, char b,char c) {
if(num == 1) {
System.out.println(a + "->" + c);
}else {
//如果有多个盘,可以看成两个盘,最下面的和上面的所有
//1)移动上面的所有盘到b,借助c
move(num - 1 , a , c ,b);
//2)把最下面的这个盘移动到c
System.out.println(a + "->" + c);
//3)再把b塔的所有盘,移动动到c,借助a
move(num - 1 , b , a ,c);
}
}
}