• Java 数据结构总结:一


      当我们使用计算机来解决问题时,一般需要这几个步骤:首先从该具体问题抽象出一个数学模型,然后设计或者选择一个解决此数学模型的算法,然后编写出程序进行调试、测试,直到得到最终的解答。这是是将数学思维用计算机实现的一个普遍逻辑,然而,随着计算机的发展,并非所有的问题都可以用简单的数学方程式解决。因此,解决这类问题的关键不再是数学分析和计算方法,而是要设计出合适的数据结构,才能有效解决此类问题。

      下面来一个具体问题体现数据结构的重要作用:

      用运回溯算法求解八皇后问题,该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。

    方法一: 定义皇后位置类来处理皇后位置数据的实现方式;

    解题思路:已在代码中注明。

    package algorithm;
    
    import java.util.LinkedList;
    
    /**
     *   回溯算法:八皇后问题
     *       该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:
     *   在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
     */
    public class EightQueen {
        private static final int SIZE = 8;  //皇后的个数,此处设置8,表示8个皇后
        private static int count = 0;  //记录摆放的方式数
    
        /**
         *     定义位置的数列结构,用于表示皇后的摆放位置
         *
         */
        static class Location {
            int x;  //对应棋盘的列
            int y;  //对应棋盘的行
    
            Location(int x, int y) {
                this.x = x;
                this.y = y;
            }
    
            @Override
            public String toString() {
                return "(" + x + "," + y +")";
            }
        }
        /**
         *     主要回溯法函数
         * @param list
         * @param x    //对应棋盘的列
         * @param y    //对应棋盘的行
         */
        private static void eightQueen(LinkedList<Location> list, int x, int y) {
            if(list.size() == SIZE) {  //当list元素个数为8时,表示8个皇后都摆放完毕,打印后即可退出函数。
                printLocation(list);    //打印皇后摆放方式
                return ;
            }
            for (int i = x; i < SIZE; i++) {
                Location loc = new Location(i,y);
                if(isLegalLoc(list,loc)) {
                    list.offer(loc);  //将第y行的皇后摆放好
                    eightQueen(list,0,y+1);   //开始摆放y+1行的皇后,同样从第0列开始摆放
                    list.pollLast();  //每次摆放完一个皇后后,都要将其撤回,再试探其它的摆法。(pollLast() 获取并移除此列表的最后一个元素)
                }
            }
    
        }
        /**
         * 判断位置为loc的皇后是否合法
         * @param list
         * @param loc
         * @return
         */
        private static boolean isLegalLoc(LinkedList<Location> list, Location loc) {
            for (Location each : list) {
                if(loc.x == each.x || loc.y == each.y) {  //判断是否在同一行或同一列
                    return false;
                }else if(Math.abs(loc.x - each.x) == Math.abs(loc.y - each.y)) {  //判断是否在同一对角线或反对角线上
                    return false;
                }
            }
            return true;
        }
        /**
         * 打印皇后摆放位置方式
         * @param list
         */
        private static void printLocation(LinkedList<Location> list) {
            for (Location each : list) {
                System.out.print(each.toString()+"	");
            }
            System.out.println();
            count ++;
        }
    
        public static void main (String[] args) {
            LinkedList<Location> list = new LinkedList<Location>();
            eightQueen(list,0,0);  //从棋盘的第0行第0列开始
            System.out.println("八皇后共有"+count+"种摆放方式");
        }
    }

    方法二: 以一维数组的方式来处理皇后位置数据的实现方式;

    解题思路:已在代码中注明。

    package algorithm;
    /**
     * 回溯算法:八皇后问题
     * @author 86135
     *
     */
    public class EightQueen2 {
        public static int num = 0;  //累计方案
        public static final int MAXQUEEN = 8;
        public static int[] cols = new int[MAXQUEEN];  //定义数组,表示8列棋子皇后摆放的位置
    
        /**
         * @param n 表示填第n列的皇后
         * */
        public void getCount(int n){
            boolean[] rows = new boolean[MAXQUEEN];
    
            for(int i = 0;i < n;i++){
                rows[cols[i]] = true;
    
                int d = n - i;  //计算差值
    
                //正斜方向
                if(cols[i] - d >= 0){
                    rows[cols[i]- d] = true;
                }
    
                //反斜方向
                if(cols[i] + d <= (MAXQUEEN - 1)){
                    rows[cols[i] + d] = true;
                }
            }
    
            for(int i = 0;i < MAXQUEEN;i++){
                if(rows[i]){
                    continue;
                }
                cols[n] = i;
    
                if(n < MAXQUEEN - 1){
                    getCount(n + 1);
                }else{
                    //找到一套完整的方案
                    num++;
                    printQueen();
                }
            }
        }
    
        public void printQueen(){
            System.out.println("第" + num + "种方案");
            for(int i = 0;i < MAXQUEEN;i++){
                for(int j = 0;j < MAXQUEEN;j++){
                    if(i == cols[j])
                        System.out.print("Q ");
                    else
                        System.out.print("+ ");
                }
                System.out.println();
            }
        }
    
        public static void main(String[] args){
            EightQueen2 q = new EightQueen2();
            q.getCount(0);
        }
    
    }

    方法三: 以二维数组的方式来处理皇后位置数据的实现方式;

    解题思路:由上往下依次向下遍历,那么我们只需要验证当前格子的上方,左斜上方和右斜上方的位置是否有皇后(因为如果由上往下遍历的时候,在当前行的下方是一定没有皇后的,所以我们只需要验证三个方向),如过三个方向都没有皇后,那么就可以确定当前位置可以放皇后

    package algorithm;
    /**
     *     回溯算法:八皇后问题
     * 
     *     解题思路:由上往下依次向下遍历,那么我们只需要验证当前格子的上方,左斜上方和右斜上方的位置是否有皇后
     *     (因为如果由上往下遍历的时候,在当前行的下方是一定没有皇后的,所以我们只需要验证三个方向),
     *     如过三个方向都没有皇后,那么就可以确定当前位置可以放皇后
     * @author 86135
     *
     */
    public class EightQueen3 {
        //定义 8*8 矩阵(二维数组)
        public static int[][] map = new int[8][8];
        public static int count = 1;
        /**
         *     显示棋盘
         */
        public static void show() {
            System.out.println("第"+count+"中排列方式");
            for (int i = 0; i < 8; i++) {
                for (int j = 0; j < 8; j++) {
                    System.out.print(map[i][j] +" ");
                }
                System.out.println();
            }
            count++ ;
        }
        /**
         *     检验方法(验证该位置是否可以放皇后)
         * @param row
         * @param col
         * @return
         */
        public static boolean check(int row,int col) {
            //上面(行减小  列不变)
            for (int i = row-1; i >= 0; i--) {
                if(map[i][col] == 1) {
                    return false;
                }
            }
            //左斜上 (行减小  列减小)
            for (int i = row-1,j = col-1; i >= 0 && j >= 0; i--,j--) {
                if (map[i][j] == 1) {
                    return false;
                }
            }
            //右斜上 (行减小  列增加)
            for (int i = row-1,j = col+1; i >= 0 && j < 8; i--,j++) {
                if (map[i][j] == 1) {
                    return false;
                }
            }
            return true;
        }
        /**
         * 皇后排列方法
         * @param row
         */
        public static void play(int row) {
            //遍历当前行的所有单元格
            for (int i = 0; i < 8; i++) {
                //判断本格是否可以放皇后
                if(check(row,i)) {
                    map[row][i] = 1;
                    //判断是否为最后一行
                    if(row == 7) {
                        show();
                    }else {
                        //接着走下一步
                        play(row + 1);
                    }
    
                    //取消当前落子  清空棋盘
                    map[row][i] = 0;
                }
    
            }
        }
        public static void main(String[] args) {
            play(0);
        }
    }
  • 相关阅读:
    [bzoj2654]tree_二分_kruskal
    [luogu1373]小a和uim之大逃离_动态规划
    [luogu1156]垃圾陷阱_动态规划_背包dp
    [luogu2209][USACO13]燃油经济性Fuel Economy_贪心
    UNIX环境高级编程——进程基本概述
    UNIX环境高级编程——进程控制
    UNIX环境高级编程——进程环境
    UNIX环境高级编程——时间和日期
    UNIX环境高级编程——Linux进程地址空间和虚拟内存
    UNIX环境高级编程——标准I/O库函数和Unbuffered I/O函数
  • 原文地址:https://www.cnblogs.com/zhaoKeju-bokeyuan/p/12157455.html
Copyright © 2020-2023  润新知