【问题标题】:Maze solver issue (Getting stack overflow error)迷宫求解器问题(出现堆栈溢出错误)
【发布时间】:2026-01-22 11:20:06
【问题描述】:

所以我们得到了一个带有墙壁(W)开放路径(O)的迷宫,起始点(S)和结束点(F)。

我正在尝试编写一个算法,该算法采用迷宫文件,然后将其转换为二维点数组来制作网格。

一旦我有了网格,我想从迷宫中的“S”字符开始,并尝试找出是否可以穿过 O 到达 F。(返回布尔值 true/false )

我知道这个迷宫是可以解决的,为什么我会收到 *Error..?

这是 Maze1.txt 文件:

WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
WSOOOOOOOOOOOOOOWOOOOOOOOOOOOOOOOOWOOOOOOOOOOOOOOOWOOOOOOW
WWOOOOOOOOOOOOOWWWWWWWWWWWWWOOOOOOOOOOWWWWWWWWWWWWWOOOOOOW
WWWWWWOOOOOOOOOOOOWWWWWWWOOOOOOOOOOOOWWWWWWWWWWWWWWWWOOOOW
WOOOOOOWWWWWWWWWWWWWWOOOOOOOOOOOWWWWWWWWOOOOOOOOOOOOOOOWWW
WOOOOWWWWWWWOOOOOOWWWWOOOOOOWWWWWWWWWWWOOOOWWWWWWWWWOWWWWW
WOOOWWWWWWWWWWWWOOWWWWWWWWWWWWOOOOOOOOOOOOWWWWWWWWWOOOOOWW
WOOWWWWWWWWWWWWWOOWWWWWWWWWWWWWWWWWOOOOOOOWWWWWWWWWWWWOOOW
WOWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWOOOOOOOWWWWWWWWWWWOOW
WOWWWWWWWWWWWWWOOOOOOOOOOOOOOOOOOOOOOOOOOOOWWWWWWWWWWWWOOW
WOOOOOOOOOOOOOOOOWWWWOOOOOOOOWWWWWWWOOOOOOWWWWWWWWWWWWWOFW
WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW

这是我的代码(新尝试):

import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Stack;
import java.awt.Point;


public class MazeExplorer {
    static Point startPoint = new Point();
    static Point finishPoint = new Point();
    final static int mazeHeight = 12;
    final static int mazeWidth = 58;
    static char[][] mazePoints = new char[mazeHeight][mazeWidth];
    Stack<Point> pointsNotTraversed = new Stack<Point>();
    Point pt = new Point();
    static HashSet<Point> previousLocations = new HashSet<Point>();
    static Stack<Point> nextPoints = new Stack<Point>();


    public static void main(String[] args) throws FileNotFoundException{

        System.out.println("Please enter the file name of your Maze");
        Scanner console = new Scanner(System.in);
        File f = new File(console.nextLine());
        Scanner sc = new Scanner(f);

        if(!sc.hasNextLine()){
            System.out.println("Sorry, please enter a file name with the extension, that contains a maze!");
        }

        System.out.println("So, you want to know if your maze is solvable.....?");


        for (int row = 0; row < mazeHeight && sc.hasNext(); row++) {
            final String mazeRow = sc.next(); //Get the next row from the scanner.
            mazePoints[row] = mazeRow.toCharArray(); //Convert the row into a char[].
        }

            //identify the finish point
        for(int i = 0; i < mazeHeight; i++){
            for(int j = 0; j<mazeWidth; j++){
                if(mazePoints[i][j] == 'F'){
                    finishPoint = new Point(i, j);

                }

            }
        }

        // Identify the start point
       for(int i = 0; i< mazeHeight; i++){
           for(int j = 0; j < mazeWidth; j++){
               if(mazePoints[i][j] == 'S'){
                 startPoint = new Point(i , j);

               }
           }
       }

       isTraversable(startPoint);

    }

