数据结构和算法七:递归

文章目录

  • 简介
  • 递归可以解决的问题
  • 递归需要遵守的规则
  • 迷宫问题
  • 八皇后问题

简介

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

递归可以解决的问题

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

递归需要遵守的规则

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

迷宫问题

数据结构和算法七:递归_第1张图片

package com.atguigu.recursion;

public class MiGong {
    public static void main(String[] args) {
        //创建一个二维数组来模拟迷宫
        int[][] miGong = new int[8][7];
        //使用1表示墙
        for (int i = 0; i < 8; i++) {
            miGong[i][0] = 1;
            miGong[i][6] = 1;
        }

        for (int i = 0; i < 7; i++) {
            miGong[0][i] = 1;
            miGong[7][i] = 1;
        }

        miGong[3][1] = 1;
        miGong[3][2] = 1;

        System.out.println("------输出地图情况-------");
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 7; j++) {
                System.out.print(miGong[i][j] + " ");
            }
            System.out.println();
        }

        //使用递归回溯找路
        setWay(miGong, 1, 1);

        System.out.println("------输出路径情况-------");
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 7; j++) {
                System.out.print(miGong[i][j] + " ");
            }
            System.out.println();
        }
    }


    /**
     * 使用递归回溯找路径
     * 说明:
     * 1.如果小球可以到 map[6][5] ,则说明找到通路
     * 2.约定:当 map[i][j] 为0时,表示该点没有走过,
     * 当为1时,表示墙,
     * 为2表示通路可以走,
     * 为3表示该位置已经走过,但是不通
     * 3.需要确定一个策略(方法),下-->右-->上-->左,如果该点走不通,再回溯
     * @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;
                }
            } else {
                //如果map[i][j] != 0, 可能是1,2,3
                return false;
            }
        }
    }
}



数据结构和算法七:递归_第2张图片

八皇后问题

数据结构和算法七:递归_第3张图片
思路分析

  1. 第一个皇后放在第一行第一列
  2. 第二个皇后放在第二行第一列、判断是否可行,如果不可行,继续放在第二列、第三列、依次把所有列都放完,找到一个合适的位置
  3. 继续第三个皇后,还是第一列、第二列…直到8个皇后都找到合适的位置,此时算是找到一个正确解
  4. 当得到一个正确解之后,栈回退到上一个栈,开始回溯,即得到第一个皇后在第一列上的正确解得到
  5. 然后将第一个皇后放在第一行第二列、第三列…循环1,2,3,4步,直到获得所有解
package com.atguigu.recursion;

/**
 * 8皇后问题解法
 */
public class Queue8 {

    /**
     * 8个皇后
     */
    int max = 8;

    /**
     * 存放8皇后的位置,下标表示行,值表示列
     */
    int[] array = new int[max];

    /**
     * 记录一共有多少种解法
     */
    static int count = 0;

    /**
     * 记录一共比较了多少次
     */
    static int judgeCount = 0;

    public static void main(String[] args) {

        Queue8 queue8 = new Queue8();
        queue8.check(0);
        System.out.printf("一共有 %d 种解法", count);
        System.out.println();
        System.out.printf("一共进行了 %d 次比较", judgeCount);

    }


    private void check(int n) {
        //n==max 时对应的是第9个皇后,说明已经找到了一种解法,打印
        if (n == max) {
            count++;
            print(array);
            return;
        }
        //寻找皇后位置
        for (int i = 0; i < max; i++) {
            //先假设当前的位置就是合适的位置
            array[n] = i;
            //看看是否有冲突
            if (judge(n)) {
                //没有冲突就走下一个皇后,开始递归
                check(n + 1);
            }
            //如果找不到,就进行回溯,通过改变上一个皇后的位置,重新进行递归,直到找到所有的解法
        }
    }


    /**
     * 判断第n个皇后是否和前几个皇后冲突
     * @param n
     * @return
     */
    private boolean judge(int n) {
        for (int i = 0; i < n; i++) {
            //array[i] == array[n]  相等说明在同一列必定会冲突
            //Math.abs(n - i) == Math.abs(array[n] - array[i])   相等说明在同一条斜线上
            judgeCount++;
            if (array[i] == array[n] || Math.abs(n - i) == Math.abs(array[n] - array[i])) {
                return false;
            }
        }
        return true;
    }


    /**
     * 打印解法
     * @param array
     */
    private void print(int[] array) {
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i]+" ");
        }
        System.out.println();
    }

}

数据结构和算法七:递归_第4张图片

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