Data structure ------ recursion + maze problem + shortest path problem solving ideas

Recursion

Scenes and concepts

Maze backtracking problem

To put it simply: Recursion is a method that calls itself , passing in different variables each time it is called. Recursion helps programmers solve complex problems, and at the same time makes the code concise.

Call mechanism

1. Printing problem

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    

Recursive call rules

1. When the program is executed to the method, it will open up an independent space (stack)

Insert picture description here

Combining our diagram, we can also find that it prints 2 first, then 3, then 4

If our method is modified like this

public static void test(int n){
    
    
    if (n>2){
    
    
        test(n-1);
    }else {
    
    
        System.out.println("n=" + n);
    }
}
结果就只有n=2输出,因为大于2的他都不会进入else输出

2. The factorial problem

/**
 * 阶乘问题
 * @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

What problem can recursion solve

  1. Various mathematical problems such as: 8 queens problem, Tower of Hanoi, factorial problem, maze problem, ball and basket problem; (google programming contest)
  2. Recursion is also used in various algorithms, such as fast sorting, merge sort, binary search, divide and conquer algorithm, etc.
  3. Problems that will be solved with the stack -> The recursive code is more concise

After designing these more difficult algorithms, I am going to answer them in another blog.

Rules for recursion

  • When a method is executed, a new protected independent air message (stack space) is created, as shown in the picture above
  • The local variables of the method are independent and will not affect each other, like the above n does not affect each other
  • If the method uses a reference type variable, the data of the reference type will be shared, as shown in the figure below
  • Recursion must approach the condition of exit recursion (there must be an exit) , otherwise it will be infinite recursion, and it will be dead. For example, n-1 in the above example is approaching the condition of exit recursion, otherwise it will Exception in thread "main" java.lang .StackOverflowError , stack overflow
  • When a method is executed, or when it encounters a return, it will return. Whoever calls it will return the result to whoever . At the same time, when the method is executed or returns, the method will also be executed.

Insert picture description here

Maze problem

Thinking analysis:

Put it directly into the code

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	

Let me describe

First, it starts at position 1, 1, now is position 6, 5 at 2? Obviously not, then we first set 1,1 to 2, assuming that according to the strategy, we first go down and call setWay(map,i+1,j), and return to the method again, to the (2,1) position , Now (6,5) is 2? No, then I continue to call back to myself, when I reach the position (3,1), I am grass, (3,1) is the wall, then I have to change my way, I go to the right, eh, I can get through, just keep calling back and forth like this , We found our destination

Then some people will say, you have no retrospective thinking! ! That’s because we have too few walls in the middle, and it’s too simple. He can walk through directly at once. Then I set it a little bit more difficult, and add more walls.

//设置我们的挡板
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	

There are two 3s, which means that we have backtracked. We first set it at the (1,1) position so that the 2 can go through, eh, we went down to (2,1), eh, I found that I can’t go no matter how I go now. I just changed (2,1) to 3 and returned to (1,1), so this road is blocked. I will continue to find another road. Hey, I found that I have no way to go. Then I put (1, 1) Also set to 3, it's gone

Shortest path problem

The path obtained by the ball is related to the path finding strategy set by the programmer , namely:

When the order of the up, down, left, and right of the way is related to get the ball path, you can first use (bottom right, top left), and then change to (top right, bottom left) to see if the path has changed.
Let’s test and change our strategy to Up-right-down-left

//修改策略
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	

How to find the shortest path?

We have no better way to save the four strategies and the corresponding 2 numbers in the array to see who has the smaller one.

//我们就在这用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;
}

Coincidentally, our map setting is quite special. It is 10 wherever you go. Emmm can make some changes if you are interested. Finally, compare the numbers corresponding to each strategy, or save them in an array for comparison.

Guess you like

Origin blog.csdn.net/qq_22155255/article/details/111414942