首页 > 编程语言 >【Java复健指南03】递归思想

【Java复健指南03】递归思想

时间:2022-10-09 15:45:37浏览次数:50  
标签:复健 03 Java 递归 map int else return public

【递归】

递归重要规则

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

  1. 方法的局部变量是独立的,不会相互影响,比如n变量

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

  3. 递归必须向退出递归的条件逼近,否则就是无限递归,出现栈溢出(StackOverflowError)

  4. 当一个方法执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁,同时当方法执行完毕或者返回时,该方法也就执行完毕。

演示

public class Recursion01{
	public static void main(String[] agrs){
		T t1 = new T();
		t1.test(4);
		int res = t1.factorial(5);
		System.out.println("res="+res);
	}
}


class T {
	/*
	每次递归调用后会在栈中生成一个新的空间
	当条件不满足之后,从栈顶往下返回值,每次返回都会把方法体的代码(在这里是"打印n")都执行一遍
	所以最后的执行结果是
	n = 2
	n = 3
	n = 4
	*/
	public void test(int n){
		if(n > 2){
			test(n - 1);
		}
		System.out.println("n="+n);
	}

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

练习

习题一 给出对应位置的斐波那契数

请使用递归的方式求出斐波那契数1,1,2,3,5,8,13.….给你一个整数n,求出它的值是多少?

思路:

​ 1.当n=1斐波那契数是1
​ 2.当n=2斐波那契数是1
​ 3.当n>=3斐波那契数是前两个数的和
​ 4.这里就是一个递归的思想

public class RecursionExercise01{
	public static void main(String[] agrs){
		T t1 = new T();
		int n = 7;
		int res = t1.fibonacci(n);
		if(res ! = -1){
			System.out.println("n="+ n +" 对应的斐波那契数=" + res);
		}
	}
}

class T {
	public int fibonacci(int n){
        //若不满足条件,则这两个数肯定是1,直接返回即可
		if(n >= 1){
			if(n == 1 || n == 2){
				return 1;
			}else{//当n>=3斐波那契数是前两个数的和,思想有点类似阶乘问题
				return fibonacci(n-1) + fibonacci(n-2);
			}
		}else {
			System.out.println("输入的整数n需要大于等于1");
			return -1;
		}	
	}

}

习题二 逆推思想与递归(猴子吃桃问题)

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

思路 逆推
1. day = 10时有1个桃子
2. day = 9时有(day10 + 1)* 2 = 4
3. day = 8时有(day9 + 1)* 2 = 10
4. 规律就是,前一天的桃子=(后一天的桃子+1)*2
5. 递归

public class RecursionExercise01{
	public static void main(String[] agrs){
		T t1 = new T();
		// int n = 7;
		// int res = t1.fibonacci(n);
		// if(res != -1){
		// 	System.out.println("n="+ n +" 对应的斐波那契数=" + res);
		// }
		
		//桃子
		int day = 9;
		int peachNum = t1.peach(day);
		if(peachNum != -1){
			System.out.println("第"+day+"天有"+ peachNum +"个桃子");

		}
	}
}

class T {
	public int peach(int day){
		if(day == 10){//第10天只有1个桃子
			return 1;
		}else if(day >= 1 && day <= 9){//规律要自己寻找
			return(peach(day + 1)+1) * 2;
		}else {
			System.out.println("day的范围是1~10");
			return -1;
		}
	}

}

习题三 递归与回溯机制(老鼠走迷宫)

老鼠走迷宫

有一个迷宫(即一个正方形二维数组map[] []),其中使用1代表边界障碍

右下角为迷宫出口(假设为map[6] [5])

找出走到出口的路线

解法

public class MiGong{
	public static void main(String[] agrs){
		//思路
		//1.先创建迷宫,用二维数组表示 
		//2.先规定map数组的元素值:0表示可以走1表示障碍物
		int[][] map = new int[8][7];
		//3.将最上面的一行和最下面的一行,全部设置为1
		for(int i = 0; i< 7; i++){
			map[0][i]= 1;
			map[7][i]= 1;
		}
		//4.将最右面的一列和最左面的一列全部置为1
		for(int i = 0; i< 7; i++){
			map[i][0]= 1;
			map[i][6]= 1;
		}
		//单独设置障碍物
		map[3][1] = 1;
		map[3][2] = 1;
		//测试回溯机制
		map[2][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);//初始位置1,1
		// t1.findWay2(map, 1, 1);//初始位置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. 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){
		//关键点1:递归退出条件
		if(map[6][5] == 2){//说明找到出路
			return true;
		}else {

			if(map[i][j] == 0){//当前这个位置0,说明可以走
				//那么可以给当前位置一个假定值2(假设可以走通)
				map[i][j] = 2;
				//关键点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 {
					//所有方向都走不通那说明最开始的假设是错的
					//那么把当前位置赋值为3并返回false
					map[i][j] = 3;
					return false;
					
				}

			}else {//不为0就只有三种情况,1,2,3
				return false;
			}
		}
	}


