首页 > 技术文章 > JAVA 递归

DL50 2022-01-17 20:58 原文

方法递归调用

递归就是方法自己调用自己,每次调用时传入不同的变量.递归有助于编程者解决复杂问题,同时可以让代码变 得简洁

1.递归能够解决什么问题?

image-20220115205607679

例子:

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.递归的重要规则

  1. 执行一个方法时,就创建一个新的受到保护的独立空间(栈空间)
  2. 方法的局部变量是独立的不会互相影响,比如n变量,对于基本变量类型
  3. 如果方法传入的是引用类型的参数,他们会共享该引用类型的数据,会相互影响
  4. 递归必须向退出递归的条件逼近,否则就是无限递归,出先栈溢出现象
  5. 当一个方法执行完毕时,或者遇到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;
		 }
	 }
}

运行效果:

image-20220116154734099


迷宫问题

代码如下:

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);
			
		}
	}
}

推荐阅读