数据结构与算法-递归(八皇后)

引言

        在数据结构与算法的世界里,递归是一种优雅且强大的工具,它将复杂的问题通过不断分解为相似的子问题来解决。而“八皇后问题”作为经典的递归问题实例,充分展示了递归算法的魅力。本文将深入探讨八皇后问题的背景、递归解决方案及其背后的逻辑。

一、八皇后问题概述

        八皇后问题是一个典型的回溯法(Backtracking)问题,要求在一个8×8的国际象棋棋盘上放置八个皇后,使得任何两个皇后都不能处于同一行、同一列或同一斜线上。这是一个 NP 完全问题,没有已知的多项式时间解决方案,但可以通过搜索算法如递归来找到所有可能的解。

二、递归求解八皇后问题的基本思路

  1. 基本情况判断: 当我们在棋盘上成功放置了8个皇后时,即找到了一个有效的解,此时返回True或增加解的数量。

  2. 递归步骤: 对于每个空格,尝试放置皇后,并对下一行进行递归调用。如果在某一行找不到合适的放置位置,则需要回溯至上一行,改变该行皇后的位置,继续寻找其他可能性。

  3. 回溯机制: 如果在当前行无法找到满足条件的位置,则撤销当前行皇后的位置,将皇后向左移动一位,并再次尝试放置。当回到第一行仍无解时,则说明当前分支探索失败,应彻底回溯到上一层递归调用,更改前一行皇后的列位置。

具体思路:

  • 第一个皇后先放第一行第一列
  • 第二个皇后放在第二行第一列,然后判断是否可以摆放,如果不可以,继续放在第二列,第三列,依次把所有列都放完,直到摆放合适位置
  • 继续摆放第三个皇后,还是从第一列,第二列依次推类,直到第八个皇后摆放完成都不冲突,就是一个正确解答
  • 当得到一个正确解的时候,在栈回退到上一个栈时,就会开始回溯,即将第一个皇后,放在第一列所有正确解全部得到
  • 然后回头继续第一个皇后放在第二列,后面继续循环执行上述操作

说明:

        理论上应该创建一个二维数组表示棋盘,但是实际上可以通过算法,用一个一维数组即可解决问题。例如 arr[8] = {0, 4, 7, 5, 2, 6, 1, 3} //对应的arr下标表示棋盘的第几行,即为第几个皇后;arr[i] = val,val表示第i + 1个皇后,放在第i + 1行的第 val + 1列的位置。

三、代码展示

1.验证第n个皇后位置是否冲突

    //    查看放置的第n个皇后,就去监测该皇后是否与前面摆放的皇后有冲突

    /**
     * @param n 表示第n个皇后
     * @return array[i] == array[n]  是否在同一列
     * Math.abs(n - i) == Math.abs(array[n] - array[i])  是否在同一斜线
     */
    private boolean judge(int n) {
        for (int i = 0; i < n; i++) {
            if (array[i] == array[n] || Math.abs(n - i) == Math.abs(array[n] - array[i])) {
                return false;
            }
        }
        return true;
    }

2.放置第n个皇后

    //    编写一个方法放置n个皇后
    //    特别注意:check是每一次递归时,进入到check中都有for (int i = 0; i < max; i++),因此会有回溯
    private void check(int n) {
        if (n == max) {
            count++;
            print();
            return;
        }
//        依次放入皇后并判断是否冲突
        for (int i = 0; i < max; i++) {
//            先把当前皇后n,放在改行的第一列
            array[n] = i;
//            判断放置这个第n个皇后到i列时是否冲突
            if (judge(n)) {
//                不冲突,接着放下一个皇后
                check(n + 1);
            }
//            如果冲突,就继续执行array[n] = i,将其放本行后一列位置
        }
    }

3.输出求解 

    //    写一个方法可以将皇后摆放的位置输出
    private void print() {
        for (int queen : array) {
            System.out.print(queen + "\t");
        }
        System.out.println();
    }

4.代码测试 

public class Queen {
    //    定义第一个max共有多少个皇后
    int max = 8;
    static int count = 0;
    int[] array = new int[max];

    public static void main(String[] args) {
        Queen queen = new Queen();
        queen.check(0);
        System.out.printf("共有%d个解法", count);
    }
}

四、优化策略

        虽然基本的递归实现可以找到所有的解,但在实际运行中可能会因为递归深度较大而导致性能问题。为了提高效率,我们可以采用一些优化策略,例如记忆化搜索(Memoization)或者使用迭代的方式模拟递归过程。

五、总结

        八皇后问题生动地展示了递归算法如何巧妙地应对复杂问题,通过不断地试探和回溯,最终找到所有可能的解决方案。理解并掌握递归思想不仅有助于我们解决类似的问题,而且对于提升编程能力和抽象思维有着深远的影响。此外,研究递归算法的过程中,也让我们更深刻地认识到计算机科学中“分而治之”的核心理念。

 

 

  • 23
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值