Convert a series of parent-child relationships into a hierarchical tree?

前端 未结 11 2137
[愿得一人]
[愿得一人] 2020-11-22 07:04

I have a bunch of name-parentname pairs, that I\'d like to turn into as few heirarchical tree structures as possible. So for example, these could be the pairings:

         


        
11条回答
  •  面向向阳花
    2020-11-22 07:49

    While Alexander-Konstantinov's solution might not seem as easy to read at first, it is both genius and exponentially better in terms of performance, this should have been voted as the best answer.

    Thanks mate, I made a benchmark in your honor to compare the 2 solutions presented in this post.

    I had an @250k flat tree with 6 levels that I had to convert and I was searching for a better way to do so and avoid recursive iterations.

    Recursion vs Reference:

    // Generate a 6 level flat tree
    $root = null;
    $lvl1 = 13;
    $lvl2 = 11;
    $lvl3 = 7;
    $lvl4 = 5;
    $lvl5 = 3;
    $lvl6 = 1;    
    $flatTree = [];
    for ($i = 1; $i <= 450000; $i++) {
        if ($i % 3 == 0)  { $lvl5 = $i; $flatTree[$lvl6] = $lvl5; continue; }
        if ($i % 5 == 0)  { $lvl4 = $i; $flatTree[$lvl5] = $lvl4; continue; }
        if ($i % 7 == 0)  { $lvl3 = $i; $flatTree[$lvl3] = $lvl2; continue; }
        if ($i % 11 == 0) { $lvl2 = $i; $flatTree[$lvl2] = $lvl1; continue; }
        if ($i % 13 == 0) { $lvl1 = $i; $flatTree[$lvl1] = $root; continue; }
        $lvl6 = $i;
    }
    
    echo 'Array count: ', count($flatTree), PHP_EOL;
    
    // Reference function
    function treeByReference($flatTree)
    {
        $flat = [];
        $tree = [];
    
        foreach ($flatTree as $child => $parent) {
            if (!isset($flat[$child])) {
                $flat[$child] = [];
            }
            if (!empty($parent)) {
                $flat[$parent][$child] =& $flat[$child];
            } else {
                $tree[$child] =& $flat[$child];
            }
        }
    
        return $tree;
    }
    
    // Recursion function
    function treeByRecursion($flatTree, $root = null)
    {
        $return = [];
        foreach($flatTree as $child => $parent) {
            if ($parent == $root) {
                unset($flatTree[$child]);
                $return[$child] = treeByRecursion($flatTree, $child);
            }
        }
        return $return ?: [];
    }
    
    // Benchmark reference
    $t1 = microtime(true);
    $tree = treeByReference($flatTree);
    echo 'Reference: ', (microtime(true) - $t1), PHP_EOL;
    
    // Benchmark recursion
    $t2 = microtime(true);
    $tree = treeByRecursion($flatTree);
    echo 'Recursion: ', (microtime(true) - $t2), PHP_EOL;
    

    The output speaks for itself:

    Array count: 255493
    Reference: 0.3259289264679 (less than 0.4s)
    Recursion: 6604.9865279198 (almost 2h)
    

提交回复
热议问题