繁体   English   中英

与父母/孩子拼合一棵树并返回所有节点

[英]Flattening a tree with parents/children and return all nodes

可能为时已晚,但是直到解决后我才能入睡:

我有一棵树,有一些父母,他们有孩子,也有孩子等。

现在,我需要一个函数来从树中获取所有节点。

这是当前有效的方法,但仅具有一个深度级别:

def nodes_from_tree(tree, parent):
    r = []
    if len(tree.get_children(parent)) == 0:
        return parent
    for child in tree.get_children(parent):
        r.append(nodes_from_tree(tree, child))
    return r

然后我尝试将r传递给它,这样它就记住了孩子,但是我使用函数的次数超过了一次,并且r累计存储了所有节点,尽管我将其设置为r=[]

def nodes_from_tree(tree, parent, r=[]):
    r = []
    if len(tree.get_children(parent)) == 0:
        return parent
    for child in tree.get_children(parent):
        r.append(nodes_from_tree(tree, child, r))
    return r

编辑 :这是树结构:

parent1    parent2    parent3
   |          |          |
   |          |          |
 child        |          |
              |          |
      +--------------+   |
      |       |      |   |
    child   child  child |
      |                  |
  +---+---+              |
child   child        +---+---+
                     |       |
                   child     |
                             |
                       +-----+-----+-----+
                       |     |     |     |
                     child child child child

可用方法:

tree.get_parents()       # returns the nodes of the very top level
tree.get_children(node)  # returns the children of parent or child

如果我理解您的问题,您想制作一个包含树中所有值的平面列表,在这种情况下,用元组表示的树将起作用:

def nodes_from_tree(tree,nodes=list()):
    if isinstance(tree,tuple):
        for child in tree:
            nodes_from_tree(child,nodes=nodes)
    else:
        nodes.append(tree)

mynodes = []
tree = (('Root',
        ('Parent',(
            ('Child1',),
            ('Child2',)
            )
        ),
        ('Parent2',(
            ('child1',(
                ('childchild1','childchild2')
            )),
            ('child2',),
            ('child3',)
        )),
        ('Parent3',(
            ('child1',),
            ('child2',(
                ('childchild1',),
                ('childchild2',),
                ('childchild3',),
                ('childchild4',)
            ))
        ))
    ))
nodes_from_tree(tree,nodes=mynodes)
print(mynodes)

产生

['Root', 'Parent', 'Child1', 'Child2', 'Parent2', 'child1', 'childchild1', 'childchild2',
 'child2', 'child3', 'Parent3', 'child1', 'child2', 'childchild1', 'childchild2', 'childchild3', 'childchild4']

我认为您的问题仅仅是您不正确地积累了东西。

首先,如果您击中一个中间节点,则每个子节点都应返回一个列表,但是您要append该列表而不是extend它。 因此,您将获得[[1, 2], [3, 4]]类的东西,而不是[1, 2, 3, 4] [[1, 2], [3, 4]] -换句话说,您只是将其转换为列表- -list树,而不是平面列表。 将其更改为extend

其次,如果您命中了一个叶子节点,那么您根本就不会返回任何列表,而只是返回parent 更改为return [parent]

第三,如果您击中一个中间节点,那么您将不会在任何地方包含parent节点,因此最终只会留下叶子。 但是您需要所有节点。 因此将r = []更改为r = [parent]

有了最后的更改,您根本不需要if块。 如果没有子代,则该循环将发生0次,最终您将按原样返回[parent]

所以:

def nodes_from_tree(tree, parent, r=[]):
    r = [parent]
    for child in tree.get_children(parent):
        r.extend(nodes_from_tree(tree, child, r))
    return r

同时,尽管此版本可以使用 ,但仍然感到困惑。 您正在混合两种不同的递归样式。 一种将累加器顺着链条传下来,然后再顺路加法的方法是这样做的。 另一个是返回价值链并在上升过程中累积结果。 你们每个人都做一半。

事实证明,您执行上游递归的方式是使下游递归完全无效。 当您确实将r传递给每个孩子时,您永远不会修改它,甚至不会使用它。 您只需创建一个新的r列表并将其返回即可。

最简单的解决方法是删除累加器参数:

def nodes_from_tree(tree, parent):
    r = [parent]
    for child in tree.get_children(parent):
        r.extend(nodes_from_tree(tree, child))
    return r

(值得注意的是,如果您以下游累加器样式而不是上游收集样式来执行分支递归,则只能对尾调用进行优化。但这在Python中并不重要,因为Python不会进行尾调用优化。因此,请写下对您更有意义的一种。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM