【问题标题】:How to list all partial trees of a tree如何列出一棵树的所有部分树
【发布时间】:2018-01-04 06:02:32
【问题描述】:

让我们首先列出我看过的内容以及我寻找的内容

我确实想要列出数组中的所有排列 - Get all permutations of a PHP array?

我确实想从数组中按顺序查找所有组合 - https://stackoverflow.com/a/38871855/1260548

上面的两个例子让我走到了现在,但我仍然产生了太多的组合。有了 50 个节点,我最终会得到数十亿甚至数万亿的组合,我认为我可以通过树结构进一步减少这种情况。

我正在寻找的是树中所有可能的有序组合,这些组合可以像这样构造为多维数组

[1]
--[2]
--[4]
[8]
--[3]
--[9]
----[5]
[6]
[7]

我想要找到的是所有可能的开放节点(甚至叶子/末端节点都可以开放)。所以这里一种可能的组合是所有的数字,比如

  • 1.2.3.4.5.8.9

这里的节点 1 是 2 和 4 的父节点。8 是 3 和 9 的父节点。9 是 8 的子节点,但也是 5 的父节点。其他可能的组合是。

  • 1
  • 1.2.4
  • 1.6.7.8
  • 3.5.8.9
  • 3.5.6.7.8.9

如果父节点未打开,则无法打开节点。例如,如果不包括 1,则不能包括 2 和 4。如果不包括9则不能包括5,如果不包括8则不能包括3、9和5。

以下是我用来生成示例节点结构以进行测试的代码。请注意,这个结构是有序的并且有一个固定的深度,因为我想提出一个可以在任何顺序和任何深度下工作的函数。

$arr = [];
$result = [];
$xtotal = 0;
$ytotal = 0;
$ztotal = 0;
for ($x=0; $x<2; $x++) {
  $arr[$xtotal] = array();
  $ytotal = $xtotal+1;
  for ($y=0; $y<2; $y++) {
    $arr[$xtotal][$ytotal] = array();
    $ztotal = $ytotal+1;
    for ($z=0; $z<2; $z++) {
      $arr[$xtotal][$ytotal][$ztotal] = array();
      $ztotal++;
    }
    $ytotal = $ztotal+1;
  }
  $xtotal = $ytotal+1;
}
for ($c=0; $c<5; $c++) {
  $arr[$xtotal] = array();
  $xtotal++;
}

所以我想知道如何编写一个列出所有这些可能组合的函数?

编辑:使用较小的集合,我可以列出所有可能的组合。

[1]
--[2]
--[4]
[8]

1
8
1.8
1.2
1.4
1.2.8
1.4.8
1.2.4
1.2.4.8

【问题讨论】:

  • 提供你的树形结构,意味着代码和你尝试了什么?
  • @ShubhamAgrawal 我添加了一些代码来生成示例树结构,请注意,相同的顺序是有序的,只有几层深,但我想制作一个适用于任何顺序的节点的函数,并且任何深度。我已经尝试了上面的链接问题,也许我可以用它们来解决我的问题。我正在尝试解决这个问题,但目前我没有代码可以显示它甚至接近解决我的问题,这就是为什么我问希望有人以前遇到过这个问题。
  • 我的问题和这个问题很相似,也没有明确的答案stackoverflow.com/questions/41248914/…
  • 你能解释一下什么是“开放节点”以及树结构“被打开”意味着什么吗?它与您链接到的“所有可能的路径”问题有何不同?
  • @MarkusTenghamn 我有一些问题:pastebin.com/PqUwNnm8

标签: php arrays tree


【解决方案1】:

我想出了一个功能,似乎可以满足您的需求。但是,在存储所有不同的组合时,您很容易开始遇到内存问题。如果您需要 50 个节点,则此解决方案可能不适合您,具体取决于内存限制。

我使用了一些不同的节点生成器(尽管我也用你的进行了测试),这让我在创建随机组合时更加灵活:

$arr = [];
$counter = 0;
// you can change the (2,6) to produce different numbers of root nodes
for($i=1;$i<=mt_rand(2,6);$i++){
    $curr = $counter++;
    $arr[$curr] = [];
    // guarantee the first node (0) will have children nodes (easier testing) - random for other nodes
    $child = ($curr == 0) ? true : rand(0,1);
    if($child){
        // you can change the (1,2)
        for($j=1;$j<=mt_rand(1,2);$j++){
            $curr2 = $counter++;
            $arr[$curr][$curr2] = [];
            $child2 = rand(0,1);
            if($child2){
                // you can change the (1,2) here too
                for($k=1;$k<=mt_rand(1,2);$k++){
                    $curr3 = $counter++;
                    $arr[$curr][$curr2][$curr3] = [];
                }
            }
        }
    }
}

现在开始计算:

function treenodes($arr,&$results,$parent=null){
    foreach($arr as $k=>$a){
        // here we copy all our current results - this gives us one with the current node closed (original), and one with it open (clone)
        $clone = [];
        foreach($results as $key=>$result){
            // if this node is allowed in this result (parent is on) - root nodes are always allowed
            if($parent === null || in_array($parent,$result)){
                $clone[] = array_merge($result,array($k));
            }
        }
        $results = array_merge($results,$clone);
        // if this node has children, run this function on them as well
        if(count($a)){
            treenodes($a,$results,$k);
        }
    }
}
// we start with one option of no nodes open
$results = [[]];
treenodes($arr,$results);

// show results - you can order these another way if you'd like before printing
print count($results)."\n";
foreach($results as $result){
    print implode(",",$result)."\n";
}

【讨论】:

  • 似乎正在工作,我想对其进行更多测试,但如果一切都按预期工作,我会标记这是答案。也感谢你的好种子:)
  • 在最多 30 个节点上按预期工作,之后我开始遇到内存问题,因为结果呈指数级增长。我想可以通过SplFixedArray 之类的方式解决这个问题
猜你喜欢
  • 1970-01-01
  • 2021-03-08
  • 1970-01-01
  • 2013-12-03
  • 1970-01-01
  • 1970-01-01
  • 2016-05-19
  • 1970-01-01
  • 2023-03-17
相关资源
最近更新 更多