递归


基本介绍

  • 简单的说:递归就是方法自己调用自己,每次调用时传入不同的变量.递归有助于编程者解决复杂的问题,同时可以让代码变得简洁。

递归调用机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.ysy.recursion;

public class RecursionTest {
public static void main(String[] args) {
test(5);
int result = factorial(5);
System.out.println("5! = " + result);
}

//打印问题
public static void test(int n){
if(n > 2){
test(n - 1);
}
System.out.println("n="+n);
}

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

调用规则

  1. 当程序执行到一个方法时,就会开辟一个独立的空间(栈)
  2. 每个空间的数据(局部变量),是独立的.

image-20220721202744711

递归能解决什么样的问题

  1. 各种数学问题如: 8皇后问题、汉诺塔、阶乘问题、迷宫问题、球和篮子的问题(google编程大赛)
  2. 各种算法中也会使用到递归,比如快排、归并排序、二分查找、分治算法等.
  3. 将用栈解决的问题–>第归代码比较简洁

递归需要遵守的重要规则

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

迷宫问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package com.ysy.recursion;

public class MiGong {
public static void main(String[] args) {
//创建一个二维数组,模拟迷宫
//地图
int[][] map = new int[8][7];
//使用1表示墙
//上下全部置为1
for(int i = 0; i < 7; i++){
map[0][i] = 1;
map[7][i] = 1;
}
//左右全部置为1
for(int i = 0; i < 8; i++){
map[i][0] = 1;
map[i][6] = 1;
}
//设置挡板,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.print(map[i][j] + " ");
}
System.out.println();
}

//使用递归回溯给小球找路
// 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();
}
}

//使用递归回溯来给小球找路
//说明
//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;
}
}
}
//更改策略
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;
}
}
}
}

八皇后问题(回溯算法)


文章作者: Yang Shiyu
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Yang Shiyu !
  目录