【问题标题】:Count all Children of Nodes in a Hierarchical (Tree) Data Structure in MySQL using PHP使用 PHP 计算 MySQL 中分层(树)数据结构中节点的所有子节点
【发布时间】:2020-03-22 20:17:16
【问题描述】:

我想计算树结构任何级别中所有子项的数量。树不是二元的,所以一个节点可以有两个以上的孩子。 现在我创建了一个递归函数来完成这项工作,但它真的很慢。我需要一个更快的方法,但我不能用其他任何方法。

所以,假设我们有这张桌子:

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

有什么办法可以避免这个递归函数?

谢谢!

【问题讨论】:

  • 当你进行递归调用时,我认为你应该传递 node_id 而不是 $element_id。 “慢”是指它永远不会终止?
  • @Olivier 我必须使用大量数据,它是用于 web 应用程序的。计算所有数据需要很长时间,而且在某些情况下它永远不会加载。
  • @cHao 我认为它确实有效,但我正在寻找 PHP 中的函数,而不是纯 MySQL,因为我想用它来创建一些类似的函数,来计算这些节点的其他一些列将有。不过,谢谢!我以前没看过这个帖子,我看看能不能用。

标签: php sql recursion tree hierarchical-data


【解决方案1】:

我认为分层数据结构(树)是递归的同义词。

我在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 函数向前搜索(实际节点的父节点加一,并调用第二个递归函数 incrementActualNodeAncestor),incrementActualNodeAncestor 向后搜索(实际节点的每个祖先都加一)。

结果在 $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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-03-13
    • 2011-08-28
    • 2011-03-24
    • 1970-01-01
    • 1970-01-01
    • 2021-01-02
    • 2011-10-29
    • 1970-01-01
    相关资源
    最近更新 更多