java - java递归数独求解器中的堆栈溢出错误

标签 java recursion stack-overflow sudoku

我对一般编码还很陌生,我现在正在用 java 编写一个递归数独求解器。然而,我不断收到 Stack Overflow 错误,而且我一辈子都无法找出原因。

这是完整的代码。据推测,错误在于各种求解方法。

import java.util.*;
public class sudoku{

protected static int n;
protected static int[][] game;

public static boolean checkRow(int a, int b){
    boolean z = true;
    for(int i=0;i<n;i++){
        if(i==b) continue;
        else if(game[a][b]==game[a][i]){
            z = false;
            break;
        }
    }
    return(z);
}

public static boolean checkColumn(int a, int b){
    boolean z = true;
    for(int i=0;i<n;i++){
        if(i==a) continue;
        else if(game[i][b]==game[a][b]){
            z = false;
            break;
        }
    }
    return(z);
}

public static boolean checkBox(int a, int b){
    boolean z = true;
    int x = (int)Math.sqrt(n)*(int)(a/Math.sqrt(n));
    int y = (int)Math.sqrt(n)*(int)(b/Math.sqrt(n));
        for(int i=x;i<x+Math.sqrt(n);i++){
            for(int j=y;j<y+Math.sqrt(n);j++){
                if(a==i&&b==j) continue;
                else if(game[a][b]==game[i][j]){
                    z = false;
                    break;
                }
            }
        }
    return(z);
}

public static boolean checkAll(int a, int b){
    return(checkRow(a,b)&&checkColumn(a,b)&&checkBox(a,b));
}

public static void solvePrevious(int row, int col){
    if(row==0&&col==0){
        System.out.println("This game is unsolvable.");
        return;
    }
    else if(col==0) solve(row-1,n-1,game[row-1][n-1]+1);
    else solve(row,col-1,game[row][col]+1);
}

public static void solveNext(int row, int col){
    if(row==n-1&&col==n-1) return;
    else if(col==n-1) solve(row+1,0,1);
    else solve(row,col+1,1);
}

public static void solve(int row, int col, int value){
    if(value<=n){
        game[row][col] = value;
        if(checkAll(row,col)) solveNext(row,col);
        else solve(row,col,value+1);
    }
    else solvePrevious(row,col);
}

public static void main(String[] args){
    Scanner inp = new Scanner(System.in);
    System.out.println("What is the side length of the puzzle?");
    n = 0;
    do{
        n = inp.nextInt();
        if(Math.sqrt(n)%1!=0) System.out.println("The side length must be a perfect square.");
    }while(Math.sqrt(n)%1!=0);
    game = new int[n][n];
    solve(0,0,1);
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            System.out.print(game[i][j]+" ");
        }
        System.out.println(" ");
    }
}

}

最佳答案

我认为您不需要从 solve 方法调用 solvePrevious

我对方法名称有点困惑 - “上一个”可能意味着“上一个单元格”或“同一单元格的上一个编号”。这是你可以改进的地方。

基本思想应该是这样的:

/* in main: */
solve(0, 0, 1);

solve(row, col, num) {
  if (checkAll(row, col)) {
    solveNextCell(row, col);
  }
  if (num < n * n) {
    solve(row, col, num + 1);
  }
}

solveNextCell(row, col) {
  if (row == n - 1 && col == n - 1)
    printSolution();
  else if (col == n - 1)
    solve(row + 1, 0, 1);
  else
    solve(row, col + 1, 1);
}

这样,您只需“向前搜索”。由于这两个方法递归地相互调用,因此调用层次结构会隐式记住所有“先前”步骤。

但即便如此,你的程序也会运行很长很长的时间,至少对于最初的空板来说是这样。这是因为它会尝试第一行每个字段中的每个数字,即 9^9 = 387420489。假设第二行也有同样多的位置,尝试的次数就会增加到150094635296999121,这个数字太大了,我不知道如何发音。这只是 9 行中的第 2 行。

所以我建议你采取完全不同的方法:一旦你填写了一个数字,你就在相应的行、列和框中将该数字标记为禁止。这样,您就不必每次都循环遍历所有行、列和框。当我编写数独解算器时,我成功地记住了每个单元格中哪些数字仍然是可能的,并在开始递归和尝试每个可能的数字之前尽可能排除它们。

关于java - java递归数独求解器中的堆栈溢出错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36803835/

相关文章:

java - 找不到 JRE/java 命令

c - 使用递归错误反转链表

python - Python数组中的所有值递归相乘

compiler-construction - 一种语言的编译器如何用该语言编写?

c - C中内存中的局部变量存储

java - 如何在我的登录和注册页面更改密码?

java - 如何使用 Java 从 Sqlite3 数据库中获取解析后的数据?

java - @ModelAttribute 注释方法在方法签名中带有@ModelAttribute

c - 大数组不会导致堆栈溢出

Java HW StackOverflowError 与从书中复制的 Max Subarray 伪代码