我在MySQL中有一个包含两个(重要)列A和B的表,其值指的是一个包。当且仅当包A在包B上需要时,表中才有一行。
我希望(1)在php中生成图表,然后(2)确定图表是非循环的(DAG),如果不是,则打印(3)图表中的所有周期。
理论上,3很容易(Johnson的算法: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
冲突答案 0 :(得分:2)
为了在搜索中找到此主题的任何人的利益
<强>(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;
}
}
}
我很感激您对此答案的评论中的任何代码审核
答案 1 :(得分:-1)
听起来很奇怪'请帮我做作业'。
在渲染图形方面 - 看看graphviz - 这将生成各种图形。 Here's an example解析PHP源代码以获取调用图。
很抱歉,但是我很忙,没有阅读您提供的参考资料(但是提供了源材料的链接做得很好)并计算出他们使用的算法,然后考虑它是否是最佳的。
您可能希望查看新的PHP垃圾收集器的源代码 - 它执行相同的操作。 (实际上你只需要走树 - 如果你来到一个已经访问过的节点,那么你就有了一个循环)。