我目前正在研究一种算法,可以解决一个三维难题。
然而,我遇到了一个问题,我使用的算法是第一个搜索深度,它似乎工作得很好,直到我得到“引发存储错误:异常堆栈溢出”。我不太清楚它为什么不起作用。你猜这为什么不管用吗?
我希望此算法执行的操作:
它需要一个列表、一个数字和一个目标。在本例中,列表由7部分组成它试图在第一个坐标中输入该部分如果它不适合,它会旋转直到它适合,然后调用它自己和其他部分(6部分)。如果零件以24种方式旋转(所有可能的方式旋转三维零件),则它将移动到另一个坐标并再次尝试配合。当所有的部分都不见了或者什么都没用的时候,它应该退出,我有另一个算法,用另一个顺序将同一个列表发送到这个算法中。
我也希望算法看看最后一个坐标是否与目标不匹配,然后它应该只是回溯并试图找到另一个解决方案。
下面是一些代码:
procedure Pseudo(Parts : in out List_Type; Figure : in out Figure_Type; Goal : in out Figure_Type; LastCoord : in out Integer) is
Unchanged : Part_Type := Parts.Data;
Next : boolean := False;
UnchangedFigure : Figure_Type;
begin
UnchangedFigure := Figure;
if Empty(Parts) then
raise Finished;
else
for I in 1..24 loop
RotNumber(Parts.Data,I); -- rotera
if Check(Parts.Data,Figure) then -- test om den platsar
Maincheck(Parts.Data,Figure,Goal,Next);
if Next then
Unchanged := Parts.Data;
Append_Part(Parts.Data,Figure);
Remove_First(Parts);
Next := False;
Pseudo(Parts,Figure,Goal,LastCoord);
Next := False;
Figure := UnchangedFigure;
Insert_First(Unchanged,Parts);
Figure.CoordX := 0;
Figure.CoordY := 0;
Figure.CoordZ := 0;
end if;
end if;
Parts.Data := Unchanged;
end loop;
end if;
-- if LastCoord /= 7 then --(Original
-- if To_String(Figure.Data)(LastCoord) /= To_String(Goal.Data)(LastCoord) then
-- Put("over");
-- return;
-- end if;
-- end if;
LastCoord := Figure.CoordZ*Figure.X*Figure.Y + (Figure.Y-Figure.CoordY-1)*(Figure.X) + Figure.CoordX +1;
if Figure.CoordY < Figure.Y-1 then
Figure.CoordY := Figure.CoordY +1;
Pseudo(Parts,Figure,Goal,LastCoord);
elsif Figure.CoordY = Figure.Y-1 then
if Figure.CoordX < Figure.X-1 then
Figure.CoordX := Figure.CoordX +1;
Figure.CoordY := 0;
Pseudo(Parts,Figure,Goal,LastCoord);
elsif Figure.CoordX = Figure.X-1 then
if Figure.CoordZ < Figure.Z-1 then
Figure.CoordZ := Figure.CoordZ +1;
Figure.CoordX := 0;
Figure.CoordY := 0;
Pseudo(Parts,Figure,Goal,LastCoord);
elsif Figure.CoordZ = Figure.Z-1 then
return;
end if;
end if;
end if;
end Pseudo;
最佳答案
首先,不要使用异常来控制程序流,这是不好的做法。考虑使用一个附加的out
参数而不是raise Finished
。
我认为将所有参数声明为in out
也是一个错误。查看Parts
:在循环中,将图附加到其Data
成员,然后删除列表的第一个元素。之后,您调用Pseudo
将再次与列表发生冲突,如果失败,Parts
可能与调用之前具有完全不同的内容之后恢复第一个元素,但无论Append_Part
做什么都将保持永久性。我不能确定这是否真的是个问题。在调用Pseudo
之后恢复列表和图的工作也是一个明显的迹象,表明您不希望这些参数是in out
。
另一件看起来可疑的事情是,在循环之后,更改图形的坐标,然后再次调用Pseudo
,这将在第一次迭代结束时将坐标重置为0(如果条件匹配)。可能的控制流程是:Pseudo
开始,Parts
不为空循环开始。假设图的Coord
值最初为0。
循环的任何迭代都不会导致Finished
。循环结束。
算法改变了一些坐标并调用Pseudo
。现在我们假设Parts
的值与第一次调用Pseudo
时的值相同。如我所写,情况似乎并非如此,但我应该正确理解你的描述。
对Pseudo
的第二个调用与第一个调用相同,只是图形的某些坐标不同(可能Last_Coord
,这似乎无关紧要)。Parts
不能为空,循环开始。
现在让我们假设在循环中的某个点上,条件匹配,但是对Pseudo
的调用失败(如“doesnotraisefinished”)。坐标将重置为0。
从那时起,执行与第一个Pseudo
调用相同,因为它操作的数据现在是相同的因此在循环中不会引发Finished
,之后,将使用与之前完全相同的参数第三次调用Pseudo
。
如您所见,这将导致无休止的递归。我无法确定是否会发生这种情况,因为我对您调用的类型或子程序一无所知。
在当前情况下,您的代码很难理解,因为它有一个非常复杂的控制流。如果你去掉了一些代码的复杂性,追踪错误会更容易。我建议使用循环来迭代坐标,而不是递归。这可以解决你的问题。
关于algorithm - 存储错误-深度搜索算法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15618373/