递归

递归 recursion

递归方法就是 自己调用自己,而且每次都传不同的变量。

1.递归要干什么?
2.递归停止的条件是什么?
3.从本层到下层的关系是什么?

调用机制

  • 先自己调用自己,不断在栈中开辟空间;
  • 到达最顶层后,函数运行完毕,销毁,转到后一个函数;
  • 直到到达 main栈,没有方法了 退出程序。

应用场景:

  1. 各种数学问题:8皇后问题,汉诺塔,阶乘,迷宫,球和篮子问题等等;
  2. 各种算法:快排,归并,二分查找,分治法等等;
  3. 各种 用栈解决的问题(用递归使代码更简洁)。

遵守重要规则:

  1. 每执行一个方法,即创建一个新的受保护的独立空间(栈空间)
  2. 方法中的 局部变量是独立的
  3. 若方法中 使用的是 引用类型变量(数组等),就会共享该数据
  4. 递归必须向 退出递归的条件逼近,否则无限递归 StackOverflowErrow栈溢出
  5. 当一个方法执行完毕 或 遇到return,就会返回,遵循谁调用返回谁。

迷宫问题

题目:
迷宫中有边界,有挡板,需要从起点位置(<1,1>--<6,5>) 到达终点。

初始化地图
  /* recursion-迷宫问题
     1. 数组 map 表示地图
     2. i,j 表示 当前出发的位置
     3. 若小球能到达 map[x-1][y-1]位置,说明通路找到;
     4. 约定当map[i][j]
          为0 表示没走过 ,
          为1 表示为墙 ,
          为2 表示通路,可以走
          为3 表示走过,走不通
     5. 确定一个走的策略(可以自己定): 下->右->上->左
  */
  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;
      map[2][2] = 1;
      map[1][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();
      }
  
      boolean isOk = setWay(map,1,1);
      System.out.println(isOk+" 走过后情况:");
      for (int i = 0; i < 8; i++) {
          for (int j = 0; j < 7; j++) {
              System.out.print(map[i][j]+"  ");
          }
          System.out.println();
      }
  }

代码实现:

  1. 判断 当前位置是否已到达终点,

  2. 没到终点,不断 递归选路:

     /**
      * 2.找路 (自己定义 上左下右的 顺序)
      * @param map 表示地图
      * @param i   表示当前位置
      * @param j
      * @return  找到通路返回true,否则返回false
      */
     public static boolean setWay(int[][] map,int i,int j){
         //1.判断是否到达终点
         int x = map.length;
         int y = map[0].length;
         if (map[x-2][y-2]==2){  //找到终点,直接返回
             return true;
         }else {
         //2.未到终点,不断递归寻路
             if (map[i][j]==0){ //a.若当前点 未走过
                 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 {          //b.当前点走过了 false
                 return false;
             }
         }
     }
    

八皇后问题

8X8的棋盘,每一行一个棋子,每个棋子 不能在同一列,不能在同一斜线。

思路:前7个放好,放第8列-->回溯到前6个放好,放第7,8列 。。。

  1. 第一个皇后先放在第一行的第一列
  2. 第二个皇后放在第二行的第一列,判断是否冲突,否则放在 第2,3..8列
  3. 直到第八个皇后的位置放好,回溯到上一个皇后 放到另一列
  4. 直到第一个皇后 放到最后一列,所有情况都遍历完毕。

代码:

  • 初始化数组
  • judge(n) 判断当前行 放置后 是否与前面冲突【n为当前行 的 列的位置】
  • check(0) 第0行开始 放皇后,遍历每一列,递归到下一行继续遍历。
8皇后问题代码实现
class Queue8{
/*  八皇后问题
  有8个栈(8行 check),
    每个栈 中都会有8次循环【列的位置】, 列judge正确就 进入下一个栈
                                  第8行判断完后直接return,回到上一栈
    8次循环完毕后 返回上一个栈
*/
    //1.创建一个 一维数组,表示皇后的位置
    public int max = 8;
    public int[] arr = new int[max]; //arr[i]=value -->i表示第几行,value表示第几列
    public static int count;         //记录轮数:即共有多少中放法
    public static int judgeCount;    //记录判断次数

    //2.检测 放的第n个皇后是否与前面的冲突
    public boolean judge(int n){
        judgeCount++;//判断次数
        //遍历前面的行
        for (int i = 0; i < n; i++) {
            boolean isCol = arr[i]==arr[n]; //同一列
            boolean isDiagonal = Math.abs(n-i)==Math.abs(arr[n]-arr[i]); //同一对角线
            if (isCol || isDiagonal){
                return false;
            }
        }
        return true; //不冲突返回true
    }

    //3.放皇后
    public void check(int n){
        if (n == max){ //遍历到了第9行,此轮放完了
            ++count;
            print();
            return;
        }
        //1.遍历每一列
        for (int i = 0; i < max; i++) {
            arr[n] = i;         //假设此列能放
            if (judge(n)){      //注意这里传n 行数,而不是i
                check(n+1);  //此列能放,进入下一行
            }
        }
    }
    //打印数组
    public void print(){
        for (int i = 0; i < max; i++) {
            System.out.print(arr[i]+" ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        Queue8 queue8 = new Queue8();
        queue8.check(0);
        System.out.printf("共有%d种结果\n",count);
        System.out.printf("共判断了%d次",judgeCount);
    }
}
posted @   simp1e1  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示