认识递归
简单的说: 递归就是方法自己调用自己,每次调用时传入不同的变量.递归有助于编程者解决复杂的问题,同时可以让代码变得简洁
public static int factorial(int n) {if (n == 1) {return 1;} else {return factorial(n - 1) * n;}}
递归的调用机制
为了说明这一点,以递归调用f(x1)→f(x2)→f(x3)为例,展示了执行步骤的顺序和堆栈布局
为了调用f(x2),会给f(x1)分配一个栈空间。同理,在f(x2)中也会为了调用f(x3)而分配另一个栈空间。最终在f(x3)中,程序到达基本情况,因此没有在f(x3)中进一步递归
递归调用规则:
1. 当程序执行到一个方法时,就会开辟一个独立的空间(栈)
2. 每个空间的数据(局部变量),是独立的
递归需要遵守的重要规则
- 执行一个方法时,就创建一个新的受保护的独立空间(栈空间)
- 方法的局部变量是独立的,不会相互影响, 比如n变量
- 如果方法中使用的是引用类型变量(比如数组),就会共享该引用类型的数据
- 递归必须向退出递归的条件逼近,否则就是无限递归,出现StackOverflowError)
- 当一个方法执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁,同时当方法执行完毕或者返回时,该方法也就执行完毕
简单来说:避免出现死循环
实际生产中,也是不能出现太大数据的循环的,影响速度
实际案例
迷宫问题

进行迷宫之前,我们需要对此作出一些说明,这样更方便代码的进行
说明
- map 表示地图
- 给出地图的数组表示,想起了学习稀疏数组的时候
- i,j 表示从地图的哪个位置开始出发 (1,1)
- 确定出发点,也是确定递归的开始
- 如果小球能到 map[6][5] 位置,则说明通路找到
- 确定终点,也是确定递归的结束点
- 约定: 当map[i][j] 为 0 表示该点没有走过 当为 1 表示墙 ; 2 表示通路可以走 ;3 表示该点已经走过,但是走不通
- 对于每个含义都要赋予特定的数值表示,不可遗漏
- 在走迷宫时,需要确定一个策略(方法) 下->右->上->左 , 如果该点走不通,再回溯
- 当然是要确定行走策略的,方便实现递归
思路清晰,代码上场
package com.xy.recursion;
public class MiGong {
public static void main(String[] args) {
//先把迷宫建立起来
//红色部分代表墙,用数字1表示,其余部分是暂时可走路径,用0表示
int MG[][] = new int[8][7];
for (int i = 0; i < 7; i++) {
MG[0][i] = 1;
MG[7][i] = 1;
}
for (int i = 0; i < 8; i++) {
MG[i][0] = 1;
MG[i][6] = 1;
}
MG[3][1] = 1;
MG[3][2] = 1;
System.out.println("迷宫模型展示~~");
for (int i = 0; i < 8; i++) {
for (int j = 0; j <7; j++) {
System.out.print(MG[i][j]);
System.out.print("\t");
}
System.out.println("\n");
}
setWay(MG, 1, 1);
System.out.println("迷宫模型路线展示~~");
for (int i = 0; i < 8; i++) {
for (int j = 0; j <7; j++) {
System.out.print(MG[i][j]);
System.out.print("\t");
}
System.out.println("\n");
}
//建立好迷宫模型以后,我们就要建立规则,这样才可以让程序本身有条理的,不出差错的按照我们的意愿走下去
//墙:1;未走过:0;走过:2;死路:3(回溯)
//行走规则: 下->右->上->左(你可以根据你的意愿填写规则)
//确定起点map[1][1]和终点map[6][5]
}
public static boolean setWay(int[][] map,int i,int j) {//给地图模型,起始位置
//给出递归结束的点,即终点
if (map[6][5] == 2) {//原始值为0,为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 {
return false;
}
}
}

public static boolean setWay(int[][] map,int i,int j) {//给地图模型,起始位置
//给出递归结束的点,即终点
if (map[6][5] == 2) {//原始值为0,为2代表走过,
return true;
}else {//没有到达终点,就要一直按照策略走下去,所以接下来是建立策略的,从而实现递归,而没走一步都需要检验是否已经到达终点,显然递归是容易实现这一点的
if (map[i][j] == 0) {
if (setWay(map, i+1, j)){
map[i][j] = 2;
return true;
}else if (setWay(map, i, j+1)) {
map[i][j] = 2;
return true;
}else if (setWay(map, i-1, j)) {
map[i][j] = 2;
return true;
}else if (setWay(map, i, j-1)) {
map[i][j] = 2;
return true;
}else {
map[i][j] = 3;
return false;
}
}else {
return false;
}
}
}
其原因是,每次判断if (map[i][j] == 0)后,下一步会进行循环,而我把赋值包含在其行走策略的代码中,导致每次都无法赋值,也就进入了死循环,出现错误
所以还是按照老师说的,提前假设可以走下一步,这样就可以提前赋值了

