我目前正在研究一种算法,可以解决一个三维难题。
然而,我遇到了一个问题,我使用的算法是第一个搜索深度,它似乎工作得很好,直到我得到“引发存储错误:异常堆栈溢出”。我不太清楚它为什么不起作用。你猜这为什么不管用吗?
我希望此算法执行的操作:
它需要一个列表、一个数字和一个目标。在本例中,列表由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/

10-13 08:21