递归(recursion)

递归

递归就是一个方法自己调用自己,每次调用时传入不同的变量。递归有助于编程者解决复杂的问题,同时可以让代码变得更简洁。
图解递归调用机制:
递归适用场景

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

递归需要遵守的重要规则

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

迷宫问题

在这里插入图片描述

代码实现

/**
 * 二维数组模拟迷宫
 * 如果小球到达map[6][5]的位置 则表示已经找到出口
 *
 * 约定 0表示没有走过 1为墙 2为通路 3为位置已经走过但不是通路
 * 确定行径放心 下 右 上 左 ,如果都不通回溯
 */
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;
        //堵死
//        map[1][2] = 1;
//        map[2][2] = 1;
        System.out.println("输出迷宫地图");
        print(map);

        System.out.println("老鼠的路径:");
        if(setWay(map,1,1)){
            print(map);
        }else{
            print(map);
            System.out.println("找不到出路");
        }
    }
    public static void print(int map[][]){
        for(int i = 0;i<8;i++){
            for(int j = 0;j<7;j++){
                System.out.print(map[i][j]+ " ");
            }
            System.out.println();
        }
    }

    /**
     * i,j表示出发的位置
     * @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){
                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{
                //1 墙 2 走过 3 不能走
                return false;
            }
        }
    }
}

八皇后问题

八皇后问题介绍
八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯.贝瑟尔于1848年提出;在8x8格的国际象棋上摆放了8个皇后,使其不能相互攻击。任意两个皇后都不能处于同一行、同一列或者同一斜线上,问有多少种摆法(92);

八皇后问题算法思路分析
1 第一个皇后先放第一行第一列
2 第二个皇后放在第二行第一列、然后判断是否ok,如果不ok继续放在第二列、第三列…依次把所有列都放完,找到一个合适的
3 继续放第三个皇后,还是第一列、第二列…直到第8个皇后也能放在一个不冲突的位置,算是找到了一个正确解
4 当得到一个正确的解时,在栈回退到上一个栈时,就会开始回溯,即将第一个皇后,放到第一列的所有正确解,全部得到
5 然后回头继续第一个皇后放第二列,后面继续循环执行1、2、3、4的步骤
在这里插入图片描述
说明:
理论上应该创建一个二维数组来表示棋盘,但实际上可以通过算法,用一个一维数组即可解决问题。arr[8]={0,4,7,5,2,6,1,3} //对应arr下标表示第几行,即第几个皇后,arr[i]=val, val 表示第i+1个皇后,放在第i+1行的第val+1列

代码实现

public class Queen8 {
    //定义有多少个皇后
    int num = 8;
    //第几种方式
    int count = 0;
    //存放皇后的位置
    int[] arr = new int[num];

    public static void main(String[] args) {
        Queen8 q8 =new Queen8();
        q8.check(0);
    }

    public void check(int n){
        if(n == num ){
            count++;
            print();
            return;
        }
        //依次放皇后是否有冲突
        for(int i=0;i<num;i++){
            //先把当前皇后放到 该行的第一列
            arr[n] = i;
            //判断是否有冲突
            if(judge(n)){
                check(n+1);
            }
            //循环 如果冲突则继续执行 arr[n] = i;往后移一个位置
        }
    }
    /**
     * 判断放置第n个皇后是否有冲突(不需要判断同行的情况 n在递增)
     * @param n 第n个皇后
     * @return
     */
    public boolean judge(int n){
        for(int i = 0 ;i < n; i++){
            // arr[8] = {0,4,7,5,2,6,1,3}
            // arr[i]==arr[n] -->第n+1个皇后和第i+1个皇后是否在同一直线上(同列)
            // Math.abs(n-i) == Math.abs(arr[n]-arr[i]) -->判断是否在同一斜线上
            if(arr[i] == arr[n] || Math.abs(n-i) == Math.abs(arr[n]-arr[i])){
                return false;
            }
        }
        return true;
    }

    //打印皇后的信息
    public void print(){
        System.out.println("第"+count+"种:");
        for(int i = 0;i<arr.length;++i){
            System.out.print(arr[i]+" ");
        }
        System.out.println();
    }
}

信息打印
经过验证有92种;
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值