场景以及概念
迷宫回溯问题
简单的说:递归就是方法自己调用自己,每次调用时传入不同的变量.递归有助于编程者解决复杂的问题,同时可以让代码变得简洁。
调用机制
1.打印问题
package com.wang.Recursion;
/**
* @author 王庆华
* @version 1.0
* @date 2020/12/20 9:30
* @Description TODO
* @pojectname 递归代码
*/
public class RecursionTest {
public static void main(String[] args) {
test(4);
}
/**
* 根据n的数字大小,打印n到2
* @param n
*/
public static void test(int n){
if (n>2){
test(n-1);
}
System.out.println("n="+n);
}
}
结果
n=2
n=3
n=4
递归调用规则
1.当程序执行到方法时,就会开辟一个独立的空间(栈)
结合我们的图示,也能发现先是打印2,然后是3,然后是4
如果我们的方法修改成了这样
public static void test(int n){
if (n>2){
test(n-1);
}else {
System.out.println("n=" + n);
}
}
结果就只有n=2输出,因为大于2的他都不会进入else输出
2.阶乘问题
/**
* 阶乘问题
* @param n
* @return
*/
public static int factorial(int n){
if (n == 1){
return 1;
}else {
return factorial(n-1) * n;
}
}
举例说明
n=2 return 1*2 = 2
n=3 return factorial(2)*3 = return factorial(1)*2*3 = return 1*2*3
递归能解决什么问题
设计到这些比较有难度的算法我准备在另外的博客进行解答
递归要遵守的规则
迷宫问题
思路分析:
直接放进了代码中
package com.wang.Recursion;
/**
* @author 王庆华
* @version 1.0
* @date 2020/12/20 10:10
* @Description TODO
* @pojectname 迷宫问题
*/
public class MiGong {
public static void main(String[] args) {
//创建二维数组,模拟迷宫
int[][] map = new int[8][7];
//上下全部置为墙体
for (int i=0;i<7;i++){
map[0][i] = 1;
map[7][i] = 1;
}
//左右两列置为墙体
for (int i = 0; i <8 ; i++) {
map[i][0] = 1;
map[i][6] = 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]+"\t");
}
System.out.println();
}
//给小球找路
setWay(map,1,1);
//输出新地图,小球走过的用2表示
System.out.println("小球走过,我们的通路是");
for (int i = 0; i < 8 ; i++) {
for (int j = 0; j <7 ; j++) {
System.out.print(map[i][j]+"\t");
}
System.out.println();
}
}
/**
//使用递归给小球找路
map表示地图
i,j表示所处的位置
如果小球能到map[6][5]则说明通路找到
约定: 当地图i,j为0时,表示该点没有走过
当为1时,不能走
当是2时,表示我们走过的通路
当是3时,表示走过,但是走不通
走之前我们制定的策略:
先走下面==下面走不通走右面
右面再走不通走上面,再走不通再走左面
再走不通,回溯
* @param map 给我地图
* @param i 从哪个位置开始找
* @param j
* @return
*/
public static boolean setWay(int[][] map,int i,int j){
if (map[6][5] == 2){//通路找到
return true;
}else {
//如果当前这个点还没走过
if (map[i][j] == 0){
//按照我们的策略走下一步下--右--上--左
//先把现在这个点置为2,假定现在这点是能走通的
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;
}
}
}
}
结果
地图效果
1 1 1 1 1 1 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 1 1 1 1
小球走过,我们的通路是
1 1 1 1 1 1 1
1 2 0 0 0 0 1
1 2 2 2 0 0 1
1 1 1 2 0 0 1
1 0 0 2 0 0 1
1 0 0 2 0 0 1
1 0 0 2 2 2 1
1 1 1 1 1 1 1
我来文字描述下
首先1,1位置开始,现在6,5位置是2么?显然不是,那我们就先将1,1置为2,假定的,根据策略我们先向下走调用setWay(map,i+1,j),,再次回到方法,到了(2,1)位置,现在(6,5)是2么?不是,那我继续回调自己,到了(3,1)位置,我草,(3,1)是墙,那我就得换路了,我去向右走,诶能走通,就这样一直来回调用,就找到了我们的终点通路
那么有人会说,你这没有回溯思想啊!!那是因为我们的中间墙体太少了,太简单了,他能直接一次走通,那我设置的难一点,多增加一些墙体
//设置我们的挡板
map[3][1] = 1;
map[3][2] = 1;
map[1][2] = 1;
map[2][2] = 1;
运行后发现
小球走过,我们的通路是
1 1 1 1 1 1 1
1 3 1 0 0 0 1
1 3 1 0 0 0 1
1 1 1 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 1 1 1 1
出现两个3,就说明我们回溯了我们先是在(1,1)位置置为了2能走通,诶,向下走到了(2,1),诶,发现我现在怎么走都走不通了,我就吧(2,1)变成了3,回到了(1,1),好这条路不通我继续找另一条路,诶,我发现我无路可走了,那我把(1,1)也设置为3,就没了
最短路径问题
小球得到的路径,和程序员设置的找路策略有关即:
找路的上下左右的顺序相关再得到小球路径时,可以先使用(下右上左),再改成(上右下左),看看路径是不是有变化
我们测试,将我们的策略改变为上——右——下——左
//修改策略
public static boolean setWay2(int[][] map,int i,int j){
if (map[6][5] == 2){//通路找到
return true;
}else {
//如果当前这个点还没走过
if (map[i][j] == 0){
//按照我们的策略走下一步下--右--上--左
//先把现在这个点置为2,假定现在这点是能走通的
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;
}
}
}
第二种策略通路是
1 1 1 1 1 1 1
1 2 2 2 2 2 1
1 0 0 0 0 2 1
1 1 1 0 0 2 1
1 0 0 0 0 2 1
1 0 0 0 0 2 1
1 0 0 0 0 2 1
1 1 1 1 1 1 1
那如何求出最短路径呢?
我们现在没有更好的方法只能把四种策略,对应的2个个数存进数组中,看看谁的更小喽
//我们就在这用3中策略吧,因为策略太多了,不一一举例了,我们就求这三种策略谁的路径短
//求最短路径方法
public static int getMinimum(int[][] map){
int count = 0;//用来存储通路多长
//遍历map
for (int i = 0; i <8 ; i++) {
for (int j = 0; j <7 ; j++) {
if (map[i][j] == 2){
count++;
}
}
}
return count;
}
巧合的是我们这个地图设置的比较特别,怎么走都是10,emmm有兴趣的可以做一些改变,最后就是把每个策略对应的数字,比较,或者存入数组比较