数据结构------递归+迷宫问题+最短路径问题解决思路

递归

场景以及概念

迷宫回溯问题

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

调用机制

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.当程序执行到方法时,就会开辟一个独立的空间(栈)

数据结构------递归+迷宫问题+最短路径问题解决思路_第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

递归能解决什么问题

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

设计到这些比较有难度的算法我准备在另外的博客进行解答

递归要遵守的规则

  • 执行一个方法时,就创建一个新的受保护的独立空闻(栈空间),像我们上面那张图所示
  • 方法的局部变量是独立的,不会相互影响,像上面的那个n相互之间是不影响的
  • 如果方法中使用的是引用类型变量,则会共享该引用类型的数据,下图所示
  • 递归必须向退出递归的条件逼近(必须有出口),否则就是无限递归,死龟了,如上面例子的n-1就是在向退出递归的条件逼近,否则会Exception in thread “main” java.lang.StackOverflowError,栈溢出
  • 当一个方法执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁,同时当方法执行完毕或者返回时,该方法也就执行完毕。

数据结构------递归+迷宫问题+最短路径问题解决思路_第2张图片

迷宫问题

思路分析:

直接放进了代码中

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有兴趣的可以做一些改变,最后就是把每个策略对应的数字,比较,或者存入数组比较

你可能感兴趣的:(算法,算法,java,数据结构,递归算法)