方法递归调用及应用实例

递归调用简单的说就是方法自己调用自己,每次调用时传入不同的变量。解决复杂问题的同时能让代码变得简洁。

先来举两个小例子来理解一下递归调用的机制:

1.打印问题

public class Recursion01{
	//编写一个main方法
	public static void main(String[] args) {
		T t1 = new T();
		t1.test(4);  //输出什么?
	}
}

class T{
	public void test(int n){
		if(n > 2){
			test(n - 1 );
		}
		System.out.println("n = "+ n);
	}
}

这段代码的目的是:当我们给方法传入一个值时,去进行一个判断,如果大于2,就继续调用方法,直到n不大于2时输出结果。那么想一下这段简单的代码输出的是什么?

结果为什么是这样呢?按照代码来看它应该只输出“n = 2”就可以了啊。 我们来看一下他的调用机制:

按照语句执行,会在堆中创建一个t1对象,接下里调用test方法,我们知道当方法被调用时就会产生一个新栈,我们在方法里传入的参数为4,直到n=2时停止调用test方法,因此会产生三个新栈(如上图所示)

方法调用停止之后,要执行输出语句,要把每个栈的结果都要输出。栈是一种要满足先进后出原则的存储结构,因此要先输出最上层的栈帧,然后逐层返回结果。输出结果即为图2所示。

我们改写一下代码,如下图:

这时的输出结果为:

这是因为输出语句写在了else的分支语句中,只有不满足n>2这一条件时才会进行输出当前栈帧的结果。

2.阶乘问题

不知道大家是否已经明白了递归调用的机制,我们再来看一个经典的递归调用的案例---阶乘。

来看以下代码:

输出结果为120,这不用多说,我们直接来看它的调用机制,

我们传入的参数为5,根据if条件可知factorial方法会被调用5次,产生5个新栈帧,直至n为1时,返回f(1)的值为1,依次返回上一层栈帧的结果。最终得到5得阶乘。


3.递归调用的重要规则

  1. 执行一个方法时,就创建一个新的受保护得独立空间(栈空间)
  2. 方法得局部变量是独立的,不会相互影响,比如n变量
  3. 如果方法中使用的是引用数据类型变量(比如数组,对象),就会共享该引用类型的数据
  4. 递归必须向退出递归的条件逼近,否则就会无限递归,出现栈溢出(StackOverflowError)
  5. 当一个方法执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁,同时当方法执行完毕或者返回时,该方法也就执行完毕

4.斐波那契数列

斐波那契数列也是递归调用的经典案例,不过不是很难,这里简单介绍一下,斐波那契数是其前两个数的和。代码放在这里,大家自行思考其调用机制:

5.递归调用应用实例---迷宫问题

我们先把迷宫的形状贴在这里

迷宫为8行7列的表格型,我们可以用二维数组来实现迷宫的创建

public class MiGong{
	//编写main方法
	public static void main(String[] args) {
		//思路
		//1.先创建二位数组表示 int[] []map = new int[8][7]
		//2.先规定map数组的元素值:0表示可以走 1表示障碍物

		int [] [] map = new int [8][7];

		//将最上面的一行和最下面的一行,全部设置为1
		for (int i = 0;i < 7;i++ ) {
			map[0][i] = 1;
			map[7][i] = 1;
		}

		//将最左面一列和最右面一列设置为1
		for (int i = 0;i < 8 ;i++ ) {
			map[i][0] = 1;
			map[i][6] = 1;
		}

		//将[3][1];[3][2]位置设为障碍物
		map[3][1] = 1;
		map[3][2] = 1;

		//输出当前地图情况
		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();
		}
	}
}

输出结果为:

下面就是给小球制定找路策略:

//创建一个类,使用递归回溯的思想来解决迷宫问题
class T {
	//1.创建findway方法找出迷宫路径
	//2.如果找到就返回true,否则返回false
	//3.i,j就是小球的位置,初始位置为(1,1)
	//4.因为要用递归的思想找路,所以要给map数组的各个位置赋予不同意义的不同值
	//  0表示可以走;1表示障碍物;2表示可以走;3表示走过,但是走不通
	//5.当map[6][5]=2,就说明找到通路,可以走,否则就继续找
	//6.确定小球的找路策略为:下->右->上->左

	public boolean findWay(int[][] map,int i,int j){
		if (map[6][5] == 2) {
			return true;
		}else{
			if (map[i][j] == 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,j-1)){
					return true;
				}else if(findWay(map,i-1,j)){
					return true;
				}else{
					map[i][j] = 3;
					return false;
				}
				
			}else{
				return false;
			}
		}
	}
}	

调用fingWay方法:


		T t1 = new T();
		t1.findWay(map,1,1);
		System.out.println("\n===找路的情况如下===");

		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 class MiGong{
	//编写main方法
	public static void main(String[] args) {
		//思路
		//1.先创建二位数组表示 int[] []map = new int[8][7]
		//2.先规定map数组的元素值:0表示可以走 1表示障碍物

		int [] [] map = new int [8][7];

		//将最上面的一行和最下面的一行,全部设置为1
		for (int i = 0;i < 7;i++ ) {
			map[0][i] = 1;
			map[7][i] = 1;
		}

		//将最左面一列和最右面一列设置为1
		for (int i = 0;i < 8 ;i++ ) {
			map[i][0] = 1;
			map[i][6] = 1;
		}

		//将[3][1];[3][2]位置设为障碍物
		map[3][1] = 1;
		map[3][2] = 1;

		//输出当前地图情况
		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();
		}

		T t1 = new T();
		t1.findWay(map,1,1);
		System.out.println("\n===找路的情况如下===");

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


//创建一个类,使用递归回溯的思想来解决迷宫问题
class T {
	//1.创建findway方法找出迷宫路径
	//2.如果找到就返回true,否则返回false
	//3.i,j就是小球的位置,初始位置为(1,1)
	//4.因为要用递归的思想找路,所以要给map数组的各个位置赋予不同意义的不同值
	//  0表示可以走;1表示障碍物;2表示可以走;3表示走过,但是走不通
	//5.当map[6][5]=2,就说明找到通路,可以走,否则就继续找
	//6.确定小球的找路策略为:下->右->上->左

	public boolean findWay(int[][] map,int i,int j){
		if (map[6][5] == 2) {
			return true;
		}else{
			if (map[i][j] == 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,j-1)){
					return true;
				}else if(findWay(map,i-1,j)){
					return true;
				}else{
					map[i][j] = 3;
					return false;
				}
				
			}else{
				return false;
			}
		}
	}
}	

以上就是递归调用的机制。可以多画几次内存图来理解透彻。

  • 18
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值