【问题标题】:Why isn't my recursive method base case not returning a Boolean as it should be?为什么我的递归方法基本案例没有返回应有的布尔值?
【发布时间】:2021-02-08 09:45:52
【问题描述】:

我写了一个方法,通过堆栈和递归解决给定的文本编辑器迷宫,它解决了迷宫。但是,我的问题是,当给出的迷宫无法解决时,因为迷宫的墙壁实际上是不可能解决的,就好像我的基本情况被跳过并且不返回错误一样。这是代码

 private boolean findPath(MazeLocation cur, MazeLocation finish) {
        int row = cur.row;
        int col = cur.col;
        mazeToSolve.setChar(row, col, 'o');
        fileWriter.println("\n"+mazeToSolve.toString());
        char strX = 'X';
        char strH = 'H';

        // First ,we need to scan the 4 directions around current location to see where to go
        MazeLocation up = new MazeLocation(row-1, col);
        MazeLocation down = new MazeLocation(row+1, col);
        MazeLocation right = new MazeLocation(row, col+1);
        MazeLocation left = new MazeLocation(row, col-1);

        // BASE CASE - WHEN WE'VE REACHED FINISH COORDINATES
        if(cur.row == finish.row && cur.col == finish.col){
            return true;
        }
        // SECOND BASE CASE - IF MAZE ISNT SOLVABLE
        if (path.isEmpty() == true){ // if the path is empty, then there is no solution.
            return false;
        }

        // Check if we can go up
        if(up.getRow() >= 0){
            if(mazeToSolve.getChar(up.getRow(), up.getCol()) == ' '){
                row = up.getRow();
                col = up.getCol();
                MazeLocation newCur = new MazeLocation(row, col);
                path.push(newCur);
                return findPath(newCur, finish);
            }
        }

        // Check if we can go down
        if(down.getRow() < mazeToSolve.getRows()){
            if(mazeToSolve.getChar(down.getRow(), down.getCol()) == ' '){
                row = down.getRow();
                col = down.getCol();
                MazeLocation newCur = new MazeLocation(row, col);
                path.push(newCur);
                return findPath(newCur, finish);
            }
        }

        // Check if we can go right
        if(right.getCol() < mazeToSolve.getCols()){
            if(mazeToSolve.getChar(right.getRow(), right.getCol()) == ' '){
                row = right.getRow();
                col = right.getCol();
                MazeLocation newCur = new MazeLocation(row, col);
                path.push(newCur);
                return findPath(newCur, finish);
            }
        }

        // Check if we can go left
        if(left.getCol() >= 0){
            if(mazeToSolve.getChar(left.getRow(), left.getCol()) == ' '){
                row = left.getRow();
                col = left.getCol();
                MazeLocation newCur = new MazeLocation(row, col);
                path.push(newCur);
                return findPath(newCur, finish);
            }
        }

         // If we cant do any of the above then we need to backtrack by popping the top of stack
         // and leaving X's until we can move up, down, left, or right again.
         MazeLocation newCur = new MazeLocation(row, col);
         path.pop(); // popping the cur where we are putting the x
         mazeToSolve.setChar(row, col, 'x'); // putting the x
         return findPath(path.top(), finish); // now we need to return to the position where the stack is NOW after the pop
    }

如您所见,有两种基本情况。一个返回真 - 迷宫解决了。另一个返回 false - 迷宫是无法解决的。我的 isEmpty() 方法的代码是这样的:

public boolean isEmpty() {
        if(head == null){
            return true;
        }
        return false;
    }

它通过检查堆栈是否为空来返回 false。例如,如果迷宫跑步者撞到墙壁并转身,它将在文本编辑器中留下一个 x,如下所示:

 0123456
0HHHHHHH
1ooooxxH
2HHHoHxH
3H  oHxH
4H HoHHH
5H Hoooo
6HHHHHHH

迷宫从 6,5 开始;并在 0,1 结束。这是可以解决的。 x 代表失败的路线,o 代表从开始到结束的路径。

在下一个示例迷宫中,当代码从 7,6 开始时,不可能完成。

HHHHHHH
      H
HHH H H
H   H H
H HHHHH
H H    
HHHHHHH

