递归应用场景
看个实际应用场景,迷宫问题(回溯),递归(Recursion)
递归的概念
简单的说:递归就是方法自己调用自己,每次调用时传入不同的变量。递归有助于编程者解决复杂问题,同时可以让代码变得简洁。
递归的调用机制
1. 打印问题
/**
* 打印问题
* @param n
*/
public static void test(int n){
if (n > 2){
test(n - 1);
}
System.out.println("n=" + n);
}
测试
public static void main(String[] args) {
//通过打印问题,回顾递归调用机制
test(4);
2. 阶乘问题
/**
* 阶乘问题
*/
public static int factoriial(int n){
if (n == 1){
return 1;
}else {
return factoriial(n - 1)* n;
}
}
测试
public static void main(String[] args) {
//通过打印问题,回顾递归调用机制
//test(4);
//通过阶乘问题,回顾递归调用机制
int res = factoriial(2);
System.out.println("res=" + res);
完整代码
package com.recursion;
public class RecursionTest {
public static void main(String[] args) {
//通过打印问题,回顾递归调用机制
test(4);
//通过阶乘问题,回顾递归调用机制
int res = factoriial(2);
System.out.println("res=" + res);
}
/**
* 打印问题
* @param n
*/
public static void test(int n){
if (n > 2){
test(n - 1);
}
System.out.println("n=" + n);
}
/**
* 阶乘问题
*/
public static int factoriial(int n){
if (n == 1){
return 1;
}else {
return factoriial(n - 1)* n;
}
}
}
递归调用机制的讲解
递归能解决什么样的问题
- 各种数学问题:8皇后问题,汉诺塔,阶乘问题,迷宫问题,球和篮子问题
- 各种算法中也会用到递归,比如快排,归并排序,二分查找,分治算法等。‘
- 将用栈解决的问题——》递归代码比较简洁
递归需要遵守的重要规则
- 执行一个方法时,就创建一个新的受保护的独立空间(栈空间)
- 方法的局部变量是独立的,不会互相影响,比如n变量
- 如果方法中使用的是引用类型变量(比如数组),就回共享该引用类型的数据
- 递归必须向退出递归的条件逼近,否则就是无限递归,出现StackOverflowError,死递归了
- 当一个方法执行完毕,或者遇到return,就会返回,遵守谁调用,将结果返回给谁,同时当方法执行完毕或者返回时,该方法也就执行完毕。
递归——迷宫问题
创建一个迷宫 9 8
package com.recursion;
public class MiGong {
public static void main(String[] args) {
//创建一个迷宫
//地图
int[][] map = new int[8][7];
}
}
使用1表示墙 先把上下置为1
//使用1表示墙
//先把上下置为1
for (int i = 0; i < 7; i++) {
map[0][i] = 1;
map[7][i] = 1;
}
}
}
左右全部设置为1
//左右全部设置为1
for (int i = 0; i < 8; i++) {
map[i][0] = 1;
map[i][6] = 1;
设置挡板
//设置挡板 4 2 4 3
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.print(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.在走迷宫时,需要确定一个策略(方法)下——》右——》上——》左,如果该点走不通,再回溯
* @param map 表示地图
* @param i 从哪个位置开始找
* @param j 从哪个位置开始找
* @return 如果找到通路了就返回true,否则返回false
*/
public static boolean setWay(int[][] map, int i, int j){
}
}
使用递归回溯来给小球找路——代码
if (map[6][5] == 2){
//通路以找到
return true;
}else {
if (map[i][j] == 0){
//如果当前这个点还没有走过
//按策略走 下——》右——》上——》左
//假定该点可以走通
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 {
//如果map[i][j] != 0,可是1,2,3
return false;
}
}
使用递归回溯来给小球找路——测试
//使用递归回溯给小球找路
setWay(map,1,1);
//输出新的地图,小球走过的,并标识过的递归
System.out.println("小球走过的,并标识过的地图的情况");
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 7; j++) {
System.out.print(map[i][j]+" ");
}
System.out.println();
}
使用递归回溯来给小球找路——效果
使用递归回溯来给小球找路——修改找路的策略,先上——》右——》下——》左
/**
* //修改找路的策略,先上——》右——》下——》左
*/
public static boolean setWay2(int[][] map, int i, int j){
if (map[6][5] == 2){
//通路以找到
return true;
}else {
if (map[i][j] == 0){
//如果当前这个点还没有走过
//按策略走 上——》右——》下——》左
//假定该点可以走通
map[i][j] = 2;
if (setWay2(map,i-1,j)){
//向上走
return true;
}else if (setWay2(map,i,j+1)){
//向右走
return true;
}else if (setWay2(map,i+1,j)){
//向下走
return true;
}else if (setWay2(map,i,j-1)){
//向左走
return true;
}else {
//说明该点是走不通的,是死路
map[i][j]=3;
return false;
}
}else {
//如果map[i][j] != 0,可是1,2,3
return false;
}
}
}
使用递归回溯来给小球找路——测试
//使用递归回溯给小球找路
//setWay(map,1,1);
setWay2(map,1,1);
//输出新的地图,小球走过的,并标识过的递归
System.out.println("小球走过的,并标识过的地图的情况");
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 7; j++) {
System.out.print(map[i][j]+" ");
}
System.out.println();
}