递归调用导致Java堆栈溢出
问题 你好, 我正在做一个Java项目来完成我的大学学业,遇到了一个我自己无法解决的问题,这是我第一次在这里问问题,所以如果我做错了什么,请告诉我 我试图用墙跟随算法来解一个简单连接的迷宫,该算法在迷宫中行走,总是尝试向右转弯,然后向前移动,最后向右转弯。当遇到一个死掉的算法时,它会掉头并开始向后移动 当迷宫大小大于500 x 500时,我的递归运算会导致堆栈溢出错误。我想知道代码中是否有错误,或者用递归算法解决这类问题是不可行的 注意:问题不是算法不起作用,而是它耗尽了堆栈 **问题:** 是否存在循环或内存泄漏,或者在一定数量的调用之后不可能使用递归 我有一个迭代的解决方案,可以在任何迷宫大小下工作 节目 迷宫被表示为一个2D数组,每个正方形都有自己的类来保存迷宫中的坐标。我的想法是,当递归方法运行时,Java存储这些方形对象而不清理它们。move()方法调用一个方法getSquareInDirection,该方法创建一个新的Square对象,这可能会导致错误。其他方法只改变枚举方向,不应该是错误的原因,但我不确定这一点 父方法递归调用导致Java堆栈溢出,java,algorithm,recursion,Java,Algorithm,Recursion,问题 你好, 我正在做一个Java项目来完成我的大学学业,遇到了一个我自己无法解决的问题,这是我第一次在这里问问题,所以如果我做错了什么,请告诉我 我试图用墙跟随算法来解一个简单连接的迷宫,该算法在迷宫中行走,总是尝试向右转弯,然后向前移动,最后向右转弯。当遇到一个死掉的算法时,它会掉头并开始向后移动 当迷宫大小大于500 x 500时,我的递归运算会导致堆栈溢出错误。我想知道代码中是否有错误,或者用递归算法解决这类问题是不可行的 注意:问题不是算法不起作用,而是它耗尽了堆栈 **问题:** 是
public SquareQue solveRecursive() {
Square start = maze.getStart();
SquareQue path = new SquareQue();
move(start, Direction.DOWN, path);
maze.setSquareValue(start.getWidth(), start.getHeight(), 3);
return path;
}
递归方法
public SquareQue move(Square pos, Direction dir, SquareQue path) {
if (maze.reachedFinish(pos)) {
path.add(pos);
return path;
}
if (canMove(pos, getDirectionToRight(dir))) {
pos = getSquareInDirection(pos, getDirectionToRight(dir));
path.add(pos);
return move(pos, getDirectionToRight(dir), path);
} else if (canMove(pos, dir)) {
pos = getSquareInDirection(pos, dir);
path.add(pos);
return move(pos, dir, path);
} else if (canMove(pos, getDirectionToLeft(dir))) {
pos = getSquareInDirection(pos, getDirectionToLeft(dir));
path.add(pos);
return move(pos, getDirectionToLeft(dir), path);
} else {
pos = getSquareInDirection(pos, reverse(dir));
return move(pos, reverse(dir), path);
}
}
Recrsuvie方法调用此
public static Square getSquareInDirection(Square pos, Direction dir) {
int col = pos.getWidth();
int row = pos.getHeight();
if (dir == Direction.UP) {
return new Square(col, row - 1);
}
if (dir == Direction.DOWN) {
return new Square(col, row + 1);
}
if (dir == Direction.RIGHT) {
return new Square(col + 1, row);
}
if (dir == Direction.LEFT) {
return new Square(col - 1, row);
}
return null;
}
再现错误
复制错误的最简单方法是克隆项目并编辑GUI类
在方法getSolveScene内的GUI类中,并更改按钮设置以调用大型递归结果
方法:
使用例如:(getSolveScene(501501,12,设置)
重新设置getSolveScene
在此之后,您可以保存并运行带有大型和递归设置的程序
提前感谢您的响应!默认堆栈大小非常小(至少对于递归算法来说通常太小)。默认值在大多数虚拟机中只有1MByte 要更改堆栈大小,请使用VM参数:-Xss
但要检查堆栈大小是否是您唯一的问题,请先尝试解决一个较小的迷宫。只要堆栈大小足够大,可以容纳所需的递归深度(这取决于迷宫的大小),递归方法就可以工作
但是,我还看到另一个问题-
getSquareInDirection
似乎没有检查是否返回到已访问的路径。如果发生这种情况,您的程序可能会陷入“循环”即无限递归。请尝试在move
中打印当前坐标,并查看它们是否重复。(提示:不应该)您需要显示所有相关代码(最好以最小的可复制方式显示)你能突出你的问题吗?你到底在问什么?你如何确保代码没有在一个圆圈中移动?canMove方法是否检查你是否已经访问了一个正方形?如果你的递归算法适用于相对较小的大小,并抛出StackOverFlow运行时异常,你很可能可以通过。这样,您可以缓存已经计算过的表达式,并将其结果重新用于同一组参数。该算法的目的不是直接跟踪它访问的方块。相反,它使用的逻辑是,始终沿着右边的墙,它最终会到达终点。我认为这并不能回答问题。@Giorgi tsiklauri:我很确定在500x500迷宫中进行递归搜索将导致递归深度可能高于1MB堆栈大小。是的,但这是您在讨论中提出的一个假设,而不是明确解决问题的答案。这是预期的,算法不允许跟踪其访问的方块。循环是通过反转遍历方向避免该算法,它将返回到第一次通过时被忽略的最后一个交叉点,因为当时它是一个左转。@VilleManninen在这种情况下,迷宫必须没有回路或平行路径,即它必须是一棵树。这就是你所说的“简单连接”吗?是的,对不起,我应该说得更清楚一些,这确实是它的意思。为了澄清算法确实解决了生成的迷宫,但使用大型迷宫时内存不足。@VilleManninen在这种情况下,您有一个比默认堆栈更大的合法要求-只需使用类似java-Xss32m
(根据需要调整大小)的东西即可。
if (selectedString.equals("Large")) {
stage.setScene(getSolveScene(81, 81, 12, setting));
stage.setTitle("Maze generator - Recursive Large");
}