• Java递归应用


    一、概念

      简单的说: 递归就是方法自己调用自己

      递归有助于解决复杂的问题,可以让代码变得简洁

    二、能解决什么样的问题

        

    三、递归需要遵守的重要规则

    四、迷宫问题

      

      说明:

      1)小球得到的路径,和程序员设置的查找策略有关,即:上 -> 下 -> 左 -> 右

      2)  在得到小球路径时,可以先使用(上下左右),在改为(上右下左),看路径是否有变化

      3)测试回溯现象

      4)最短路径求法?

      代码: 

     1 public class MiGong {
     2     public static void main(String[] args) {
     3         // 先创建一个二维数组,模拟迷宫
     4         int[][] map = new int[8][7];
     5         // 使用1 表示墙
     6         // 上下全部置为1
     7         for (int i = 0; i < map[0].length; i++) {
     8             map[0][i] = 1;
     9             map[7][i] = 1;
    10         }
    11         // 左右全部置为1
    12         for (int i = 1; i < map.length - 1; i++) {
    13             map[i][0] = 1;
    14             map[i][6] = 1;
    15         }
    16         //设置挡板, 1 表示
    17         map[3][1] = 1;
    18         map[3][2] = 1;
    19         // 输出地图
    20         for (int i = 0; i < map.length; i++) {
    21             for (int j = 0; j < map[i].length; j++) {
    22                 System.out.print(map[i][j] + "	");
    23             }
    24             System.out.println();
    25         }
    26         System.out.println("------------------------");
    27         //使用递归回溯给小球找路
    28         findWay(map, 1, 1);
    29         //输出新的地图, 小球走过,并标识过的递归
    30         for (int i = 0; i < map.length; i++) {
    31             for (int j = 0; j < map[i].length; j++) {
    32                 System.out.print(map[i][j] + "	");
    33             }
    34             System.out.println();
    35         }
    36     }
    37     //使用递归回溯来给小球找路
    38     //说明
    39     //1. map 表示地图
    40     //2. i,j 表示从地图的哪个位置开始出发 (1,1)
    41     //3. 如果小球能到 map[6][5] 位置,则说明通路找到.
    42     //4. 约定: 当map[i][j] 为 0 表示该点没有走过 当为 1 表示墙  ; 2 表示通路可以走 ; 3 表示该点已经走过,但是走不通
    43     //5. 在走迷宫时,需要确定一个策略(方法) 下->右->上->左 , 如果该点走不通,再回溯
    44 
    45     /**
    46      * @param map
    47      * @param i   从哪个位置开始找
    48      * @param j
    49      * @return 如果找到通路,就返回true, 否则返回false
    50      */
    51     public static boolean findWay(int[][] map, int i, int j) {
    52         if (map[6][5] == 2) {
    53             return true;
    54         } else {
    55             //如果当前点没走过
    56             if (map[i][j] == 0) {
    57                 //假定可以走通
    58                 map[i][j] = 2;
    59                 //下{
    60                 if (findWay(map, i+1, j )) {
    61                     return true;
    62                 }
    63                 //
    64                 else if (findWay(map, i , j+1)) {
    65                     return true;
    66                 }
    67                 //
    68                 else if (findWay(map, i - 1, j)) {
    69                     return true;
    70                 }
    71                 //
    72                 else if (findWay(map, i, j - 1)) {
    73                     return true;
    74                 }
    75                 else {
    76                     //说明该点是走不通,是死路
    77                     map[i][j] = 3;
    78                     return false;
    79                 }
    80              // 如果map[i][j] != 0 , 可能是 1, 2, 3
    81             } else {
    82                 return false;
    83             }
    84 
    85         }
    86     }
    87 }

    五、八皇后问题(回溯算法)

       1、概述

      八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。计算机发明后,有多种计算机语言可以解决此问题。

      

      2、思路分析 

      3、说明

      理论上应该创建一个二维数组来表示棋盘,但实际可以通过算法,用一个一位数组即可解决问题

      arr[8] = {0, 4, 7,5,2,6,1,3},对应的下标表示第几行,即第几个皇后,arr[i] = val, val 表示第i+1个皇后,放在i+1行的第val+1列

      4、代码

     1 public class Queen8 {
     2     //定义一个max表示共有多少个皇后8
     3     final static int max = 8;
     4     //定义数组array, 保存皇后放置位置的结果,比如 arr = {0 , 4, 7, 5, 2, 6, 1, 3}
     5     static int[] arr = new int[max];
     6     //记录不冲突的次数
     7      static int count;
     8     //总判断次数
     9     static int sumCount;
    10 
    11     public static void main(String[] args) {
    12         check(0);
    13         System.out.printf("共有%d种走法,一共判断%d次
    ",count,sumCount);
    14     }
    15 
    16     //编写一个方法,放置第n个皇后
    17     //特别注意: check 是 每一次递归时,进入到check中都有  for(int i = 0; i < max; i++),因此会有回溯
    18     public static void check(int n) {
    19         //n = 8 , 其实8个皇后就既然放好
    20         if (n == max) {
    21             print();
    22             return;
    23         }
    24         //依次放入皇后,并判断是否冲突
    25         for (int i = 0; i < max; i++) {
    26             //先把当前这个皇后 n , 放到该行的第1列
    27             arr[n]=i;
    28             //判断当放置第n个皇后到i列时,是否冲突
    29             if(judge(n)){ // 不冲突
    30                 //接着放n+1个皇后,即开始递归
    31                 check(n+1);
    32             }
    33             //如果冲突,就继续执行 array[n] = i; 即将第n个皇后,放置在本行得 后移的一个位置
    34         }
    35 
    36     }
    37 
    38     //查看当我们放置第n个皇后, 就去检测该皇后是否和前面已经摆放的皇后冲突
    39     public static boolean judge(int n) {
    40         sumCount++;
    41         // 说明
    42         //1. array[i] == array[n]  表示判断 第n个皇后是否和前面的n-1个皇后在同一列
    43         //2. Math.abs(n-i) == Math.abs(array[n] - array[i]) 表示判断第n个皇后是否和第i皇后是否在同一斜线
    44         // n = 1  放置第 2列 1 n = 1 array[1] = 1
    45         // Math.abs(1-0) == 1  Math.abs(array[n] - array[i]) = Math.abs(1-0) = 1
    46         //3. 判断是否在同一行, 没有必要,n 每次都在递增
    47         for (int i = 0; i <n ; i++) {
    48             if(arr[i]==arr[n]||Math.abs(arr[n]-arr[i])==Math.abs(n-i)){
    49                 return false;
    50             }
    51         }
    52         return true;
    53     }
    54 
    55     //写一个方法,可以将皇后摆放的位置输出
    56     public static void print() {
    57         count++;
    58         for (int i = 0; i < arr.length; i++) {
    59             System.out.print(arr[i]+"	");
    60         }
    61         System.out.println();
    62     }
    63 }
  • 相关阅读:
    Jinja2 教程 第 2 部分 循环和条件
    Jinja2 教程 第 5 部分 宏
    Jinja2 教程 第 4 部分 模板过滤器
    Jinja2 教程 第 3 部分 空白控制
    Jinja2 教程 第 6 部分 包含和导入
    高并发下Redis的分布式锁在集群中的问题
    [bug] SourceTree 推送时,没有分支可选
    [bug] github:You‘re using an RSA key with SHA1, which is no longer allowed
    Leetcode 797 所有可能的路径 BFS 回溯
    Linux驱动开发一.字符设备框架——4.驱动测试
  • 原文地址:https://www.cnblogs.com/hyunbar/p/11291073.html
Copyright © 2020-2023  润新知