	//改变寻路策略,下右上左->上右下左
	public boolean findWay2(int[][] map, int i, int j){
		//关键点1:递归退出条件
		if(map[6][5] == 2){//说明找到出路
			return true;
		}else {

			if(map[i][j] == 0){//当前这个位置0,说明可以走
				//那么可以给当前位置一个假定值2(假设可以走通)
				map[i][j] = 2;
				//关键点2:寻路策略
				//然后根据找路策略来确定该位置是否真的可以走通
				//下->右->上->左
				if(findWay2(map, i - 1, j)){//上
					return true;
				}else if(findWay2(map, i, j + 1)){//右
					return true;
				}else if (findWay2(map, i + 1, j)) {//上
					return true;
				}else if (findWay2(map, i, j - 1)) {//左
					return true;
				}else {
					//所有方向都走不通那说明最开始的假设是错的
					//那么把当前位置赋值为3并返回false
					map[i][j] = 3;
					return false;
					
				}

			}else {//不为0就只有三种情况,1,2,3
				return false;
			}
		}
	}

}

注意点:
所谓的“回溯机制”,就是递归条件达成之后,栈从最顶端往后返回值的过程实现的

在这个问题中体现为,如果“老鼠”走出下一步之后,判定上下左右均不可走,那么会把当前位置标注为3,即不可走

然后会回到上一步的位置,接着判断下一个位置是否能走(因为上一个位置只是选中了一个可以走的方向,其他的还没有判断)

习题四 汉诺塔

汉诺塔问题

image-20221009151909313

即有三个柱子,第一个柱子上有一些从大到小往上摞的圆盘

现在需要将这些圆盘全部移动到最右边的柱子上,过程中要求大圆盘不能在小圆盘之上

思路

实际上我们可以把问题简化成最基本的两种情况:
①若只有一个块需要移动,那么只需要将其从a移动到c即可
②若有两个块需要移动,那么需要先将最上面的块移动到b,用b作为过渡存放最上面的块,
然后将最下面的块移动到c并将b的块也移动至c即可

然后无论是之后需要移动多少个块,我们都可以将其简化为上述两种基本类型
使用递归的方法,对移动个数每次减一,不断开辟新的栈,直到将其简化为基本类型
完成基本类型的计算后再不断的返回值到下一个栈即可实现目标

public class HanoiTower{
	public static void main(String[] agrs){
		Tower tower = new Tower();
		tower.move(2, 'A', 'B', 'C');
	}
}

class Tower{
	//方法
	//num 表示要移动的个数,a, b, c 分别表示A塔、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);
		}
	}
}

注意点:我们只是给出移动的步骤,而无需考虑盘子本身

标签:复健,03,Java,递归,map,int,else,return,public
From: https://www.cnblogs.com/DAYceng/p/16772381.html

相关文章

  • java序列化
    一、序列化与反序列化序列化:指堆内存中的java对象数据,通过某种方式把对存储到磁盘文件中,或者传递给其他网络节点(网络传输)。这个过程称为序列化,通常是指将数据结构或对象转......
  • 003Java的诞生
    003Java的诞生1、计算机语言发展史(1)第一代语言机器语言我们都知道计算机的基本计算方式都是基于二进制的方式。二进制:010111001010110010110100这种代码是直接输......
  • Java虚拟机详解(五)------JVM参数
    JVM参数有很多,其实我们直接使用默认的JVM参数,不去修改都可以满足大多数情况。但是如果你想在有限的硬件资源下,部署的系统达到最大的运行效率,那么进行相关的JVM参数设置是必......
  • 【Java复健指南01】简介与数组
    写在最前学习Java已经是很久之前的事情了,因为技术栈的转变,很久没有使用Java正经地开发过项目。对于该语言的理解也是停留在表面,因此萌生了重新学习的念头。一方面是为刷......
  • Java实现多线程
    Java实现多线程的方式有4种分别是继承Thread类,实现Runnable,Callable接口和通过线程池提交线程任务。其中实现Callable接口的方式可以获取返回值。1.继承Thread类通过继......
  • 浏览器中javascript简易实现json数据保存到客户端
    思路很简单,就是利用Blob、URL.createObjectURL()方法和<a>便签的HTML5新属性download来模拟远端文件下载保存。下面直接上代码savePath:function(){varme......
  • JavaScript异步概念及与c#异步的区别
    JS的异步操作函数往往是通过回调函数来实现异步任务的结果处理,在ES6之前如setTimeout函数和异步AJAX编程;在ES6规范后Promise类对象使得书写异步任务更加容易,返回Promise......
  • java---了解以下运算符
    了解即可1&2用于条件判断,&条件1和2都执行1&&2,条件1判断错误的情况下,条件2不执行&当运算符的化,例如4&7,两者上下对比都是1则为1,反之为0,结果就是二进制100也就是......
  • 如果你也面试03-全缓冲 行缓冲 无缓冲
    首先介绍一下UNIX里面关于标准IO的几种缓冲机制:1、全缓冲。全缓冲指的是系统在填满标准IO缓冲区之后才进行实际的IO操作;注意,对于驻留在磁盘上的文件来说通常是由标准IO库......
  • JAVA中计算两个日期时间的差值竟然也有这么多门道
    JAVA中计算两个日期时间的差值竟然也有这么多门道上半年春招的时候,作为面试官,对于面试表现的不错的同学会要求其写一小段代码看看。题目很简单:给定一个日期,然后计算下......