寻找一个好的Python Tree数据结构


92

我正在寻找一个好的Tree数据结构类。我遇到过这个软件包,但是由于我对Python相对较新(不是编程),所以我不知道是否还有更好的软件包

我想在这里听到来自Pythonista的消息-您是否有喜欢的树脚本经常使用并会推荐使用?

[编辑]

为了澄清,用“树”来表示,是指一个简单的无序树(嗯,这是一个递归定义,但希望可以使情况有所澄清)。关于我需要的树(即用例)。我正在从一个平面文件中读取树数据,并且需要从该数据构建一棵树并遍历树中的所有节点。



1
同时,有一个简单,轻便和可扩展的树数据结构:anytree.readthedocs.io/en/latest
c0fec0de

Answers:


38

自己动手。例如,仅将树建模为列表列表。在人们可以提供更好的建议之前,您应该详细说明自己的特定需求。

为了回答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”方式遍历此类树中的所有元素?
HelloGoodbye 2014年

通常,您使用DFS或BFS迭代树。我通常使用像def walk(tree)这样的DFS实现一个生成器:...
惠业东

1
什么是DFS和BFS?这些缩写对我来说是新的。
HelloGoodbye 2014年

1
添加了DFS的示例代码。
威业东

1
深度优先搜索意味着在节点的兄弟节点之前访问节点的子节点。因此,如果您有`[[A,[B,[C,D]],[E,[F,G]]]`,那么,假设您在E之前访问B,您也将在E之前访问C和D。第一检索装置在同级别的所有节点之前的任何子女被访问,所以B和E将两者之前的任何C,d,F或G的访问
马克·里德

76

您可以像这样构建一棵漂亮的辞典树:

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'})}) 

有关更多信息,请查看要点


1
哇,使用defaultdict是一个好主意!
laike9m 2013年

太好了,除了设置员,我总是尝试使用围墙。
Jimmy Kane

5
缺点之一是添加与树操作有关的方法非常棘手。这在Wiki中也称为自动生存:en.wikipedia.org/wiki/Autovivification#Python
denfromufa 2014年

41

我发现Brett Alistair Kromkamp编写的模块尚未完成。我完成并在github上将其公开,并将其重命名为treelib(original pyTree):

https://github.com/caesar0301/treelib

可以帮助您...


5
许可证是GPL,真可惜
denfromufa 2014年

12
该许可证是在我什至不知道许可证含义的情况下颁发的。我知道它是一个简单但有用的模块。从1.3.0版开始,我根据Apache许可证重新分发它。现在,您可以在声明原始版权​​的情况下在需要的地方使用它。
caesar0301 2014年

9

使用defaultdict在单行Tree上面给出的答案的基础上,可以将其设为类。这将允许您在构造函数中设置默认值,并以其他方式在其上进行构建。

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的:“诠释”对象有没有属性“父”
MatthieuBizien

@oao这没有坏。您要指定t [0] [1] [2] =3。因此,t [0] [1] [2]不会是defaultdict类型,而是Number类型(因为defaultdict用于为缺少元素)。如果希望它成为默认值,则需要使用t [0] [1] [2]而不进行分配。
桑迪查普曼

7

对于有顺序的孩子的树,我通常会做这样的事情(尽管通用性稍差一些,是针对我的工作量身定制的):

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)

如果要通过密钥访问无序的子代,则可以执行与a dict或use DictMixin或它或更现代的后代类似的操作。




4

这是我正在做的事情。

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)))


3

B树的帮助?它们是Zope对象数据库代码的一部分。下载整个ZODB软件包有点过分,但是我希望BTrees模块至少可以分开。


2

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.