【问题标题】:python recursive function return nodes without children in a treepython递归函数返回树中没有子节点的节点
【发布时间】:2018-10-31 12:32:31
【问题描述】:
     0
   /   \
  1     2
 / \   /|\
3   4 5 6 7

我正在尝试使用递归函数从对象返回没有子节点 (3,4,5,6,7) 的节点。

它使用一个全局变量和这个函数来工作:

def find(self, nodes):
    if not hasattr(self, 'children'): 
        nodes.append(self)
    else:
        for i in self.children:
            i.find(nodes)


nodes = []
node.find(nodes) # can be any node (0,1,2,3,4, etc.)
print(nodes)

但我想在我的函数中使用 return。我尝试过这样的事情:

   def find2(self):
    if not hasattr(self, 'children'): 
        return self
    else:
        for i in self.children:
            return i.find2()


nodes = root.find2()
print(nodes)

但我只得到 1 个节点。我还尝试在这篇文章中传递一个数组:PYTHON Return a list from a recursive function。但是我没有得到我想要的结果,因为树结构(我猜)......

我被困住了,你能帮帮我吗?如何“将递归函数每次迭代的结果返回给变量”?谢谢

【问题讨论】:

    标签: python recursion tree return


    【解决方案1】:

    请注意,在您的基本情况下,您返回一个节点。然后该节点在递归中传播回来,并最终返回。 IE。您返回的节点是第一个没有您命中的子节点的节点。有多种方法可以解决这个问题(例如通过返回和连接列表),但我认为一个自然的方法是让你的函数成为一个生成器。为此,只需将return 替换为yield。然后,函数的返回值用作迭代器,每次迭代都会产生下一个值,该值将在执行中“返回”,直到函数终止。

    【讨论】:

      【解决方案2】:

      您没有为我提供足够的代码来制作可运行和可测试的示例,但这是我对您寻求的内容的猜测:

      def find(self):
          if not hasattr(self, 'children'):
              return [self]
      
          nodes = []
      
          for child in self.children:
              return nodes.extend(child.find())
      
          return nodes
      
      # ...
      
      nodes = root.find()
      print(nodes)
      

      【讨论】:

        【解决方案3】:

        这是输入示例:

             0
           /   \
          1     2
         / \   /|\
        3   4 5 6 7
        

        想想你希望(递归)函数为每个节点返回什么:

        • 在根 (0) 上调用时,应返回完整结果 (3, 4, 5, 6, 7)
        • 在叶节点(例如 5)上调用时,应返回该节点 (5)
        • 对于任何其他节点(例如 1),它就像是一棵较小树的根节点

        因此,它有时会返回一个结果,有时会返回多个结果。 您的代码中的错误在这里,因为函数在第一次返回时结束,它不会返回很多:

            for i in self.children:
                return i.find2()
        

        有两种解决方案:

        • 创建一个生成器函数,或者
        • 创建一个返回列表的函数(让它始终返回一个列表,即使它只有一个元素!)

        所以,选项 1:

        def find(self):
            if not hasattr(self, 'children'): 
                yield self
            else:
                for child in self.children:
                    yield from child.find()
        

        选项 2:

        def find(self):
            if not hasattr(self, 'children'): 
                return [self]
            else:
                rtn = []
                for child in self.children:
                    for result in child.find():
                        rtn.append(result)
                return rtn
        

        我更喜欢生成器。此外,我并不特别喜欢您的某些节点具有children 属性而其他节点没有这一事实。我会确保他们所有人都有children,它可以是空的或非空的。那么,代码就变成了:

        def find_leaves(self):
            if self.children:
                for child in self.children:
                    yield from child.find_leaves()
            else:
                yield self
        

        【讨论】:

        • 感谢您提供这个非常好的答案。我不知道yield(和生成器)也不知道[self]。我现在将阅读有关它们的文档以了解它们的工作原理。它正在工作!
        • @cdlane for result in child.find() 解压缩列表,然后将每个项目添加到 rtn。我没有测试它(我只测试了find_leaves),但我认为它应该可以工作......
        • 你是对的,我没有看到嵌套循环。虽然我认为.extend() 比整个额外循环更有意义!
        • @cdlane 是的,extend 会更好,但我认为这会更容易理解...
        猜你喜欢
        • 2018-12-31
        • 2010-12-12
        • 2017-07-25
        • 1970-01-01
        • 1970-01-01
        • 2014-09-02
        • 1970-01-01
        • 1970-01-01
        • 2012-02-10
        相关资源
        最近更新 更多