它会尝试向左移动两次,留下 x,然后堆栈会弹出,直到没有堆栈并且堆栈的顶部指向 null。但是我的基本案例代码被跳过了,它应该在尝试弹出空堆栈之前测试堆栈是否为空,如果是,则返回 false。但事实并非如此。有什么帮助吗?

【问题讨论】:

  • 这似乎无法编译,因为没有声明“路径”
  • 从 (7,6) 开始迷宫有没有位置?
  • 它会编译,path 是在另一个方法中声明的 Stack 对象。 Eklavya 是什么意思?
  • 您是否为您的项目使用了特定的库?
  • 不,@bdzzaid 没有什么特别的,一定是函数出了问题,导致它跳过为 isEmpty() 返回 false。我已经单独测试了 isEmpty() 并且它有效。

标签: java recursion stack maze


【解决方案1】:

首先,让我们先尝试理解问题陈述。我们正在尝试在这里使用深度优先方法找到从源到目标的可能路径。

算法中存在一个主要缺陷

        // Check if we can go up
        if(up.getRow() >= 0){
            if(mazeToSolve.getChar(up.getRow(), up.getCol()) == ' '){
                row = up.getRow();
                col = up.getCol();
                MazeLocation newCur = new MazeLocation(row, col);
                path.push(newCur);
                return findPath(newCur, finish);
            }
        }

        // Check if we can go down
        if(down.getRow() < mazeToSolve.getRows()){
            if(mazeToSolve.getChar(down.getRow(), down.getCol()) == ' '){
                row = down.getRow();
                col = down.getCol();
                MazeLocation newCur = new MazeLocation(row, col);
                path.push(newCur);
                return findPath(newCur, finish);
            }
        }

考虑我们目前在点 (2,2) 并且可以选择在 4 个方向中的任何一个方向上移动,即 (1,2) , (3,2) , (1,3) , (2,1) .

按照你的逻辑。我们首先向上移动 (1,2)

可能有两种可能性。

  1. 您从该点找到一条路径(返回 true)
  2. 您没有找到路径并想继续搜索其他三个选项。 (返回假)

如果路径导致失败,您的代码目前不会探索更多选项 由于return语句

return findPath(newCur, finish);

这个问题归结为在所有操作完成之前提前退出方法。

必须在当前仅在其中一种场景中调用的方法的任何返回语句之前调用以下堆栈清理

// If we cant do any of the above then we need to backtrack by popping the top of stack
// and leaving X's until we can move up, down, left, or right again.

path.pop(); // popping the cur where we are putting the x

这里我还是没完全理解显式栈的用法。因为递归解决了您尝试使用堆栈解决的类似问题。但是, 我想围绕以下几行提出改进建议。

// Check if we can go up
        if(up.getRow() >= 0){
            if(mazeToSolve.getChar(up.getRow(), up.getCol()) == ' '){
                row = up.getRow();
                col = up.getCol();
                MazeLocation newCur = new MazeLocation(row, col);
                path.push(newCur);
                boolean val =  findPath(newCur, finish);
                if(val){
                  path.pop();
                  return true;
                }

            }
        }

【讨论】:

  • 感谢您的帮助,但对我没有帮助。同样,这是我的代码的工作方式:迷宫开始,迷宫在各个方向搜索路径,并沿着可用的开放路径直到死胡同或到达迷宫的终点。它使用堆栈执行此操作,每个坐标都添加到堆栈中。如果它到达死胡同,它会弹出堆栈的顶部,直到另一个路径可用。我的问题是,如果一个迷宫实际上是不可能完成的,因为路径被围在 4 个侧面并且没有去处,我的方法不会返回“假”,这意味着它无法找到解决方案。
  • 我的 mazerunner 方法适用于每个有可能解决方案的迷宫,算法没有被破坏。如果没有真正的解决方案,我的方法会给我一个空堆栈异常,因为它试图删除一个空堆栈的顶部。
  • 此外,您的答案包含的固定代码将在第一次向上移动后停止任何递归
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-03-21
  • 2018-07-09
  • 2015-12-27
  • 1970-01-01
  • 2021-09-06
  • 2021-02-12
  • 2011-11-20
相关资源
最近更新 更多