使用 PHP 检测 MySQL 数据库中的循环

发布于 2024-10-16 03:41:02 字数 620 浏览 8 评论 0原文

我在 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冲突

I have a table in MySQL with two (important) columns, A and B, with value referring to a package. A row is in the table if and only if package A requires on package B.

I was hoping to (1) generate a graph in php, then (2) determine if the graph is acyclic (a DAG), and if not, print (3) all the cycles in the graph.

So 3 is easy enough, in theory, (Johnson's algorithm: http://dutta.csc.ncsu.edu/csc791_spring07/wrap/circuits_johnson.pdf ).

(2) can be done by (3) listing no cycles, but I was wondering if there was any faster algorithms.

I'm unsure of (1) - efficiently pulling data from a table and making a graph in php that lends itself to implementing (2) and (3). How should I do so?


As an aside, I also have a second table, also with two columns, having a row if and only if A conflicts with B. I also wanted to (4) find cases (or verify that there are none) where:
A requires B, B requires C, but A conflicts with C

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

赠意 2024-10-23 03:41:02

为了在搜索

(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)

中找到此主题的任何人的利益,我最终使用了算法< a href="http://www.cs.hmc.edu/~keller/courses/cs60/s98/examples/acirclic/" rel="nofollow">此处。基本上,通过删除叶节点,您要么留下一个(一组)循环,要么留下一个空图。

$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;
        }
    }
}

我很感激评论中对此答案的任何代码审查

In the interests of anyone who finds this topic in a search

(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) and (3)

I ended up using the algorithm here. Basically by removing leaf nodes, you are either left with a (set of) loop(s) or an empty graph.

$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)

For finding A requires B requires C, but A conflicts with C, I used a depth first search for each conflict, starting from A, looking for C (the conflict).

$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;
        }
    }
}

I'd appreciate any code review in the comments for this answer

々眼睛长脚气 2024-10-23 03:41:02

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

在渲染图表方面 - 看看 graphviz - 这将生成各种图表。 这是一个示例 解析 PHP 源代码以获取调用图。

抱歉,但我很忙,没有阅读您提供的参考资料(但提供了源材料的链接做得很好),也没有计算出他们使用的算法,然后考虑它是否是最佳的。

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

Sounds suspiciously like 'please help me with my homework'.

In terms of rendering the graph - have a look at graphviz - this will generate all sorts of graphs. Here's an example which parses PHP source code to get a call graph.

Sorry, but I'm busy enough without reading the reference you provided (but well done for providing a link to your source material) and working out the algorithm they've used then thinking about whether it is optimal.

You might want to have a look at the source code for the new PHP garbage collector - which does the same thing. (really you just need to walk the tree - if you come to a node you've already visited then you've got a loop).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文