我正在尝试使用Java编写一个数独解题程序。我使用了一个常见的回溯算法,但程序运行不正常(返回null值)
这是代码
public class Sudoku { int[][] board; //Sudoku board public Sudoku() { //constructor this.board = new int[9][9]; for(int i=0;i<9;i++) for(int j=0;j<9;j++) board[i][j]=0; } public Sudoku(int[][] board){ //constructor this.board=board; } public int[][] Solve(int[][] board){ int i, j, k,l,val; //iterators int empty=1; //empty flag int[][] temp=new int[9][9]; //temporary array for backtracking temp=board; for(i=0;i<9;i++) //check if any empty space available for(j=0;j<9;j++){ if(board[i][j]==0){ empty=0; break; } } if(empty==1)return board; for(i=0;i<9;i++) outerLoop: for(j=0;j<9;j++){ if(board[i][j]>0)continue; for(val=1;val<10;val++){ //try values for(k=0;k<9;k++){ if(board[i][k]==val)break; //check row consistancy if(board[k][j]==val)break; //check column consistancy } for(k=(i/3)*3;k<(i/3+1)*3;k++) //check latin square consistancy for(l=(j/3)*3;l<((j/3+1)*3);l++) if(board[k][l]==val)break; temp[i][j]=val; //put consistant value Solve(temp); //recursive call for backtrack } } return null; } public static void main(String[] args) { // TODO code application logic here int[][] board={ {5,3,0,0,7,0,0,0,0}, {6,0,0,1,9,5,0,0,0}, {0,9,8,0,0,0,0,6,0}, {8,0,0,0,6,0,0,0,3}, {4,0,0,8,0,3,0,0,1}, {7,0,0,0,2,0,0,0,6}, {0,6,0,0,0,0,2,8,0}, {0,0,0,4,1,9,0,0,5}, {0,0,0,0,8,0,0,7,9}}; Sudoku s=new Sudoku(board); int[][] temp=new int[9][9]; temp=s.Solve(board); for(int i=0;i<9;i++){ System.out.println(""); for(int j=0;j<9;j++){ System.out.print(temp[i][j]); System.out.print(","); } } } }
我根据NetBeans的建议添加了返回null的语句,但它应该永远不会返回null。我找不到错误。提前感谢您的帮助。
回答:
我将专注于你的Solve(int[][])
方法:
public int[][] Solve(int[][] board){
根据Java命名 conventions,方法名应该使用驼峰命名法:solve(int[][] board)
int i, j, k,l,val;
除非必要,你不应该在方法开始时定义迭代器。这会给它们一种“虚假的目的感”,使代码更难理解。
int empty=1;
这应该是一个布尔值,因为它只会持有1或0的值。布尔值在这里会更易读:boolean empty = false;
int[][] temp=new int[9][9]; temp=board;
此外,我建议将你的代码分成“段落”或相关操作。这是一个从定义转向一些初始逻辑的好地方,可以开始新的一段。
for(i=0;i<9;i++) for(j=0;j<9;j++){ if(board[i][j]==0){ empty=true; break; } } if(!empty)return board;
这应该作为一个独立的段落,因为它处理单一任务,即检查棋盘是否已解决。我还更新了它以展示布尔值如何读起来更清晰。
for(i=0;i<9;i++) outerLoop: for(j=0;j<9;j++){ if(board[i][j]>0)continue; for(val=1;val<10;val++){ for(k=0;k<9;k++){ if(board[i][k]==val)break; if(board[k][j]==val)break; } for(k=(i/3)*3;k<(i/3+1)*3;k++) for(l=(j/3)*3;l<((j/3+1)*3);l++) if(board[k][l]==val)break; temp[i][j]=val; Solve(temp); } } return null; }
你的代码有两个返回语句,一个用于完成的棋盘,另一个用于捕获逻辑错误。错误在于你的递归调用。仅仅调用Solve(temp);
不会保留你对数据所做的任何更改。递归函数只有在使用递归调用生成的新信息时才有效。因此,为了修复你的错误,返回你的递归调用:
return Solve(temp);