递归调用
从jvm(虚拟机)入手, 方法栈的存在使得最后调用的方法, 最先执行.
递归能解决什么样的问题
1)求结果的数学问题
如: 8个皇后问题\ 汉诺塔问题\ 阶乘问题\ 迷宫问题\ 球和篮子问题
2)查找或者排序的算法问题
如: 快排\ 归并排序\ 二分查找\ 分治算法
3)将用栈解决的问题->递归代码比较简洁
递归的底层
1)执行一个方法时, 就创建一个新的受保护的独立空间(栈)
2)方法的局部变量是不会相互影响的
但是, 方法中使用的是引用类型的变量(如:数组)就会共享(这其实和变量在jvm中的位置有关)
3)递归必须向退出递归的条件逼近
4)当方法执行完毕或者遇到return时, 就会返回, 遵循谁调用就返回给谁, 方法也就结束.
递归解决迷宫问题(小球找路问题)
假设一个这样的迷宫(地图) 七行八列
1 1 1 1 1 1 1 1
1 0 0 0 0 0 0 1
1 0 0 0 0 0 0 1
1 1 1 0 0 0 0 1
1 0 0 0 0 0 0 1
1 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1
出口就是map[5][6]的位置
入口就是map[1][1]的位置
思路: 约定0表示该点没有走过, 1表示墙, 2表示通路可以走, 3表示该点已经走过, 但是走不通
根据迷宫问题确定方向的优先级, 也就是走的策略
这里我们确定为 下>右>上>左
public class Migong {
public static void main(String[] args) {
int[][] map = new int[7][8];
//设置围墙
for (int i = 0; i < 7; i++){
map[i][0] = 1;
map[i][7] = 1;
}
for (int i = 0; i < 8; i++){
map[0][i] = 1;
map[6][i] = 1;
}
//设置挡板
map[3][1] = 1;
map[3][2] = 1;
//查看初始地图
for (int row = 0; row < map.length; row++){
for (int col = 0; col < map[0].length; col++){
System.out.print(map[row][col]+" ");
}
System.out.println();
}
if (canFindway(map, 1, 1)){
System.out.println("能找到出口");
for (int row = 0; row < map.length; row++){
for (int col = 0; col < map[0].length; col++){
System.out.print(map[row][col]+" ");
}
System.out.println();
}
}else{
System.out.println("没有出口");
}
}
//判断能否找到路径
public static boolean canFindway(int[][] map, int i, int j){
//先判断是不是已经走到了终点
if (map[5][6] == 2){
return true;
}else if(map[i][j] == 0){
//说明该点能走
map[i][j] = 2;
if (canFindway(map, i+1, j)){
return true;
}else if (canFindway(map, i, j+1)){
return true;
}else if (canFindway(map, i-1, j)){
return true;
}else if (canFindway(map, i, j-1)){
return true;
}else{
map[i][j] = 3;
return false;
}
}else{
return false;
}
}
}
解决八个皇后问题
回溯法: 也就是循环中配合递归
首先说明一下我们这里是使用一维数组来表示摆放的结果
索引表示第几个皇后, 也就是第几行, 值就是表示在第几列
public class Q8 {
int max = 8; //确定有几个皇后
int[] jieguo = new int[max]; //创建存放结果的容器
static int count = 0; //创建结果种类计数器
public static void main(String[] args) {
Q8 q = new Q8();
q.huisu(0);
System.out.printf("一共有%d种结果", count);
}
//创建一个回溯方法, 打印结果
public void huisu(int n){
if (n == max){
//因为有max个皇后, 到max-1所有皇后都摆放上去了
dayin();
return;
}
for (int col = 0; col < max; col++){
jieguo[n] = col; //每一个皇后, 也就是每一行, 所有的col都试一试
if (!isChongtu(n)){
huisu(n+1);
}
}
}
//创建一个判断当前皇后和之前放置的皇后是否有冲突的方法
public boolean isChongtu(int n){
for (int i = 0; i < n; i++){
//如果是第一个皇后, 也就是n=0; 都不会进循环, 也就是都不用判断了
if (jieguo[i] == jieguo[n] || Math.abs(n-i) == Math.abs(jieguo[n]-jieguo[i])){
return true;
}
}
return false;
}
//创建一个打印结果的方法
public void dayin(){
count++;
for (int i = 0; i < jieguo.length; i++){
System.out.print(jieguo[i]+" ");
}
System.out.println();
}
}