        public static  boolean isTraversable(Point current){

            boolean isSolvable = false;

            do {
                mazePoints[current.x][current.y] = ' ';

                if (mazePoints[current.y - 1][current.x] == 'O'){ //up dir
                   nextPoints.push(new Point(current.y - 1, current.x));
                    mazePoints[current.y - 1][current.x] = ' ';  //'X' marks where you've already been


                }
                if(mazePoints[current.y + 1][current.x] == 'O'){ // below direction
                    nextPoints.push(new Point(current.y + 1, current.x));
                    mazePoints[current.y + 1][current.x] = ' ';


                }
                if(mazePoints[current.y][current.x + 1] == 'O'){ // to the right
                    nextPoints.push(new Point(current.y, current.x + 1));
                    mazePoints[current.y][current.x + 1] = ' ';


                }
                if(mazePoints[current.y][current.x - 1] == 'O'){ // to the left
                    nextPoints.push(new Point(current.y, current.x - 1));
                    mazePoints[current.y][current.x - 1] = ' ';


                }
                if(mazePoints[current.y][current.x] == 'F'){
                    isSolvable = true;
                    System.out.println("MAZE IS SOLVABLE, YAHOOOOOO!!!!!!");
                }

                current = nextPoints.peek();
                nextPoints.pop();
                isTraversable(current);


            } while(!current.equals('F') && !nextPoints.isEmpty()); 


            return isSolvable;

            }

}

【问题讨论】:

  • 开始和结束应该在边缘,不是吗?
  • 对不起,我刚刚去编辑了我的代码,如果你想尝试帮助,请查看这个新版本。 (我原来有很多错误)
  • 哦,不,他们不是。(别问我,这是我们被给予的方式哈哈)
  • 您在上面/下面/左/右方法中修改同一个 Point 对象。您需要使用新坐标创建一个新的 Point 对象。 (对不起,我现在没有时间了;祝你好运)。
  • 看来你的递归调用太频繁了。尝试改进该功能,或者使用递归以外的其他形式(backtrackingwavefront algorithms 怎么样?)编辑:哦,在我写我的时候有很多 cmets。对于堆空间错误,您可以assign more memory 到您的 JVM。

标签: java stack


【解决方案1】:

您收到堆栈溢出错误的原因如下:

public static  boolean isTraversable(Point current){
        boolean isSolvable = false;
        Stack<Point> dumbPoints = new Stack<>(); // visited
        dumbPoints.push(current); // pt is now visited
        previousLocations.add(startPoint); // starts with the 'S' point
        while(!dumbPoints.isEmpty()){
            Point test = dumbPoints.pop();
            if(previousLocations.contains(test)){
                continue; // This gets called, and while loop skips to next iteration
            }
          /* None of this code matters right now, it never gets looked at */

        } // End of while loop

        isTraversable(current);
        return isSolvable;
        }

您将startPoint 发送到isTraversable() 方法。在方法内部,它被称为current。然后将current AKA startPoint 推入堆栈,然后将startPoint 添加到previousLocations 集合中。

while 循环运行是因为dumbPoints 不为空(您将current AKA startPoint 放在那里)。

在 while 循环中创建一个新点 test 并将其设置为等于堆栈中的顶部项目(即 current,AKA startPoint)。

你查看if(previousLocations.contains(test)) 是真的,它是。您将startPoint 添加到previousLocations 设置3 行。因为它确实包含startPoint,所以它继续到while循环的下一次迭代。

下次进入 while 循环时,堆栈为空,因为您弹出了其中唯一的项目 (test)。所以这次 while 循环没有被执行。

然后我们跳到while循环之后的下一行:

isTraversable(current);

这又重新开始了我刚才所说的一切。这将永远运行,直到您的计算机内存不足。因此你的错误。

建议 我建议尝试不同的方法。我相信你昨天问了一个关于这个问题的问题,其他人建议将所有相邻点推入堆栈。我认为这是个好主意。除了将当前项目推入堆栈之外,您还可以将所有相邻的 O 推入堆栈,然后在这些点上递归调用 isTraversable 方法。这将一直持续到返回 true 或 false 并且您将得到答案。

这可能是您可以使用的更简洁的方法之一,与您已经创建的代码相差不远。

【讨论】:

  • 是的,非常感谢您对新方法的建议。请查看我的代码以获取您的建议....(请参阅编辑)
  • 看起来你现在正在努力寻找 x,y 坐标和 Point 对象之间的链接。将 2D 数组设为 MazeSquare 对象数组可能会更容易一些。每个方块都有一个值:O、W、S 或 F,以及一个 X 和 Y 值,表示其在数组中的位置。您不能将迷宫的值更改为 X 来标记访问过的位置。如果一个 O 可以在所有 4 个方向上移动(可能是迷宫的交叉点),那么你会将它变成一个 X,并且永远不会被允许返回并访问其他方向。
  • 我写了另一个版本,我真的不想改变我的结构上的所有这些......现在怎么样了?我能用它做些什么吗?我得到一个数组索引越界异常