5、递归
- 简单的说: 递归就是方法自己调用自己,每次调用时传入不同的变量,递归有助于编程者解决复杂的问,同时可以让代码变得简洁。
public class RecursionTest {
public static void main(String[] args) {
//通过打印问题,回顾递归调用机制
//test(4);
int res = factorial(3);
System.out.println("res=" + res);
}
//打印问题
public static void test(int n) {
if (n > 2) {
test(n - 1);
} //else {
System.out.println("n=" + n);
// }
}
//阶乘问题
public static int factorial(int n) {
if (n == 1) {
return 1;
} else {
return factorial(n - 1) * n; // 1 * 2 * 3
}
}
}
- 递归需要遵守的重要规则:
- 执行一个方法时,就创建一个新的受保护的独立空间(栈空间);
- 方法的局部变量是独立的,不会相互影响, 比如n 变量;
- 如果方法中使用的是引用类型变量(比如数组),就会共享该引用类型的数据;
- 递归必须向退出递归的条件逼近,否则就是无限递归,出现StackOverflowError;
- 当一个方法执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁,同时当方法执行完毕或者返回时,该方法也就执行完毕。
迷宫问题:
//迷宫问题,求初始点到终点的一条通路(不一定是最小通路!)
//墙体设为1,路径设为0
/*
整体思路:
1、每当我们经过一个点,将点标记为2,代表已走过;
2、对于该点,我们依照下右上左的方向向后查找;
3、如果该点所有路径都走不通,就返回false,回到上一个点处向后查找;
4、当到达终点,即终点标记为2时,一层一层向上推出递归。
递归思路:
1、终止条件:终点处被遍历到或者已遍历完所有可遍历点;
2、每层递归该做的事:判断该点是否是终点,标记该点已走过,下右上左策略判断是否可走;
3、返回参数:返回该点四个方向是否有可到终点的通路。
*/
public class MiGong {
static int m = 3, n = 3;//终点位置
public static void main(String[] args) {
int[][] map = new int[6][6];//迷宫初始化
int i = 1, j = 0;//起点位置
//设置墙体
map[1][2] = 1;
map[0][2] = 1;
map[4][4] = 1;
map[5][1] = 1;
System.out.println(findWay(map, i, j));
for (int i1 = 0; i1 < map.length; i1++) {
for (int i2 = 0; i2 < map[0].length; i2++) {
System.out.print(map[i1][i2] + " ");
}
System.out.println();
}
}
private static boolean findWay(int[][] map, int i, int j) {
//当到达(6,5)时,表示已经找到通路
if (map[m][n] == 2) {
return true;
}
if (map[i][j] == 0) {
map[i][j] = 2;
if (i + 1 < map.length && findWay(map, i + 1, j)) {
return true;
} else if (j + 1 < map[0].length && findWay(map, i, j + 1)) {
return true;
} else if (i - 1 >= 0 && findWay(map, i - 1, j)) {
return true;
} else if (j - 1 >= 0 && findWay(map, i, j - 1)) {
return true;
} else {
return false;
}
} else {
map[i][j] = 0;//走不通后标记回0;
return false;
}
}
}
八皇后问题
二维数组解法:
/*
1、递归结束条件:当遍历完所有(即遍历完从第一行第八列开始的所有可能)自动结束
2、每层递归流程:首先判断这一行是否为第八行,如果是,直接输出并返回,如果不是,在这一行寻找可以放置皇后的位置
*/
public class EightEmpress {
static int k=1;
public static void main(String[] args) {
int[][] board = new int[8][8];//初始化棋盘
int num = 0;
findWay(board, num);
}
private static void findWay(int[][] board, int num) {
//已摆放完毕
if (num >= 8) {
System.out.println("摆放方法"+k+":");
k++;
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
System.out.print(board[i][j]+" ");
}
System.out.println();
}
return;
}else{
for (int i = 0; i < 8; i++) {
if(placeAble(board,num,i)){
board[num][i]=1;
findWay(board,num+1);
board[num][i]=0;
}
}
}
}
//判断是否可以放置棋子
private static boolean placeAble(int[][] board,int x, int y) {
for (int i = 0; i < x; i++) {
//纵向是否存在棋子
if(board[i][y]==1){
return false;
}
/*
斜向是否存在棋子
斜向表示:要么与该点和相等(左上->右下),要么与该点差相等(右上->左下)
即:i+j==x+y||i-j==x-y j=x+y-i||j=y-x+i
*/
if((x+y-i>=0&&x+y-i<8&&board[i][x+y-i]==1)||(y-x+i>=0&&y-x+i<8&&board[i][y-x+i]==1)){
return false;
}
}
return true;
}
}
一维数组解法:
//用一维数组解决八皇后问题
/*
思路分析:用数组小标来表示行号,用数组的值表示列数
*/
public class EightEmpress2 {
static int num = 1;
public static void main(String[] args) {
int[] col = new int[8];//初始化棋盘
int row = 0;
findWay(col, row);
}
private static void findWay(int[] col, int row) {
if (row >= 8) {
System.out.println("方法" + num + ":");
num++;
print(col);
return;
} else {
for (int i = 0; i < 8; i++) {
if (check(col, row, i)) {
col[row] = i;
findWay(col, row + 1);
/*
注意,这儿与二维数组不同,不需要让col[row]=0,
因为向后遍历赋值后col[row]会改变不需要
当然,你加上去也不会使结果受到影响
*/
}
}
}
}
//判断是否可以放置
private static boolean check(int[] col, int row, int column) {
for (int i = 0; i < row; i++) {
if (row + column == i + col[i] || row - column == i - col[i] || col[i] == column) {
return false;
}
}
return true;
}
//输出
private static void print(int[] col) {
for (int i = 0; i < col.length; i++) {
for (int i1 = 0; i1 < col.length; i1++) {
if (i1 + 1 == col[i]) {
System.out.print(1 + " ");
} else {
System.out.print(0 + " ");
}
}
System.out.println();
}
}
}