【问题标题】:Optimizing N Queens code to avoid stack overflow优化 N Queens 代码以避免堆栈溢出
【发布时间】:2010-11-14 03:49:11
【问题描述】:

我一直在尝试编写一个 java 类来使用某种堆叠和递归来解决 n 个皇后问题,答案存储在网格(二维数组)中,但我遇到了堆栈的死墙在 n=8 处递归溢出(最大递归深度达到 2298) 所以我一直想知道是否有某种方法可以通过做一些复杂的事情来绕过这个死,比如在java中分配更多的堆空间(如果可能的话?)或使用多线程(指出我的教程/示例)......或者请就如何优化代码提供建议... 提前致谢

    public void resoudre(){

        this.gridPile.push(copyGrid(grid));
        try{
            int row = gridPile.size()-1;
            if(gridPile.size()==0)row = 0;
            chooseGridSpace(this.grid, locateFirstAvailable(grid, row));
            if(gridPile.size() == this.taille){
                gridSolutions.push(copyGrid(grid));
                grid = gridPile.pop();
                boolean erronous = true;
                while(erronous){
                    try{
                        MakeNextUnavailable(grid, gridPile.size());
                        erronous = false;
                    }
                    catch(UnavailabilityException r1){
                        try{
                            grid = gridPile.pop();
                        }
                        catch(java.util.EmptyStackException r2){
                            return;
                        }
                    }
                }
            }

        }
        catch(InvalidPositionException e1){
            this.grid = gridPile.pop();
            boolean error = true;
            while(error){
                try{
                    MakeNextUnavailable(grid, gridPile.size());
                    error = false;
                }
                catch(UnavailabilityException er){
                    try{
                        this.grid = gridPile.pop();
                    }
                    catch(java.util.EmptyStackException err){
                        return;
                    }
                }
            }
        }
        catch(java.lang.ArrayIndexOutOfBoundsException e2){
            return;
        }
        this.resoudre();
    }

    private static void chooseGridSpace(int[][] grid, Position a){
        grid[a.getLigne()][a.getColonne()] = 1;
        fillNotAvailable(grid, a);
    }

【问题讨论】:

  • 我做了一些简单的优化,一个是为了避免递归结构所以代替 public void resoudre(){ /** * 代码行数 <i>/ resourdre(); } </i> 我做了 public void resoudre(){ do{ /* * 代码行 */ } while(true); } 无论如何,我同意下面的一些意见,即程序结构更简单,但我选择了这种方式来简化 gui 操作......

标签: java recursion stack-overflow


【解决方案1】:

直接回答:无需将整个网格推入堆栈,您可能希望将网格表示为 8 个整数的数组,表示每行的皇后位置。

真正的问题:你的代码太长太复杂了。把事情简单化!女王的问题通常由两个

public static boolean isSolution(final int[] board)
{
    for (int i = 0; i < board.length; i++) {
        for (int j = i + 1; j < board.length; j++) {
            if (board[i] == board[j]) return false;     // same column "|"
            if (board[i]-board[j] == i-j) return false; // diagonal "\"
            if (board[i]-board[j] == j-i) return false; // diagonal "/"
        }
    }
    return true;
}

public static void solve(int depth, int[] board)
{
    if (depth == board.length && isSolution(board)) {
        outputSolution(board);
    }
    if (depth < board.length) {  // try all positions of the next row
        for (int i = 0; i < board.length; i++) {
            board[depth] = i;
            solve(depth + 1, board);
        }
    }
}

添加一些输出代码和一个主程序,你就完成了!

public static void outputSolution(final int[] board)
{
    System.out.println("--- Solution ---");
    for (int i = 0; i < board.length; i++) {
        for (int j = 0; j < board[i]; j++) System.out.print(" ");
        System.out.println("Q");
    }
}

public static void main(String[] args)
{
    int n = 8;
    solve(0, new int[n]);
}

【讨论】:

  • 您好,感谢您的宝贵时间...我必须同意您的代码非常雄辩和简洁,我的第一次尝试失败了,因为以递归方式使用了消耗内存的迭代结构...但是有一次我消除了递归性,我获得了我不那么简洁的代码的好处......例如,对于 n = 10,高度雄辩的运行超过 3 分钟(然后我停止了它),而我的代码花了 3 秒并输出所有解决方案...@stephen c,现在我可以说我非常不同意 ;)
  • 这与简洁与不简洁无关!这只是我的 isSolution() 函数有点愚蠢。它以错误的顺序检查内容,并且不执行部分解决方案的检查。如果你优化它,我的代码会增长大约 1-2 行。
【解决方案2】:

阅读代码,您的程序似乎使用的是 Stack<..> 而不是 Java 递归。因此,它可能是用完 Java 堆空间而不是 Java 堆栈空间。如果是这种情况,您可以使用 -Xms 和 -Xmx 选项来增加初始和最大堆大小。

【讨论】:

  • 但是@vos 是对的,你的算法不优雅而且效率极低,修复它比在问题上投入更多内存更好。
【解决方案3】:

N = 8 时没有理由达到 2298 的堆栈深度!

正确的算法是用一个由 8 个整数组成的数组来表示皇后,每个整数代表第 i 个皇后的行位置(每列皇后)。

您的最大堆栈大小应为 8。

【讨论】:

  • 我达到了 2298 的最大递归深度...不是 2298 的堆栈深度...但堆栈大小小于 n..
【解决方案4】:

在 Java 中,命令 -ss 和 -oss 都可用于更改堆栈大小。

$java -ss156k (native) 
$java -oss600k (Java) 

参数是您想要的堆栈大小,以 kbytes 或 mbytes 为单位。尝试增加一些值,直到不溢出为止。

【讨论】:

  • 您的回答有助于绕过我的 n=8 和 9 问题,但我再次撞到了死墙,但是一旦我消除了求解(resoudre)函数中的递归结构,我就不需要使用这些命令...但是感谢您的帮助:)
猜你喜欢
  • 2020-03-08
  • 2010-11-30
  • 1970-01-01
  • 2016-07-12
  • 2011-09-21
  • 2015-11-14
  • 2014-04-13
  • 1970-01-01
  • 2015-11-22
相关资源
最近更新 更多