【Java数据结构与算法】 递归及迷宫问题(回溯)

文章目录

    • 递归调用机制
        • 简单的递归使用
        • 递归能解决的问题和规则
        • 递归-迷宫问题
          • 思路分析:
          • 代码如下:

递归调用机制

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

递归应用场景:
迷宫问题(回溯),递归(Recursion)

简单的递归使用

打印问题递归代码:

public class RecursionTest {
    public static void main(String[] args) {
    	//通过打印问题,来了解递归的调用机制
		test(4);
    }
    public static void test(int n) {
        if (n > 2){
            test(n - 1);
        }
        System.out.println("n=" + n);
    }

分析:
程序首先进入到main方法,在栈里面开辟一个空间,随之调用test(4),然后开辟一个独立的空间(栈),然后在test里面有if,而且n也满足于他,就执行if方法里面的,结果是本身test方法,所以他又开辟了一个新的空间(栈),往复循环,到n=2时,不符合if,所以执行Systeam.out.println(“n=” + n);.所以先输出结果一个结果2,然后回到上一个空间,上一个空间里面的n是3,继续执行Systeam.out.println(“n=” + n);,再回到上一层执行Systeam.out.println(“n=” + n);,随之退出程序。所以最后结果是:输出n = 2,n = 3,n = 4

阶乘问题递归代码:

package datatype;

public class RecursionTest {
    public static void main(String[] args) {
        System.out.println(factotial(4));
    }
    public static int factotial(int n) {
        if (n == 1) {
            return 1;
        } else {
            return factotial(n - 1) * n;
        }
    }
}

分析:
形参为4,同为递归,也是调用自己,所以可以理解为factotial(4-1)*4
=factotial(3-1)*3*4
=factotial(2-1)*2*3*4
=factotial(1)*1*2*3*4
=1*1*2*3*4。

递归能解决的问题和规则

递归能解决什么样的问题?

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

递归需要遵守的重要规则:

  1. 执行一个方法时,就创建一个新的受保护的独立空间(栈空间)
  2. 方法的局部变量是独立的,不会相互影响,比如前面的那个n
  3. 如果方法中使用的是引用类型变量(如数组),就会共享该引用类型的数据
  4. 递归必须是向退出递归的条件逼近,否则就是无限递归,出现StackOverflowError,死龟了
  5. 当一个方法执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁,同时当方法执行完毕或返回时,该方法也就执行完毕。

递归-迷宫问题

迷宫问题,即有一迷宫,然后用代码的方式找到出去的出口。
【Java数据结构与算法】 递归及迷宫问题(回溯)_第1张图片
由于本人太懒,就不弄太复杂的迷宫了,有兴趣的朋友可以自己修改一下!

0为迷宫的路,1为墙,2为出去的路,3为不可行的路

思路分析:

假设小球出发点为可走的路,然后按照下->右->上->左的顺序进行找路,向下面走,如果可行,那么这个点就更改为2,(0为迷宫的路,1为墙,2为出去的路,3为不可行的路),然后再进行下->右->上->左的顺序进行找路,使用递归挨个找,类似台球当中的大力出奇迹,只要我够大力,白球就可以一直弹弹弹,进球的概率就越大。

代码如下:
package datatype;

public class MiGong {
    public static void main(String[] args) {
        //先创建一个二维数组,模拟迷宫
        //地图
        int[][] map = new int[8][7];
        //使用1表示墙壁
        //上下全部添加“墙”
        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] + "  ");
            }
            System.out.println();
        }
        //使用递归回溯来给小球找路
        setWay(map,1,1);
        //输出新的地图,小球走过,并标识过的递归
        System.out.println("小球走过的路为:");
        for (int i = 0;i < 8;i ++) {
            for (int j = 0; j < 7;j ++) {
                System.out.print(map[i][j] + "  ");
            }
            System.out.println();
        }
    }
    //使用递归回溯来给小球找路
    /*说明
    * 1.map表示迷宫
    * 2.i和j表示从迷宫的哪个位置开始出发
    * 3.出口为map[6][5],如果小球能找到map[6][5]位置,则说明通路找到
    * 4.约定:当map[i][j]为0,表示该点没有走过,当为1时,表示墙,2表示通路可以走,3表示已经走过,但是走不通
    * 5.在走迷宫时。需要确定一个策略(方法),先走下面->右面->上面->左面,如果该店走不通,再回溯
    */
    /**
     *
     * @param map表示迷宫
     * @param i从哪个位置开始走
     * @param j
     * @return如果找到能走的路就返回true,否则返回false
     */
    public static boolean setWay(int[][] map,int i,int j) {
        //说明通路已经找到
        if (map[6][5] == 2){
            return true;
        }else {
            //如果当前这个点还没有走过
            if (map[i][j] == 0){
                //按照策略下面->右面->上面->左面
                //假定该点是可以走通的
                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;
                }
            }
            //如果map[i][j]!=0,则可能是1,2,3
            else {
                return false;
            }
        }
    }
}

运行结果:
【Java数据结构与算法】 递归及迷宫问题(回溯)_第2张图片
0为迷宫的路,1为墙,2为出去的路,3为不可行的路

毕竟编程我是初学者,如若有理解错误的地方,希望大家看完之后,发现错误可以评论出来,谢谢大家!

你可能感兴趣的:(数据结构与算法)