簡體   English   中英

迷宮遞歸解決StackOverflow錯誤

[英]Maze recursion solving StackOverflow error

我正在嘗試使用遞歸來解決迷宮問題。 它被宣布為Cell [][] maze

public class Cell {
    private Wall left;
    private Wall right;
    private Wall up;
    private Wall down;
    private boolean end;

    // Setters and getters not shown
}

如果單元格的某一側沒有Wall ,那么它的值為null ,否則它指的是Wall對象。 Wall參考是一致的:與單壁相鄰的兩個單元都用適當的字段表示它。 如果缺少牆,則兩個相鄰單元都具有相應的null條目。 這是搜索:

public boolean solveMaze(Cell[][] maze, int i, int j) {

    if (maze[i][j].isEnd()){
        System.out.println(maze[i][j].toString());
        return true;
    }
    if (maze[i][j].getDown() == null) {
        return solveMaze(maze, i, j + 1); 
    }
    if (maze[i][j].getUp() == null) {
        return solveMaze(maze, i, j - 1) ;
    }
    if (maze[i][j].getLeft() == null) {
        return solveMaze(maze, i - 1, j);
    }
    if (maze[i][j].getRight() == null) {
        return solveMaze(maze, i + 1, j) ;  
    }
    return false;
}

我收到了Stack Overflow錯誤。 我的遞歸停止條件有什么問題?

更新:

有了您非常感謝的幫助,我解決了這個問題:這是正確無誤的解決方案:

public boolean solveMaze(Cell[][] maze, int i, int j){

    if (maze[i][j].isEnd()){
        System.out.println("Maze Exit :["+i+","+j+"]" );
        return true;
    }

    if (maze[i][j].isVisited()){
        return false;
    }

    maze[i][j].setVisited(true);

    if ((maze[i][j].getButtom() == null) ){
        if (solveMaze(maze,i,j+1)==true)
            return true;
    }

    if ((maze[i][j].getUp() == null) ){
    if ( solveMaze(maze,i,j-1) ==true )
        return true;
    }

    if ((maze[i][j].getLeft() == null)){
        if (solveMaze(maze,i-1,j))
            return true;
    }

    if ((maze[i][j].getRight() == null)){
        if (solveMaze(maze,i+1,j)) 
            return true;
    }

    maze[i][j].setVisited(false);
    return false;
} 

可能對未來的任何機構都有幫助。

如果迷宮有一個循環,求解器可以永遠圍繞這個循環運行,這將導致你看到的堆棧溢出。 您需要一種方法來確定何時看到已經看過的迷宮廣場。 在這種情況下,您應該立即回溯。

這可以通過在最初設置為false的每個單元格中visited的布爾標志然后為您搜索的每個方塊設置為true來完成,或者您可以維護已搜索的單獨的一Set (i,j)對,最初為空。

注意:你對ij使用是非常規的。 如果其他人用常規用法編寫了迷宮閱讀代碼,這可能會導致問題。 在數學中, i通常用於行號, j用於列。 根據此慣例,您的牆壁測試不同意您的增量和減量。 如果缺少底壁,則需要增加i

在我看來,就像你在解算器方法中運行一樣。
我建議你熟悉廣度優先搜索 ,這通常用於不太大的狀態搜索問題。

如果你有一些“知識”,一個啟發式,如何搜索迷宮,那么你也可以看看A-Star搜索


在你的情況下,BFS可以做的是:(順便說一句,很好,並使用適當的建設者,吸氣劑和制定者)

public class Cell {
    public int x;
    public int y;
    public Cell parent;

    @Override
    public boolean equals(Object obj) {
        // TODO Override equals so it only incudes x and y coorinates, and not parent
        return true;
    }

    @Override
    public int hashCode() {
        // TODO Override hash code as well
        return 0;
    }
}

public Cell seachFor(Cell start, Cell finish) {
    Queue<Cell> open = new LinkedList<>();
    Set<Cell> closed = new HashSet<>();

    open.add(start);

    while (!open.isEmpty()) {
        Cell current = open.poll();
        if (current.equals(finish)) {
            return current;
        }

        closed.add(current);

        for (Cell neighbour : getNeighbours(current)) {
            if (!closed.contains(neighbour)) {
                open.add(neighbour);
            }
        }
    }

    return null;

}

private List<Cell> getNeighbours(Cell current) {
    /* TODO Set the neighbour's "parent"
     * Return valid adjacent neighbour cells
     */
    return null;
}

public Deque<Cell> pathfinder(Cell start) {
    Deque<Cell> path = new ArrayDeque<>();
    path.push(start);

    Cell current = start;

    while (current.parent != null) {
        current = current.parent;
        path.push(current);
    }

    return path;
}

public static void main(String[] args) {
    Cell start = maze.getStart();
    Cell finish = maze.getFinish();
    Deque<Cell> path = pathFinder(searchFor(start, finish))
    while (!path.isEmpty()) {
        Cell current = path.pop();
        maze.moveTo(current);
    }
}

請注意,這是一個模擬代碼,您需要在它工作之前對其進行優化。

您的代碼中沒有任何內容可以檢測您之前已經存在的位置。 如果你的迷宮包含任何你可以進入一個圓圈或循環回到你之前沒有回溯的地方的段落,它將繼續無限地沿着同一條路徑遞減。

你在堆棧上分配的內存耗盡。 也就是說,如果在給定時間超過JVM的資源,則遞歸速度過快。

你可以增加內存然后殺死這個方法的所有其他迭代,或者更改你的算法。 更改stacksize將是一個糟糕的解決方案但它可能工作,即使您的代碼如果有缺陷如何增加eclipse中的堆棧大小我會建議標記您已經訪問過哪些區域

迷宮是Cell[][] maze

  public class Cell{
    boolean visited = false;
    Wall left;
    Wall right;
    Wall up;
    Wall bottom;
    boolean end;

    //Settters and Getters
    }

每次點擊變量時將訪問變量設置為true,然后將代碼更改為

public boolean solveMaze(Cell[][] maze, int i, int j){
        if (maze[i][j].isEnd()){
            System.out.println(maze[i][j].toString());
            return true;
        }
        if (maze[i][j].getButton() == null)&&(maze[i][j].visited==false)){
            return solveMaze(maze,i,j+1); 
        }

        if (maze[i][j].getUp() == null){
        return solveMaze(maze,i,j-1) ;
        }
        // ect 

我不會實施它,除非你自己有問題,面試問題我覺得它很整潔如果你自己解決它們的提示,你會覺得你可以再次解決類似問題,如果你只是閱讀並理解答案你也許能夠重申同一問題的答案,但你可能無法用類似的策略想出一個類似問題的新穎答案。

首先,你走下去,直到你到達牆。 然后,一個 - 然后再次下降。 一個向上,一個向下 - 直到java檢測到這是非常愚蠢的並且停止了StackOverFlowError;)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM