方法递归(recursion)调用

方法自己调用自己,每次调用的时候传入不同的变量(有助于解决复杂问题,让代码简洁)

重要规则:

1.执行一个方法的时候就会创建一个新的受保护的空间(栈空间)

2.方法的局部变量独立,不会相互影响

3.如果方法中使用的是引用数据类型(数组,对象),就会共享该引用类型的数据

【如果是引用数据类型,方法中传入的形参就是地址,这些形参都可以通过这个地址影响堆里面的同一个空间】

4.递归必须向退出递归的条件逼近,否则无限递归【StackOverFlowError,栈溢出】

5.一个方法执行完毕或者遇到return,就会返回(谁调用就将结果返回给谁),方法执行完毕或者遇到return,该方法就结束

 每次需要递归的时候都会出现一个新栈,新栈执行完之后才执行旧栈(所以最先输出的结果就是最最新的栈的结果,以此类推)

假设改一下方法体:

 改完之后结果只会出现一个n=2

why?(最外层【第一层】方法执行的时候满足n>2,所以执行递归(不执行else里面的输出语句),第二层递归的时候也满足n>2,所以执行第三层递归......以此类推,一直执行递归,直到出现n=2不满足n>2的情况,这时候就执行else里面的输出语句,输出n=2,因为前面几层递归都是执行下一层递归,所以不会出现n=3、4、5、6.。。。的情况)

阶乘

//阶乘(factorical)
	public int factorical(int n){
		if(n == 1){
			return 1;
		}else{
			return factorical(n - 1)*n;
		}
	}

 从最顶层的栈得到的确定值依次往下,5*4*3*2*1 = 120

练习:

①斐波那契数(后一个数字是前两个数字之和)

class t{
	public int feibo(int n){
		if(n==1 || n ==2){
			return 1
		}else{
			return feibo(n-1)+feibo(n-2);
		}
	}
}

可以稍微改进(做一个数据保护)

class t{
	public int feibo(int n){
		if(n>0){
			if(n==1 || n ==2){
				return 1;
			}else{
				return feibo(n-1)+feibo(n-2);
			}
		}else{
			System.out.println("请输入一个大于0的数字");
			return -1;
		}
	}
}

猴子吃桃子问题:有一堆桃子,猴子第一天吃了其中的一半,并再多吃了一个! 以后每天猴子都吃其中的一半,然后再多吃一个。当到第 10 天时, 想再吃时(即还没吃),发现只有 1 个桃子了。问题:最初共多少个桃子?

(规律:前一天的桃子数量=后一天桃子数量+1再*2)

//猴子吃桃
	public int tao(int day){//day表示倒数第几天
		if(day==1){
			return 1;
		}else{
			return (tao(day-1)+1)*2;
		}
	}

法二:

public int tao2(int day){//day表示正数第几天
		if(day == 10){
			return 1;
		}else if(day >=1 && day <= 9){
			return (tao2(day + 1)+1)*2;
		}else{
			return -1;
		}
	}

 结果都是1534,两种方法都没问题(重要的是找规律)

迷宫问题(小球从左上角走到右上角,躲避障碍物)

public class migong{
	public static void main(String[] args) {
		//用二维数组表示迷宫
		//元素值0可以走,1表示障碍物
		int[][] map = new int[8][7];//8行7列的迷宫

		//将最上面最下面两行都设为1(表示不能走)
		for(int i = 0;i<7;i++){
			map[0][i] = 1;
			map[7][i] = 1;
		}
		
		//左右两列设为1(每列有8行,所以i<8)
		for(int i = 0;i<8;i++){
			map[i][0] = 1;
			map[i][6] = 1;
		}
		//单独设置两个障碍物
		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();
		}

		//使用findway找路
		t t1 = new t();
		t1.findway(map,1,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{

	//递归思想求解
	
	//findway这个方法用来找迷宫路径
	//找到返回true,找不到返回false
	//map是二维数组,表示迷宫
	//i,j表示位置,初始位置是(1,1)
	//规定数组值的含义,元素值0可以走,1表示障碍物,2可以走,3走过但是走不通
	//当map[6][5] = 2,说明找到路了,否则继续找
	//确定找路的策略,下->右->上->左
	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 - 1,j)){//走上
					return true;
				}else if(findway(map,i,j - 1)){//走左
					return true;
				}else{
					map[i][j] = 3;//,假定能走通,其实走不通,所以就赋值为3
					return false;
				}

			}else{
				return false;
			}
		}
	}
}

(结果里面2就是小球的路径) 

findway方法里面,当我们把数组,i,j传进来之后,数组里的元素除了外围一周和内两个也定的元素是1之外其他都是0,这时候map[6][5]是不等于2的,这时候就进入到下面的else,我们调用方法传入的i和j都是1,这时候map[1][1] = 0成立,进入if语句,我们先假设可以走通,先把当前位置改为2,然后我们让他往下走(这个所谓的往下走其实就是运用递归重新调用一下自己这个方法,只不过把传进去的参数改成起始位置往下的一个元素),然后在看这个元素满足if-else里面的那个条件,往下走不了就往右.....以此类推,直到终点位置变成2或者返回false(走不通)

为啥调用两个不同的方法输出是一样的结果?

 先调用哪个方法,下面的就跟着上面的一样?

原因:调用findway2的时候,传入的map时已经被第一次调用findway

的时候改过的地图,改过的地图map[6][5]==2,所以直接执行if语句,else里面的内容就不执行了

测试回溯现象

 

回溯:比如把起始位置右下角挡起来,小球按照下右上左的顺序走到起始位置下面的时候,发现再按照下下右上左的顺序走是走不通的,这时候这个位置就会变成3,这时候就会返回到起始位置,回到起始位置之后会发现起始位置下面走不通,所以就会向右走 【在某一个位置四个方向都走不通的时候就会回到上一个栈,根据刚才已经走得方向的下一个方向进行探测】

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值