【问题标题】:Detecting cycles in a MySQL database using PHP使用 PHP 检测 MySQL 数据库中的周期
【发布时间】:2011-02-08 10:02:09
【问题描述】:

我在 MySQL 中有一个表,其中包含两个(重要的)列 A 和 B,其值指的是一个包。当且仅当包 A 需要包 B 时,表中才会出现一行。

我希望 (1) 在 php 中生成一个图形,然后 (2) 确定该图形是否是非循环的(DAG),如果不是,则打印(3)图中的所有循环。

理论上,3 很简单(约翰逊算法:http://dutta.csc.ncsu.edu/csc791_spring07/wrap/circuits_johnson.pdf)。

(2) 可以通过 (3) 不列出循环来完成,但我想知道是否有更快的算法。

我不确定 (1) - 有效地从表中提取数据并在 php 中制作一个图表,这有助于实现 (2) 和 (3)。我该怎么做?


顺便说一句,我还有第二个表,也有两列,当且仅当 A 与 B 冲突时才有一行。我还想 (4) 查找案例(或验证没有)其中: A 需要 B,B 需要 C,但 A 与 C 冲突

【问题讨论】:

  • 有限,但除此之外,没有。我可能有一个很长的链,例如 A=>B=>C=>...=>Z=>A。我还应该澄清一下,它可能是一个定向森林,而不仅仅是一棵树(即未连接的)。

标签: php mysql graph cycle


【解决方案1】:

为了在搜索中找到此主题的任何人的利益

(1)

$pkgList = array();
$result = mysqli_query($conn, 'SELECT * FROM `Packages`');
while (($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) != NULL) {
    $pkgList[] = $row['idPackages'];
}

$reqEdgeList = array();
$conEdgeList = array();

$result = mysqli_query($conn, "SELECT * FROM `Dependancies` WHERE `Relationship` = 'Requires'");
while (($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) != NULL) {
    switch ($row['Relationship']) {
        case 'Requires':
            $reqEdgeList[] = array($row["DependerPackage"], $row["DependeePackage"]);
            break;
        case 'Conflicts':
            $conEdgeList[] = array($row["DependerPackage"], $row["DependeePackage"]);
            break;
    }
}

(2)(3)

我最终使用了算法here。基本上通过删除叶节点,您要么留下(一组)循环,要么留下一个空图。

$allReqs = $reqEdgeList;

$noDependanciesCycle = true;

$searching = true;
while ($searching) {
    if (empty($pkgList)) {
        $searching = false;
        echo "Req is a DAG\n<br />";
    } else {
        $foundleaf = false;
        $leaf = null;
        foreach ($pkgList as $key => $l) {
            $isLeaf = true;
            foreach ($reqEdgeList as $k => $edge) {
                if ($edge[0] == $l) {
                    $isLeaf = false;
                }
            }

            if ($isLeaf) {
                $foundleaf = true;
                $leaf = $l;
            }
        }
        if ($foundleaf) {
            $pkgList = array_diff($pkgList, array($leaf));
            foreach ($reqEdgeList as $key => $value) {
                if ($value[1] == $leaf) {
                    unset($reqEdgeList[$key]);
                }
            }
            $reqEdgeList = array_values($reqEdgeList);
        } else {
            $searching = false;
            echo "Req cycle detected\n<br />";
            $noDependanciesCycle = false;
            print_r($reqEdgeList);
            echo "<br />\n";
        }
    }
}

(4)

为了找到 A 需要 B 需要 C,但是 A 与 C 冲突,我对每个冲突都使用了深度优先搜索,从 A 开始,寻找 C(冲突)。

$reqEdgeList = $allReqs;
echo "<br />\n";

$anyReqConfError = false;
foreach ($conEdgeList as $endpoints) {
    for ($i = 0; $i < 2; $i++) {
        if ($i == 0) {
            $startPkg = $endpoints[0];
            $endPkg = $endpoints[1];
        } else {
            $startPkg = $endpoints[1];
            $endPkg = $endpoints[0];
        }

        $marked = array();
        foreach ($allPkgs as $pkg) {
            $marked[$pkg] = false;
        }

        $queue = array();
        $queue[] = $startPkg; // enque
        $marked[$startPkg] = true;

        $searching = true;
        $found = false;
        while ($searching) {
            $v = array_shift($queue); // deque (use array_pop for stack (dfs))
            if ($v == $endPkg) {
                $searching = false;
                $found = true;
            } else {
                foreach ($reqEdgeList as $edge) {
                    if ($edge[0] == $v) {
                        $w = $edge[1];
                        if (!$marked[$w]) {
                            $marked[$w] = true;
                            $queue[] = $w;
                        }
                    }
                }
            }

            if($searching) {
                $searching = !empty($queue);
            }
        }

        if($found) {
            echo "$startPkg requires $endPkg, but are conflicting [$endpoints[0] $endpoints[1]]\n<br />";
            $anyReqConfError = true;
            $noDependanciesCycle = false;
        }
    }
}

感谢 cmets 中对此答案的任何代码审查

【讨论】:

    【解决方案2】:

    听起来很可疑,就像“请帮我做作业”。

    在渲染图表方面 - 看看 graphviz - 这将生成各种图表。 Here's an example 解析 PHP 源代码以获取调用图。

    抱歉,我很忙,没有阅读您提供的参考资料(但很好地提供了指向您的源材料的链接)并制定了他们使用的算法,然后考虑它是否是最佳的。

    您可能想查看新的 PHP 垃圾收集器的源代码 - 它做同样的事情。 (真的,你只需要遍历树——如果你来到一个你已经访问过的节点,那么你就有了一个循环)。

    【讨论】:

    • 对不起,如果我误导了你,但我不是问如何实现我发现的算法,我问的是 (1) 从 PHP 中的 MySQL 数据和 PHP 中的 (2) 图形遍历生成图形(如组合/数据结构类型)。我对绘图不感兴趣,但谢谢你的链接。
    • 我不是要你告诉我一些晦涩难懂的算法是否适合我的任务(这当然是我的工作),甚至是如何实现它,而是建议另一个(如果你知道一个),更重要的是建议(链接到)与(1)和(2)相关的示例代码。我还应该提到这不是功课,而是实际工作——我已经用其他语言实现了图遍历,我只是在寻找其他人在 PHP 中是如何做到的,特别是使用 MySQL 数据。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多