PHP中如何检测和避免无限循环

PHP中如何检测和避免无限循环,php,algorithm,Php,Algorithm,这个问题与我的PHP代码中的错误无关(目前我没有任何PHP脚本,我仍在考虑算法)。问题是: 我目前正在开发一个机械零件管理器,它能够根据内部零件构建一个机械零件(例如,我有一个零件是自行车,对于该零件,我需要2个车轮,1个把手,对于一个车轮,我需要一个轮胎等) 每个内部零件在我的数据库中也是一个机械零件,并与一个唯一的ID链接(并且有一个包含许多PDF、许多3D文件等的文件夹) 我得到了一个代表我的数据库的GUI(HTML),每个部分都有一个“构建”按钮来收集构建内部部分所需的所有文件 例如:

这个问题与我的PHP代码中的错误无关(目前我没有任何PHP脚本,我仍在考虑算法)。问题是:

我目前正在开发一个机械零件管理器,它能够根据内部零件构建一个机械零件(例如,我有一个零件是自行车,对于该零件,我需要2个车轮,1个把手,对于一个车轮,我需要一个轮胎等)

每个内部零件在我的数据库中也是一个机械零件,并与一个唯一的ID链接(并且有一个包含许多PDF、许多3D文件等的文件夹)

我得到了一个代表我的数据库的GUI(HTML),每个部分都有一个“构建”按钮来收集构建内部部分所需的所有文件

例如:

我的自行车ID为1,车轮ID为2,把手ID为3

该算法非常简单,但存在无限循环

我该如何避免以下情况:如果我的自行车(id 1)需要一个车轮(id 2),我的车轮需要一辆自行车…哪个需要一个车轮,哪个需要一辆自行车


非常感谢,

您应该区分孩子与父母的关系

自行车可以包含车轮作为子项,车轮可以包含自行车作为其父项。此外,一个螺钉和轮胎可以是车轮的子项


导航应该有一个方向,从父项到子项或相反方向

在构建函数的执行过程中,您只需跟踪已生成结果的所有组件(以散列形式),如果您再次遇到其中一个组件,您只需忽略它即可

以下是一些样板代码,您可以从中获得灵感:

// Sample "database":
$components = array(
    1 => array (
        "id" => 1,
        "name" => "bike",
        "needs" => array (
            array ("id" => 2, "count" => 2), // 2 wheels
            array ("id" => 3, "count" => 1), // 1 handlebar
        ),
        "folder" => "/my/folders/bike"
    ),
    2 => array(
        "id" => 2,
        "name" => "weel",
        "needs" => array(
            array("id" => 4, "count" => 1), // 1 tire
            array("id" => 1, "count" => 1)  // 1 wheel?? - erroneous information!
        ),
        "folder" => "/my/folders/wheel"
    ),
    3 => array(
        "id" => 3,
        "name" => "handlebar",
        "needs" => array (),
        "folder" => "/my/folders/handlebar"
    ),
    4 => array(
        "id" => 4,
        "name" => "tire",
        "needs" => array(),
        "folder" => "/my/folders/tire"
    )
);  

// Build function: returns a list of folders related
// to all the parts of the given component.
function build($componentId, $components, $hash = array()) {
    // Protection against infinite recursion:
    if (isset($hash[$componentId])) return []; 
    $elem = $components[$componentId];
    // set hash, keyed by component ID.
    $hash[$componentId] = 1;
    // Add folder for this component
    $folders[] = $elem['folder'];
    // Collect folders of dependent components recursively
    foreach($elem['needs'] as $child ) {
        // ... pass the hash as third argument
        $folders = array_merge($folders, build($child["id"], $components, $hash));
    }
    return $folders;
}

// Example call: build component with ID 1, returning a list of folders:
print_r (build(1, $components));
上述代码的输出为:

Array
(
    [0] => /my/folders/bike
    [1] => /my/folders/wheel
    [2] => /my/folders/tire
    [3] => /my/folders/handlebar
)

因此,当第二次遇到自行车时,它就被忽略了。

为什么你的车轮需要自行车?一个轮子是一个可以用于更多产品,自行车,汽车,溜冰鞋,滑板的零件。一个轮子可以自行存在,但一辆自行车并没有。这就有点关系:作为一个孩子,把父母当作自行车和轮子。我认为将来我的数据库会有成千上万篇文章,而且很容易犯错误。如果由我决定,我不在乎,但是。。。我为关心。。。当你实例化一个新的零件时,你需要跟踪并检查它是否不存在于它的父对象中——这是一种在你的例子中避免无限循环的简单方法。希望这对你有意义。这个问题和算法标签有关吗?OP想通过点击自行车的任何部分来创建一辆自行车。这意味着在这种情况下导航确实有多个方向。非常感谢,我使用了您的解决方案,但我做了一些更新,我不做$hash[$componentId]=1;但是$hash[]=$componentId,然后我在_array()中使用它而不是isset()!非常感谢,你救了我一天。不客气。您的变体也可以工作,但速度较慢,因为_array中的
可能需要搜索整个数组,而
isset
以恒定时间运行。然而,在一个只有100个组件的数据集上,差异不会那么显著。如果您有1000个或更多的组件,它将变得引人注目。