Java八皇后问题递归无输出解排查:递归是否仅走单一路径?
你的八皇后问题无输出?我帮你揪几个关键bug
嘿,刚重新学Java就练八皇后,挺棒的!我看了你的代码片段和疑问,大概率是这几个问题导致没输出解,甚至让你觉得递归只走单一路径:
1. 二维数组克隆踩了浅拷贝的坑
你写的char[][] newBoard = board.clone();是个典型的新手坑——Java里二维数组的clone()只会克隆外层数组,里面的每一行还是和原board共用同一个数组对象。也就是说,你改newBoard[row][i]的时候,原board的对应位置也会被改掉!这直接打乱了回溯逻辑,后续递归的位置判断全错了,看起来就像递归只走了一条路。
正确的深拷贝应该逐行复制:
char[][] newBoard = new char[board.length][]; for (int j = 0; j < board.length; j++) { newBoard[j] = board[j].clone(); // 把每一行单独克隆一遍 }
2. 递归终止条件大概率没写
你没贴全代码,但八皇后递归必须有终止条件:当row == 8(所有行都放好皇后)时,要打印当前棋盘。如果没这个逻辑,就算递归走通了,也不会有任何输出。比如在solve方法开头加:
if (row == 8) { printBoard(board); // 自己写个打印棋盘的方法 return; }
3. 关于你问的「递归是否仅走单一路径」
正常八皇后是回溯递归:每一行尝试所有合法列,放皇后后递归下一行,递归返回后回溯恢复状态。但你因为浅拷贝污染了原棋盘,导致后续列的尝试都在被修改过的棋盘上进行,自然走不通其他路径。另外,如果你invalidate方法没正确标记皇后的攻击范围(同一列、两条对角线),那后续行找不到合法位置,递归就提前终止了,也会没输出。
给你个修正后的核心代码参考
我把关键部分改好,你可以对照着调:
public void solve(char[][] board, int row) { // 终止条件:所有行都放完皇后,输出解 if (row == board.length) { printBoard(board); return; } for (int col = 0; col < 8; col++) { // 先判断当前位置能不能放皇后(比直接看board[row][col]更可靠) if (canPlaceQueen(board, row, col)) { // 深拷贝棋盘,避免污染原数据 char[][] newBoard = new char[8][]; for (int j = 0; j < 8; j++) { newBoard[j] = board[j].clone(); } // 放皇后 newBoard[row][col] = 'q'; // 标记攻击范围(或者你也可以每次判断时实时检查,不用提前标记) markInvalidPositions(newBoard, row, col); // 递归处理下一行 solve(newBoard, row + 1); } } } // 检查(row,col)能不能放皇后 private boolean canPlaceQueen(char[][] board, int row, int col) { // 检查同一列有没有皇后 for (int i = 0; i < row; i++) { if (board[i][col] == 'q') return false; } // 检查左上到右下的对角线 for (int i = row-1, j = col-1; i >=0 && j >=0; i--, j--) { if (board[i][j] == 'q') return false; } // 检查右上到左下的对角线 for (int i = row-1, j = col+1; i >=0 && j <8; i--, j++) { if (board[i][j] == 'q') return false; } return true; } // 打印棋盘的辅助方法 private void printBoard(char[][] board) { for (char[] row : board) { System.out.println(new String(row)); } System.out.println("=========="); }
这样改完后,应该就能看到八皇后的所有解输出了。
内容的提问来源于stack exchange,提问作者Joe
相关产品推荐
相关产品推荐

