[英]Depth First Search recursive calls cause StackOverflow error
我正在使用深度優先搜索算法的實現來解決迷宮問題。 我不希望找到最短路徑,而是希望找到找到有效路徑的最快方法。 這是我用來解決迷宮的方法。 迷宮是 2d int arrays,其中 0 是一個開放的方塊,1 是一堵牆,2 是一個訪問過的方塊,9 是目的地。
public class DepthAlgorithm {
/**
* This method returns true when a path is found. It will also fill up the
* list with the path used. It will start from (xn,yn,.....,x2,y2,x1,y2)
* because it will use recursion.
* @param maze 2d array of maze
* @param x the x of the starting position
* @param y the y of the starting position
* @param path a List of the path
* @return True if a path is found
*/
public static boolean searchPath(int [][] maze, int x, int y, List<Integer> path){
// Check if the destination (9) is reached
if (maze[y][x] == 9) {
path.add(x);
path.add(y);
return true;
}
// When the current position is not visited (0) we shall make it visited (2)
if (maze[y][x] == 0) {
maze[y][x] = 2;
//Here we visit all neighbour squares recursively and if a path is found
// we shall fill the path list with the current position.
int dx = -1; // Start and search from starting
int dy = 0; // position (x-1,y)
if (searchPath(maze, x + dx, y + dy, path)) {
path.add(x);
path.add(y);
return true;
}
dx = 1; // Start and search from starting
dy = 0; // position (x+1,y)
if (searchPath(maze, x + dx, y + dy, path)) {
path.add(x);
path.add(y);
return true;
}
dx = 0; // Start and search from starting
dy = -1; // position (x,y-1)
if (searchPath(maze, x + dx, y + dy, path)) {
path.add(x);
path.add(y);
return true;
}
dx = 0; // Start and search from starting
dy = 1; // position (x,y+1)
if (searchPath(maze, x + dx, y + dy, path)) {
path.add(x);
path.add(y);
return true;
}
}
return false;
}
}
我的算法適用於小型迷宮。 當我想解決一個 50 * 50 的迷宮時,它非常快。 當我移動到 500 * 500 時,出現堆棧溢出錯誤。 我可以理解它是由於 function 的許多遞歸調用而出現的,但我不知道如何修復它。 有沒有另一種方法,這樣我仍然可以使用深度優先搜索並存儲我的路徑但沒有堆棧溢出? 或者是否可以在我的代碼中進行任何更改以修復它?
public class MazeRunner {
// Maze is a 2d array and it has to be filled with walls peripherally
// with walls so this algorithm can work. Our starting position in this
// will be (1,1) and our destination will be flagged with a 9 which in
// this occasion is (11,8).
private int[][] maze ;
private final List<Integer> path = new ArrayList<>();
public long startTime,stopTime;
public MazeRunner(int [][] maze){
this.maze = maze;
}
public void runDFSAlgorithm(int startingX,int startingY){
startTime = System.nanoTime();
DepthAlgorithm.searchPath(maze,startingX,startingY,path);
stopTime = System.nanoTime();
printPath();
System.out.println("Time for Depth First Algorithm: "+((double) (stopTime-startTime) / 1_000_000)+" milliseconds");
}
public void printPath(){
ListIterator li = path.listIterator(path.size());
int lengthOfPath = (path.size()/2-1);
int fromX,fromY,bool = 0,toX = 0,toY = 0,i = 2;
while(li.hasPrevious()){
if (bool == 0) {
fromX = (int) li.previous();
fromY = (int) li.previous();
toX = (int) li.previous();
toY = (int) li.previous();
System.out.println("From ("+fromY+", "+fromX+") to ("+toY+", "+toX+")");
bool++;
continue;
}
if (bool == 1){
fromX = toX;
fromY = toY;
toX = (int) li.previous();
toY = (int) li.previous();
System.out.println("From ("+fromY+", "+fromX+") to ("+toY+", "+toX+")");
i++;
}
}
System.out.println("\nLength of path is : "+lengthOfPath);
}
public static void main(String[] args){
int [][] maze = {{1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,1,0,1,0,1,0,0,0,0,0,1},
{1,0,1,0,0,0,1,0,1,1,1,0,1},
{1,0,0,0,1,1,1,0,0,0,0,0,1},
{1,0,1,0,0,0,0,0,1,1,1,0,1},
{1,0,1,0,1,1,1,0,1,0,0,0,1},
{1,0,1,0,1,0,0,0,1,1,1,0,1},
{1,0,1,0,1,1,1,0,1,0,1,0,1},
{1,0,0,0,0,0,0,0,0,0,1,9,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1}};
MazeRunner p = new MazeRunner(maze);
p.runDFSAlgorithm(startingPoint[0],startingPoint[1]);
}
}
這是我用於測試的 class。 它肯定適用於此示例,但對於更大的 arrays 它不起作用。 任何建議將不勝感激。 當我在大 arrays 上運行我的程序時,出現以下錯誤:
一般來說,只有兩種可能導致堆棧溢出異常 1.memory 堆棧不夠 2.存在死循環,在使用遞歸時意味着它不存在結束條件。
由於您的算法適用於小型迷宮。 這可能是一個原因。 眾所周知遞歸的規則是先進后出,在 JVM 中所有未執行函數的數據將存儲在堆棧中,堆棧擁有比堆小得多的 memory 。
除非您確定堆棧的深度將被限制在一個合理的數字,否則您永遠不應該在實際工作中使用遞歸算法。 通常這意味着 O(log N),或最多 O(log^2 N)。
500x500 迷宮的 DFS 可以在堆棧上放置大約 250000 個 function 調用,這太多了。
如果你真的願意,你可以使用 DFS,但你應該在一個單獨的數據結構中維護你自己的堆棧。 不過,BFS 會更好,除非出於某種原因您真的不想要最短路徑。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.