[英]Count all Children of Nodes in a Hierarchical (Tree) Data Structure in MySQL using PHP
我想计算树结构任何级别中所有子级的数量。 树不是二元的,因此一个节点可以有 2 个以上的子节点。 现在我已经创建了一个递归函数来完成这项工作,但它真的很慢。 我需要一种更快的方法,但我不能以任何其他方式做到。
所以,假设我们有那个表:
NodeID | ParentID
-------------------
1 | 0
2 | 1
3 | 1
4 | 2
5 | 1
6 | 2
7 | 3
8 | 5
9 | 6
10 | 8
11 | 6
11 | 6
• 1
• 2
• 4
• 6
• 9
• 11
• 12
• 3
• 7
• 5
• 8
• 10
因此,如果我想获取节点 1 的子节点数,则该数字应为 11 而不是 3。节点 2 也是如此。数字应为 5 而不是 2。
这是我在 PHP 中创建的递归函数,但它很慢:
function count_all_nodes($connection, $element_id, $elements=false, $i=0) {
if (!$elements) {
$result = mysqli($connection, "SELECT `node_id`, `parent_id` FROM `elements`");
while ($row = mysqli_fetch_array($result)) {
$sub_elements["node_id"] = $row["node_id"];
$sub_elements["parent_id"] = $row["parent_id"];
$elements[] = $sub_elements;
}
}
foreach ($elements as $element) {
if ($element["parent_id"] == $element_id) {
$i++;
$i += count_all_nodes($connection, $element_id, $elements);
}
}
return $i;
}
有什么办法可以避免这个递归函数吗?
谢谢!
我认为分层数据结构(树)是递归的同义词。
我在 php 中实现了两个递归函数,它们可能比您的代码更快,因为我只执行一个 MySql 查询来获取树信息,而不是像您一样在每次调用递归函数时执行一个。
示例数据:
根节点(树的第一个节点)没有父亲,我将此设置指示到其父亲字段“0-A”(此节点不存在)中,但您可以将其设为 null。
要获取树信息,我执行此查询:
SELECT node, father
FROM tree
ORDER BY node;
我在 php 中得到这样的东西:
$nodes = array ( 0 => array ( 'node' => '1-A', 'father' => '0-A', ), 1 => array ( 'node' => '2-A', 'father' => '1-A', ), 2 => array ( 'node' => '3-A', 'father' => '1-A', ), 3 => array ( 'node' => '4-A', 'father' => '2-A', ), 4 => array ( 'node' => '5-A', 'father' => '2-A', ), 5 => array ( 'node' => '6-A', 'father' => '3-A', ), 6 => array ( 'node' => '7-A', 'father' => '3-A', ), 7 => array ( 'node' => '9-A', 'father' => '6-A', ), 8 => array ( 'node' => '10-A', 'father' => '7-A', ), 9 => array ( 'node' => '8-A', 'father' => '7-A', ), 10 => array ( 'node' => '11-A', 'father' => '10-A', ), )
这是我的php代码:
/**
* Count all Children of each node in a Hierarchical Data Structure (Tree).
*
* @param array(idNode => idNodeFather) $nodes
* @param string $actualNode
* @param array(idDode => totalChildrens) $result
*/
function countChildrensNode($nodes, $actualNode, &$result) {
foreach($nodes as $node => $father) {
if($actualNode == $father) {
$result[$father]++;
countChildrensNode($nodes, $node, $result);
incrementActualNodeAncestor($nodes, $father, $result);
}
}
}
/**
* Increment by one to all actual node's ancestors.
*
* @param array(idNode => idNodeFather) $nodes
* @param string $actualNode
* @param array(idDode => totalChildrens) $result
*/
function incrementActualNodeAncestor($nodes, $actualNode, &$result) {
foreach($nodes as $node => $father) {
if($actualNode == $node) {
if($father != '0-A' && ! is_null($father)) {
$result[$father]++;
incrementActualNodeAncestor($nodes, $father, $result);
}
}
}
}
//$nodes is the array return by my query.
$nodesfathers = array_combine (array_column($nodes, "node"), array_column($nodes, "father"));
$res = array_fill_keys(array_column($nodes, "node"), 0);
countChildrensNode($nodesfathers, array_keys($nodesfathers)[0], $res);
countChildrensNode 函数向前搜索(将实际节点的父亲递增 1 并调用 incrementActualNodeAncestor 第二个递归函数)和 incrementActualNodeAncestor 向后查找(并且将实际节点的每个祖先递增 1)。
结果在 $res var 中:
'1-A' | 10 |
---|---|
'2-A' | 2 |
'3-A' | 6 |
'4-A' | 0 |
'5-A' | 0 |
'6-A' | 1 |
'7-A' | 3 |
'9-A' | 0 |
'10-A' | 1 |
'8-A' | 0 |
'11-A' | 0 |
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.