【问题标题】:Looking for a good Python Tree data structure [closed]寻找一个好的 Python Tree 数据结构 [关闭]
【发布时间】:2010-06-09 21:05:23
【问题描述】:

我正在寻找一个好的 Tree 数据结构类。我遇到过this package,但由于我对 Python 比较陌生(不是编程),我不知道是否有更好的。

我想听听 Pythonistas 的来信 - 您是否有一个您经常使用并推荐的最喜欢的树脚本?

[编辑]

为了澄清,“树”是指一个简单的无序树(嗯,这有点递归定义 - 但希望能在一定程度上澄清事情)。关于我需要树的用途(即用例)。我正在从平面文件中读取树数据,我需要根据数据构建树并遍历树中的所有节点。

【问题讨论】:

标签: python


【解决方案1】:

你可以像这样构建一个漂亮的字典树:

import collections

def Tree():
    return collections.defaultdict(Tree)

它可能不是您想要的,但它非常有用!值仅保存在叶节点中。以下是其工作原理的示例:

>>> t = Tree()
>>> t
defaultdict(<function tree at 0x2142f50>, {})
>>> t[1] = "value"
>>> t[2][2] = "another value"
>>> t
defaultdict(<function tree at 0x2142f50>, {1: 'value', 2: defaultdict(<function tree at 0x2142f50>, {2: 'another value'})}) 

欲了解更多信息,请查看the gist

【讨论】:

  • 哇,使用 defaultdict 真是个好主意!
  • 太棒了,我一直在使用 try 除了 setter。
  • 一个缺点是添加与树操作相关的方法非常棘手。这也在 wiki 中,称为 autovivification:en.wikipedia.org/wiki/Autovivification#Python
【解决方案2】:

我发现了一个未完成的由 Brett Alistair Kromkamp 编写的模块。我完成并在github上公开并重命名为treelib(原pyTree):

https://github.com/caesar0301/treelib

希望对你有帮助....

【讨论】:

  • license是GPL,可惜了
  • 这个许可证是在我什至不知道许可证是什么意思的时候给出的。我知道它是一个简单但有用的模块。从 1.3.0 版开始,我根据 Apache 许可证重新分发它。现在您可以在需要的地方使用它,并声明原始版权​​。
【解决方案3】:

滚动你自己的。例如,只需将您的树建模为列表列表。您应该详细说明您的具体需求,然后人们才能提供更好的建议。

针对 HelloGoodbye 的问题,这是一个迭代树的示例代码。

def walk(node):
    """ iterate tree in pre-order depth-first search order """
    yield node
    for child in node.children:
        for n in walk(child):
            yield n

一个问题是这个递归实现是 O(n log n)。它适用于我必须处理的所有树木。也许 Python 3 中的子生成器会有所帮助。

【讨论】:

  • 你如何以“pythonic”的方式遍历这种树中的所有元素?
  • 通常使用 DFS 或 BFS 迭代树。我通常使用 DFS 来实现生成器,例如 def walk(tree): ...
  • 什么是 DFS 和 BFS?这些首字母缩写词对我来说是新的。
  • 添加了 DFS 的示例代码。
  • 深度优先搜索意味着节点的子节点在其兄弟节点之前被访问。所以如果你有` [ A, [ B, [C, D] ], [ E, [ F, G ] ] ]`,那么,假设你在E之前访问了B,那么你也在E之前访问了C和D。 first search 意味着同一级别的所有节点都在其任何子节点之前被访问,因此 B 和 E 都将在 C、D、F 或 G 中的任何一个之前被访问。
【解决方案4】:

the answer given above with the single line Tree using defaultdict 为基础,您可以将其设为一个类。这将允许您在构造函数中设置默认值并以其他方式构建它。

class Tree(defaultdict):
    def __call__(self):
        return Tree(self)

    def __init__(self, parent):
        self.parent = parent
        self.default_factory = self

此示例允许您进行反向引用,以便每个节点都可以引用其在树中的父节点。

>>> t = Tree(None)
>>> t[0][1][2] = 3
>>> t
defaultdict(defaultdict(..., {...}), {0: defaultdict(defaultdict(..., {...}), {1: defaultdict(defaultdict(..., {...}), {2: 3})})})
>>> t[0][1].parent
defaultdict(defaultdict(..., {...}), {1: defaultdict(defaultdict(..., {...}), {2: 3})})
>>> t2 = t[0][1]
>>> t2
defaultdict(defaultdict(..., {...}), {2: 3})
>>> t2[2]
3

接下来,您甚至可以在类 Tree 上覆盖 __setattr__ ,以便在重新分配父级时,将其作为子级从该父级中删除。这种模式有很多很酷的东西。

【讨论】:

  • 上例中 t[0][1][2] 的父级已损坏。 AttributeError: 'int' 对象没有属性 'parent'
  • @oao 这没有坏。您正在指定 t[0][1][2] = 3。因此 t[0][1][2] 不会是 defaultdict 类型,而是 Number 类型(因为 defaultdict 用于为缺少元素)。如果您希望它成为默认字典,则需要使用 t[0][1][2] 而不进行赋值。
【解决方案5】:

对于一棵有有序孩子的树,我通常会做类似这样的事情(虽然不太通用,但适合我正在做的事情):

class TreeNode(list):

    def __init__(self, iterable=(), **attributes):
        self.attr = attributes
        list.__init__(self, iterable)

    def __repr__(self):
        return '%s(%s, %r)' % (type(self).__name__, list.__repr__(self),
            self.attr)

您可以做一些与dict 或使用DictMixin 类似的事情,或者如果您希望通过键访问无序子项,则可以使用更现代的后代。

【讨论】:

    【解决方案6】:

    可能值得使用networkx 库基于无环有向图编写自己的树包装器。

    【讨论】:

      【解决方案7】:

      这是我正在做的事情。

      class Tree:
          def __init__(self, value, *children):
              '''Singly linked tree, children do not know who their parent is.
              '''
              self.value = value
              self.children = tuple(children)
      
          @property
          def arguments(self):
              return (self.value,) + self.children
      
          def __eq__(self, tree):
              return self.arguments == tree.arguments
      
          def __repr__(self):
              argumentStr = ', '.join(map(repr, self.arguments))
              return '%s(%s)' % (self.__class__.__name__, argumentStr)
      

      按原样使用(数字用作示例值): t = Tree(1, Tree(2, Tree(4)), Tree(3, Tree(5)))

      【讨论】:

        【解决方案8】:

        BTrees 会帮忙吗?它们是 Zope 对象数据库代码的一部分。下载整个 ZODB 包有点矫枉过正,但我​​希望 BTrees 模块至少在某种程度上是可分离的。

        【讨论】:

          【解决方案9】:

          我认为,根据我自己在更高级数据结构问题上的经验,你可以在这里做的最重要的事情是很好地了解作为数据结构的树的一般概念。如果您了解该概念背后的基本机制,那么实施适合您问题的解决方案将非常容易。有很多很好的资料来描述这个概念。几年前在这个特定问题上“拯救”了我的是“计算机编程艺术”中的第 2.3 节。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-07-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-08-27
            • 2011-11-13
            相关资源
            最近更新 更多