Java数据结构与算法---递归(笔记六)

                                                             第六章 递归

6.1递归应用场景
迷宫问题(回溯),递归(Recursion)在这里插入图片描述
6.2递归的概念
简单说,递归就是自己调用自己,每次调用时传入不同的变量,递归有助于编程者解决复杂的问题,同时可以让代码变得简洁。
6.3递归的调用机制
1)当程序执行到一个方法时,就会开辟一个独立的空间(栈)。
2)每个空间的数据(局部变量),是独立的。
在这里插入图片描述
打印问题:

package com.atguigu.Recursion;

public class print {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		test(4);
	}
	public static void test(int n) {
		if(n>2) {
			test(n-1);
		}
		System.out.println("n="+ n);
	}

}

阶乘问题:

package com.atguigu.Recursion;

public class print {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int res = factorial(1);
		System.out.println(res);
	}
	public static int factorial(int n) {
		if(n==1) {
			return 1;
		}else {
			return factorial (n-1)*n;
		}
	}
}

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

6.5递归迷宫问题
代码实现:

package com.atguigu.Recursion;

public class MiGong {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//先用二维数组模拟构造一个地图
		int [][] map = new int[8][7];
		//将所有墙壁置为一
		for(int i=0;i<7;i++) {
			map[0][i] = 1;
			map[7][i] = 1;
		}
		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<8;i++) {
			for(int j=0;j<7;j++) {
				System.out.printf(map[i][j] +" ");
			}
			System.out.println();
		}
		
		setWay(map,1,1);
		//输出小球走过的地图
		System.out.println("小球走过的地图:");
		for(int i=0;i<8;i++) {
			for(int j=0;j<7;j++) {
				System.out.printf(map[i][j] +" ");
			}
			System.out.println();
		}
	}
	//使用递归回溯来给小球找路
	//1.map表示地图
	//2.i,j表示从地图的哪个位置开始出发(1,1)
	//3.如果小球能到map[6][5]位置,则说明通路找到
	//4.约定:当map[i][j]为0表示该点没有走过,当为1时表示墙,2表示通路可以走,3表示该点已经走过,但是走不通
	//5.在走迷宫时,需要确定一个策略(下->右->上->左)
	public static boolean setWay(int[][] map,int i,int j) {
		if(map[6][5]==2) {//表示该条路已经找到
			return true;
		}else {
			if(map[i][j]==0) {//如果当前点还没走过
				//将值置为2,假定该路可走
				map[i][j]=2;
				if(setWay(map,i+1,j)) {//向下走
					return true;
				}else if(setWay(map,i,j+1)) {//向右走
					return true;
				}else if(setWay(map,i-1,j)) {
					return true;
				}else if(setWay(map,i,j-1)){
					return true;
				}else {
					map[i][j]=3;
					return false;
				}
			}else {//如果当前点走过
				return false;
			}
		}
	}
}

效果:
在这里插入图片描述
6.6八皇后问题
6.6.1问题介绍:
八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8*8的国际象棋上摆放8个皇后,时期不能互相攻击,即:任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法(92)。

说明:
理论上应该创建一个二维数组来表示棋盘,但是实际上可以通过算法,用一个一维数组即可解决问题,arr[8]={0,4,7,5,2,6,1,3}//对于arr下标表示第几行,即第几个皇后,arr[i]=val,val表示第i+1个皇后,放在第i+1行的第val+1列。

6.6.2代码实现:

package com.atguigu.Recursion;

public class Queue8 {
	//定义一共有多少个皇后
	int max=8;
	//定义一个数组,保存皇后放置位置的结果,比如arr[8]={0,4,7,5,2,6,1,3}
	int [] array = new int[max];
	static int count=0;//定义静态变量统计方法个数
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Queue8 queue8 = new Queue8();
		queue8.check(0); 
		System.out.printf("一共有%d种解法",count);
	}
	//编写一个方法,放置第n个皇后
	private void check(int n) {
		if(n == max) {//到最后一个皇后
			print();
			return;
		} else {
			for (int i = 0; i < max; i++) {
				// 先把当前皇后n放到第1列
				array[n] = i;
				// 判断是否冲突
				if (judge(n)) {// 不冲突
					check(n + 1);
				}
			}
		}
	}
	//查看当我们放置第n个皇后后,是否与前面几个皇后冲突
	private boolean judge(int n) {
		for (int i = 0; i < n; i++) {
			//说明
			//1.array[i]==array[n] 表示判断第n个皇后是否和第i个皇后在同一列
			//2.Math.abs(n-i)==Math.abs(array[n]-array[i] 表示判断是否和第n个皇后在同一斜线
			if(array[i]==array[n] || Math.abs(n-i)==Math.abs(array[n]-array[i])) {
				return false;  
			}
		}
		return true;
	}
	//写一个方法,将皇后摆放位置输出
	private void print() {
		count++;
		for (int i = 0; i < array.length; i++) {
			System.out.printf(array[i] +" ");
		}
		System.out.println();
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值