原谅我,我是递归的新手,但据我所知,这应该有效,但事实并非如此。我做了这个方法,当成功找到路径时递归调用自己:
private void RandStep(Point pos)
{
Collections.shuffle(Arrays.asList(directions), rand); //Incorrect, should have a local directions array. Nothing to do with the question though.
for (int i = 0; i < directions.length;i++)
{
//Check if the positions are within map bounds.
if (pos.x + directions[i].x >= 0 && pos.x + directions[i].x < width && pos.y + directions[i].y >= 0 && pos.y + directions[i].y < height)
{
//Check if the position is unvisited.
if (!mazeMap[pos.x + directions[i].x][pos.y + directions[i].y].visited)
{
//Break walls this tile.
CarvePassage(pos, directions[i]);
mazeMap[pos.x + directions[i].x][pos.y + directions[i].y].visited = true;
position.setLocation(pos.x + directions[i].x, pos.y + directions[i].y);
RandStep(position);
}
}
}
}
这一切都有效,直到它第一次卡在被访问的单元格或地图边界之间。如果我理解正确的递归,它应该退出此方法并转到上一次运行RandStep
并完成方向循环。当它在那里找不到任何有效的单元格时:它应该再次退出并完成前一个RandStep
中的循环。这应该重复,直到完成第一次RandStep
运行的方向循环。
就像我说的那样,它暂时无法找到任何有效的细胞。它不会在递归堆栈上继续以前的方法。
答案 0 :(得分:3)
很简单,因为你不退后了!
position.setLocation(pos.x + directions[i].x, pos.y + directions[i].y);
RandStep(position);
应该是这样的:
position.setLocation(pos.x + directions[i].x, pos.y + directions[i].y);
RandStep(position);
position.setLocation(pos.x - directions[i].x, pos.y - directions[i].y);
作为一种直觉,想想在递归的基本情况下会发生什么。你周围的所有瓷砖都被访问过,你处于死路。这种情况看起来像:
_
| |
|x|
(x
=&#34;你在这里&#34;)
然后,position.setLocation(pos.x + directions[i].x, pos.y + directions[i].y);
将你带到这里:
_
|x|
| |
然后,RandStep(position);
无法 ,因为您周围的所有位置都会被探索。所以接下来要做的就是退步,这可以通过以下方式实现:position.setLocation(pos.x - directions[i].x, pos.y - directions[i].y);
。
答案 1 :(得分:1)
让我们仔细看看幕后发生的事情。假设您熟悉堆和堆栈的内容,变量position
位于heap
,因为它不是函数RandStep
的本地变量。另一方面,pos
是本地的,因此它驻留在堆栈上。每次递归调用时,都会分配一个新的堆栈帧(从frameA到frameC)。为简洁起见,我将头寸表示为单一值。让我们说你从位置0开始,然后将墙壁向位置1突破。会发生的是为pos
的新值分配新帧,但会覆盖position
。当你从位置1转换到位置2时也一样。让我们说从位置2那里无处可去,所以我们需要追溯。然后取消分配frameC。但是,不是在顶部框架(现在是frameB)中使用pos
的值,而是在RandStep
上调用position
,因此您使用的值是在堆上,尽管帧取消分配,但仍保持不变。
&#34;退后&#34;正如Intredasting所暗示的那样,意味着手动更新堆,以便position
遵循与pos
相同的演变。在我看来,这违背了递归的目的。它的美妙之处在于它通过释放来照顾踩踏部分。
总之,您需要做的是避免在递归函数中更改堆。
|STACK | |STACK | |STACK |
| | | | | |
| | | | |frameC: pos = 2|---> got stuck, deallocate frame
| | |frameB: pos=1 | |frameB: pos = 1| and backtrack
|frameA: pos=0 | |frameA: pos=0 | |frameA: pos = 0|
|---------------| |--------------| |---------------|
|HEAP | |HEAP | |HEAP |
|position = 0 | |position=1 | |position = 2 |
| | | | | |
| | | | | |
----------------- ---------------- -----------------