5.递归
作者:互联网
1、概念
递归就是方法自己调用自己,每次调用时传入不同的变量.递归有助于编程者解决复杂的问题,同时可以让代码变得简洁。并且递归用到了虚拟机栈
2、能解决的问题
数学问题
- 八皇后问题
- 汉诺塔
- 求阶乘
- 迷宫问题
- 球和篮子
各种排序算法
3、规则
-
方法的变量是独立的,不会相互影响的
-
如果方法中使用的是引用类型变量(比如数组),就会共享该引用类型的数据
-
递归必须向退出递归的条件逼近,否则就是无限递归,出现 StackOverflowError
-
当一个方法执行完毕,或者遇到 return,就会返回,遵守谁调用,就将结果返回给谁,同时当方法执行完毕或
者返回时,该方法也就执行完毕
4、迷宫问题
思路
- 用一个二维矩阵代表地图
- 1代表边界
- 0代表未做过该地点
- 2代表走过且能走得通
- 3代表走过但走不通
- 设置起点和终点以及每个地点的行走策略
- 行走策略指在该点所走的方向的顺序,如 右->下->左->上(调用寻找路径的方法,使用递归)
- 每次行走时假设该点能够走通,然后按照策略去判断,如果所有策略判断后都走不通,则该点走不通
图解
初始地图
行走路径
策略:右下左上
代码
public class Demo2 {
public static void main(String[] args) {
//得到地图
int length = 7;
int width = 6;
int[][] map = getMap(length, width);
//设置一些障碍
map[1][2] = 1;
map[2][2] = 1;
//打印地图
System.out.println("地图如下");
for(int i=0; i<length; i++) {
for(int j=0; j<width; j++) {
System.out.print(map[i][j]+" ");
}
System.out.println();
}
//走迷宫
getWay(map, 1, 1);
//行走路径
System.out.println("行走路径");
for(int i=0; i<length; i++) {
for(int j=0; j<width; j++) {
System.out.print(map[i][j]+" ");
}
System.out.println();
}
}
/**
* 创建地图
* @param length 地图的长
* @param width 地图的宽
* @return 创建好的地图
*/
public static int[][] getMap(int length, int width) {
int[][] map = new int[length][width];
//先将第一行和最后一行设置为1(边界)
for(int i=0; i<width; i++) {
map[0][i] = 1;
map[length-1][i] = 1;
}
//再将第一列和最后一列设置为1
for(int i=0; i<length; i++) {
map[i][0] = 1;
map[i][width-1] = 1;
}
return map;
}
/**
* 开始走迷宫
* @param map 地图
* @param i 起点横坐标
* @param j 七点纵坐标
* @return 能否走通,true能走通,false反之
*/
public static boolean getWay(int[][] map, int i, int j) {
int length= map.length;
int width = map[0].length;
//假设右下角为终点
if(map[length-2][width-2] == 2) {
//走通了,返回true
return true;
} else {
if(map[i][j] == 0) {
//假设改路能走通
map[i][j] = 2;
//行走策略 右->下->左->上
if(getWay(map, i, j+1)) {
return true;
}else if(getWay(map, i+1, j)) {
return true;
}else if(getWay(map, i-1, j)) {
return true;
}else if(getWay(map, i, j-1)) {
return true;
}
//右下左上都走不通
map[i][j] = 3;
}else {
//改路已经被标记过了,不用再走了,直接返回false
return false;
}
}
return false;
}
}Copy
运行结果
地图如下
1 1 1 1 1 1
1 0 1 0 0 1
1 0 1 0 0 1
1 0 0 0 0 1
1 0 0 0 0 1
1 0 0 0 0 1
1 1 1 1 1 1
行走路径
1 1 1 1 1 1
1 2 1 0 0 1
1 2 1 0 0 1
1 2 2 2 2 1
1 0 0 0 2 1
1 0 0 0 2 1
1 1 1 1 1 1Copy
5、八皇后问题
八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在 8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即:任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法(92)。
思路
-
将第一个皇后放在第一行第一列
-
将第二个皇后放在第二行第一列,判断是否会和其他皇后相互攻击,若会相互攻击,则将其放到第三列、第四列…知道不会相互攻击为止
-
将第三个皇后放在第三行第一列,判断是否会和其他皇后相互攻击,若会相互攻击,则将其放到第三列、第四列…知道不会相互攻击为止,并以此类推,在摆放的过程中,有可能会改动前面所放的皇后的位置
-
当得到一个正确的解时,就会回溯到上一行,由此来找出第一个皇后在第一行第一列的所有解
-
再将第一个皇后放到第一行第二列,并重复以上四个步骤
-
注意:
- 棋盘本身应该是用二维数组表示,但是因为皇后所在的行数是固定的,所以可以简化为用一个一维数组来表示。其中的值代表皇后所在的列
- 数组下标代表皇后所在行数,所以判断是否在同一行列斜线上时,只需要判断是否在同一列和同一斜线上即可
- 是否同列判断:值是否相同
- 是否同一斜线:行号-行号是否等于列号-列号,且列号相减要取绝对值
代码
public class Demo3 {
/**
* 创建皇后所放位置的数组,数组的下标代表行号,数组中的值代表所在的列号
*/
static int sum = 0;
int max = 8;
int[] arr = new int[max];
public static void main(String[] args) {
Demo3 demo = new Demo3();
//放入第一个皇后,开始求后面的皇后
demo.check(0);
System.out.println("一共有"+sum+"种放法");
}
/**
* 打印数组元素
*/
public void print() {
for(int i = 0; i<arr.length; i++) {
System.out.print(arr[i] + " ");
}
sum++;
System.out.println();
}
/**
* 判断该位置的皇后与前面几个是否冲突
* @param position 需要判断的皇后的位置
* @return true代表冲突,false代表不冲突
*/
public boolean judge(int position) {
for(int i = 0; i<position; i++) {
//如果两个皇后在同一列或者同一斜线,就冲突
//因为数组下标代表行数,所以不会存在皇后在同一行
//所在行数-所在行数 如果等于 所在列数-所在列数,则两个皇后在同一斜线上
if(arr[i] == arr[position] || (position-i) == Math.abs(arr[position]-arr[i])) {
return true;
}
}
return false;
}
/**
* 检查该皇后应放的位置
* @param queen 要检查的皇后
*/
public void check(int queen) {
if(queen == max) {
//所有的皇后都放好了,打印并返回
print();
return;
}
//把皇后放在每一列上,看哪些不会和之前的冲突
for(int i = 0; i<max; i++) {
//把第queen+1个皇后放在第i列
arr[queen] = i;
if(!judge(queen)) {
//不冲突,就去放下一个皇后
check(queen+1);
}
}
}
}Copy
一共有92种放法,就不一一展示了
标签:map,return,递归,int,数组,皇后 来源: https://www.cnblogs.com/55zjc/p/15972147.html