【问题标题】:python returning a list from a recursive methodpython从递归方法返回一个列表
【发布时间】:2015-06-25 11:07:46
【问题描述】:

我正在使用本书中描述的二叉树 problem solving with algorithms and data structures

class BinaryTree:
    def __init__(self,rootObj):
        self.key = rootObj
        self.leftChild = None
        self.rightChild = None

已经有如下定义的前序遍历方法。

def preorder(tree):
    if tree:
        print(tree.self.key)
        preorder(tree.getLeftChild())
        preorder(tree.getRightChild())

我只想添加访问的节点列表的返回值。所以我可以做类似的事情

for i in preorder(tree):
    etc...

我无法从递归方法返回列表。递归在遇到“返回”时立即停止,我尝试过使用

return [tree.self.key] + preorder()

或者

yield ...

有什么想法吗?

【问题讨论】:

  • 您遇到什么错误?是关于连接 None 和 list 的吗?
  • 1)。 preorder() 似乎是一个辅助函数,实际上并不是 BinaryTree 类的方法,因此将其称为方法有点令人困惑。 2)。如果treeBinaryTree 的一个实例,那么tree.self.key 是错误的。 3)。在 Python 中,您很少需要 getter(或 setter)方法,您只需直接访问属性即可。例如,preorder(tree.leftChild).

标签: python recursion binary-tree preorder


【解决方案1】:

您确定要在打印时使用tree.self.key 而不仅仅是tree.key

否则,使用yield from (Python 3.3+) 的解决方案:

def preorder(tree):
    if tree:
        yield tree
        yield from preorder(tree.getLeftChild())
        yield from preorder(tree.getRightChild())

或者用简单的yield:

def preorder(tree):
    if tree:
        yield tree
        for e in preorder(tree.getLeftChild()):
            yield e
        for e in preorder(tree.getRightChild()):
            yield e

请注意,使用yieldyield from 会将函数转换为generator function;特别是,如果您想要一个实际列表(例如用于索引、切片或显示),您需要显式创建它:list(preorder(tree))

如果您有不同数量的孩子,很容易适应:

def preorder(tree):
    if tree:
        yield tree
        for child in tree.children:
            yield from preorder(child)

【讨论】:

  • 既然是直接访问tree.key,不如使用preorder(tree.leftChild)preorder(tree.getRightChild)。此外,您应该提到,要以这种方式获取节点列表,您需要执行 nodes = list(preorder(tree))nodes = [node for node in preorder(tree)] 之类的操作。
  • 感谢您对列表的建议。至于您的另一点,我正在访问tree.key,因为我不想猜测是否有getKey() 方法,但我相信OP 的tree.self.key 可能有问题。已经有评论说 Python 中不需要 getter 和 setter,但这里真的不是重点。
  • 我提到显示如何创建一个列表,因为问题的标题。另请注意,它应该是print tree.key,而不是yield tree.key——OP 想要一个节点列表,而不是节点和键的混合列表。
  • 没有节点,只有键(通过归纳:preorder 只产生 tree.keypreorder 产生的)。但实际上 OP 似乎想要一个节点列表,所以我已经编辑了 yield tree
【解决方案2】:

您可以简单地为每个递归调用返回一个连接列表,它结合了当前键、左子树和右子树:

def preorder(tree):
        if tree:
            return ([tree.key] + preorder(tree.getLeftChild()) +
                    preorder(tree.getRightChild()))
        return []

对于 n 叉树:

def preorder(tree):
    if tree:
        lst = [tree.key]
        for child in tree.children:
            lst.extend(preorder(child))
        return lst
    return []

【讨论】:

  • 感谢您的回复完美。只是徘徊,如果它不是二叉树,我怎么能遍历所有的孩子,例如def preorder(tree): if tree: return [tree.key] + [preorder(child, msg) for child in tree.children]
  • @DamianSavage 是的,但是在这里使用列表解析会导致列表列表,因为每个 preorder 调用都会返回一个列表。您可以使用循环来实现此目的。我会更新我的答案。
  • 您可以使用sum: return sum((preorder(child) for child in tree.children), [tree.key]),而不是显式循环。
【解决方案3】:

您实际上必须从递归函数中返回一个值(目前,它只是打印值)。而且您应该随时构建列表,并且可能会稍微清理一下代码 - 像这样:

def preorder(tree):
    if not tree:
        return []
    # optionally, you can print the key in this line: print(self.key)
    return [tree.key] + preorder(tree.leftChild) + preorder(tree.rightChild)

【讨论】:

  • 非常感谢您的回复。我正在使用python v3.4,我没有让yield表达式工作,我在迭代器和生成器之间仍然有点迷失......无论如何,这个'如果不是树返回空列表'解决了我遇到的问题'可以不是 + NoneType'
【解决方案4】:

您可以将第二个参数添加到 preorder 函数,类似于

def preorder(tree, visnodes):
    if tree:
        visnodes.append(tree.self.key)
        print(tree.self.key)
        preorder(tree.getLeftChild(), visnodes)
        preorder(tree.getRightChild(), visnodes)

...
vn = []
preorder(tree, vn)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-24
    • 2018-10-25
    • 1970-01-01
    • 1970-01-01
    • 2016-05-27
    相关资源
    最近更新 更多