使用父项/子项展平树并返回所有节点

时间:2013-05-14 00:47:19

标签: python recursion tree

可能为时已晚,但在解决之前我无法入睡:

我有一棵树,有一些父母,有孩子,还有孩子等。

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

这是目前的工作方式,但只有一个深度:

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累计存储所有节点,尽管我将其设置为{ {1}}:

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

2 个答案:

答案 0 :(得分:2)

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

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']

答案 1 :(得分:2)

我认为你的问题只是你正在积累不正确的东西。

首先,如果你点击一个中间节点,每个孩子都应该返回一个列表,但是你append该列表而不是extend。因此,代替[1, 2, 3, 4],您将获得类似[[1, 2], [3, 4]]的内容 - 换句话说,您只是将其转换为列表列表树,而不是平面列表。将其更改为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不进行尾调用优化。所以,写一个对你更有意义的东西。)