Java深度优先搜索(DFS)迷宫算法空指针异常排查求助
迷宫DFS算法空指针异常排查
运行以下Java迷宫DFS求解代码时,抛出空指针异常:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "depthfirstsearch.NodeClass.getState()" because "currentNode" is null
但在循环内部打印currentNode时,发现它并非null,现需排查问题原因及解决建议。
完整代码
//Upgraded dfs algorithm that creates an array of nodeclass objects package depthfirstsearch; public class DepthFirstSearch { public static void main(String[] args) { int[][] stateArr = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 2, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0}, {0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0}, {0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0}, {0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0}, {0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0}, {0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0}, {0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0}, {0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0}, {0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, {0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0}, {0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0}, {0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0}, {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0}, {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; //Maze array declaration int mazeRows = stateArr.length; int mazeCols = stateArr[0].length; //Creates an array of NodeClass objects NodeClass[][] mazeArr = new NodeClass[mazeRows][mazeCols]; //Assigning values to the nodes (state, isPath, coords) for(int i = 0; i < mazeRows; i++) { for(int j = 0; j < mazeCols; j++) { int state = stateArr[i][j]; mazeArr[i][j] = new NodeClass(i, j, state); //Assigning coordinates & state (wall, path) to the node } //End of col for-loop } //End of row for-loop //Currently have an array of nodes with coordinates, state and isPath = false NodeClass currentNode = mazeArr[1][1]; //This is the node we'll be working with. Assigned the value of the starting node at position (1;1) while(currentNode.getState() != 3) //3 Indicates the end of the maze. While we haven't reached the end { //Getting the position of the current node int row = currentNode.getNodeRow(); int col = currentNode.getNodeCol(); System.out.println("Run"); System.out.println(currentNode); //We'll be taking the currentNode and checking every unchecked adjacent node: //Check up if((mazeArr[row-1][col].getState() == 1 || mazeArr[row-1][col].getState() == 3) && (mazeArr[row-1][col].haveTried() == false)) { //Storing the parent node: NodeClass temp = currentNode; //Stores the current node as the node temp mazeArr[row-1][col].setParentNode(temp); //Stores the current node as the parent node the new checked node mazeArr[row][col].setTried(true); //Sets the current node as tried mazeArr[row][col].setIsPath(true); //Considers the current node as a potential path currentNode = mazeArr[row-1][col]; //The new current node is the node above the original node System.out.println("Up"); //We moved up } //Check right else if((mazeArr[row][col+1].getState() == 1 || mazeArr[row][col+1].getState() == 3) && (mazeArr[row][col+1].haveTried() == false)) { //Storing the parent node: NodeClass temp = currentNode; //Stores the current node as the node temp mazeArr[row-1][col].setParentNode(temp); //Stores the current node as the parent node the new checked node mazeArr[row][col].setTried(true); //Sets the current node as tried mazeArr[row][col].setIsPath(true); //Considers the current node as a potential path currentNode = mazeArr[row][col+1]; //The new current node is the node above the original node System.out.println("Right"); //We moved right } //Check down else if((mazeArr[row+1][col].getState() == 1 || mazeArr[row+1][col].getState() == 3) && (mazeArr[row+1][col].haveTried() == false)) { //Storing the parent node: NodeClass temp = currentNode; //Stores the current node as the node temp mazeArr[row+1][col].setParentNode(temp); //Stores the current node as the parent node the new checked node mazeArr[row][col].setTried(true); //Sets the current node as tried mazeArr[row][col].setIsPath(true); //Considers the current node as a potential path currentNode = mazeArr[row+1][col]; //The new current node is the node below the original node System.out.println("Down"); //We moved down } //Check left else if((mazeArr[row][col-1].getState() == 1 || mazeArr[row][col-1].getState() == 3) && (mazeArr[row][col-1].haveTried() == false)) { //Storing the parent node: NodeClass temp = currentNode; //Stores the current node as the node temp mazeArr[row][col-1].setParentNode(temp); //Stores the current node as the parent node the new checked node mazeArr[row][col].setTried(true); //Sets the current node as tried mazeArr[row][col].setIsPath(true); //Considers the current node as a potential path currentNode = mazeArr[row][col-1]; //The new current node is the node left of the original node System.out.println("Left"); //We moved left } //If there are no paths left: we reached a dead end and need to back track else { mazeArr[row][col].setTried(true); //Sets the current node as tried mazeArr[row][col].setIsPath(false); //Since it's a dead end, we remove it from the potential solution currentNode = mazeArr[row][col].getParentNode(); //Sets the current node as the previous node } } //End of while-loop for finding the solution System.out.println("Yay yay, we did it!"); } //End of main method } //End of DepthFirstSearch Class
问题原因
- 回溯时currentNode变为null:起始节点
mazeArr[1][1]的parentNode初始为null。当算法回溯到起始节点且没有可走路径时,执行currentNode = mazeArr[row][col].getParentNode()会将currentNode赋值为null。而空指针异常是在while循环条件判断时触发的(currentNode.getState()),你在循环内部打印currentNode的时机早于这个判断,所以看不到null的情况。 - 分支中parentNode赋值错误:在
Check right分支里,错误地将mazeArr[row-1][col]的parentNode设置为当前节点,而不是应该移动到的mazeArr[row][col+1]。这个错误会导致部分节点的父节点未正确设置,加剧回溯时的null问题。 - 无边界校验:检查上下左右方向时,未判断坐标是否越界(比如
row-1可能为-1,col+1可能超出数组长度),这会引发其他潜在异常。
排查与修复建议
- 修复parentNode赋值错误:检查四个方向的分支,确保给对应方向的节点设置父节点。比如
Check right分支中,将mazeArr[row-1][col].setParentNode(temp)改为mazeArr[row][col+1].setParentNode(temp)。 - 循环条件增加非空判断:将while循环条件改为
while(currentNode != null && currentNode.getState() != 3),避免currentNode为null时调用getState()。 - 处理起始节点回溯边界:可以给起始节点设置一个特殊的父节点(比如自身),或者在回溯分支中判断如果当前节点是起始节点且无路径,直接终止循环。
- 添加回溯调试日志:在else回溯分支中打印当前节点及其父节点,比如:
这样能清晰追踪currentNode何时变为null。System.out.println("回溯节点:" + currentNode + ",父节点:" + currentNode.getParentNode()); - 增加边界校验:每个方向判断前先检查坐标是否合法,比如
Check up的条件先加row-1 >= 0:if(row-1 >= 0 && (mazeArr[row-1][col].getState() == 1 || mazeArr[row-1][col].getState() == 3) && !mazeArr[row-1][col].haveTried())
内容的提问来源于stack exchange,提问作者LonelyBoi404
相关产品推荐
相关产品推荐

