Auf der Suche nach einer guten Python Tree-Datenstruktur [geschlossen]


92

Ich suche eine gute Tree-Datenstrukturklasse. Ich bin auf dieses Paket gestoßen , aber da ich relativ neu in Python bin (keine Programmierung), weiß ich nicht, ob es bessere gibt.

Ich würde gerne von den Pythonisten hier hören - haben Sie ein Lieblingsbaumskript, das Sie regelmäßig verwenden und empfehlen würden?

[Bearbeiten]

Zur Verdeutlichung meine ich mit 'Baum' einen einfachen ungeordneten Baum (Hmm, das ist eine rekursive Definition - aber hoffentlich klärt das die Dinge etwas). In Bezug darauf, wofür ich den Baum brauche (dh Anwendungsfall). Ich lese Baumdaten aus einer flachen Datei und muss aus den Daten einen Baum erstellen und alle Knoten im Baum durchlaufen.



1
In der Zwischenzeit gibt es eine einfache, einfache und erweiterbare Baumdatenstruktur
c0fec0de

Antworten:


38

Roll deinen eigenen. Modellieren Sie beispielsweise Ihren Baum einfach als Listenliste. Sie sollten Ihre spezifischen Bedürfnisse detaillieren, bevor die Leute bessere Empfehlungen geben können.

Als Antwort auf die Frage von HelloGoodbye ist dies ein Beispielcode zum Iterieren eines Baums.

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

Ein Haken ist, dass diese rekursive Implementierung O (n log n) ist. Es funktioniert gut für alle Bäume, mit denen ich umgehen muss. Vielleicht würde der Subgenerator in Python 3 helfen.


Wie können Sie alle Elemente in einem solchen Baum auf "pythonische" Weise durchlaufen?
HelloGoodbye

Normalerweise iterieren Sie einen Baum mit DFS oder BFS. Normalerweise implementiere ich einen Generator mit DFS wie def walk (tree): ...
Wai Yip Tung

1
Was ist DFS und BFS? Diese Akronyme sind für mich neu.
HelloGoodbye

1
Beispielcode für DFS hinzugefügt.
Wai Yip Tung

1
Tiefensuche bedeutet, dass die Kinder eines Knotens vor seinen Geschwistern besucht werden. Wenn Sie also "[A, [B, [C, D]], [E, [F, G]]] haben, dann besuchen Sie, vorausgesetzt Sie besuchen B vor E, auch C und D vor E. Breite- Erste Suche bedeutet, dass alle Knoten auf derselben Ebene vor einem ihrer Kinder besucht werden, sodass B und E beide vor C, D, F oder G besucht werden.
Mark Reed

76

Sie können einen schönen Baum von Diktaten wie diesen bauen:

import collections

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

Es ist vielleicht nicht genau das, was Sie wollen, aber es ist sehr nützlich! Werte werden nur in den Blattknoten gespeichert. Hier ist ein Beispiel, wie es funktioniert:

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

Weitere Informationen finden Sie im Kern .


1
Wow, die Verwendung von defaultdict ist eine brillante Idee!
Laike9m

Toll und ich wand immer mit Versuch außer mit Setzern.
Jimmy Kane

5
Ein Nachteil ist, dass es sehr schwierig ist, Methoden im Zusammenhang mit Baummanipulationen hinzuzufügen. Auch dies ist im Wiki und heißt Autovivification: en.wikipedia.org/wiki/Autovivification#Python
denfromufa

41

Ich fand ein Modul von Brett Alistair Kromkamp, ​​das nicht abgeschlossen wurde. Ich habe es fertiggestellt und auf Github veröffentlicht und in treelib(Original pyTree) umbenannt:

https://github.com/caesar0301/treelib

Möge es Ihnen helfen ...


5
Lizenz ist GPL, wie schade
denfromufa

12
Diese Lizenz wurde vergeben, als ich überhaupt nicht wusste, was eine Lizenz bedeutet. Ich weiß, dass es ein einfaches, aber nützliches Modul ist. Seit Version 1.3.0 verteile ich es unter der Apache-Lizenz. Jetzt können Sie es dort verwenden, wo Sie es benötigen, und das ursprüngliche Urheberrecht deklamieren.
Caesar0301

9

Aufbauend auf der oben angegebenen Antwort mit dem einzeiligen Baum unter Verwendung von defaultdict können Sie daraus eine Klasse machen. Auf diese Weise können Sie Standardeinstellungen in einem Konstruktor einrichten und auf andere Weise darauf aufbauen.

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

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

In diesem Beispiel können Sie eine Rückreferenz erstellen, damit jeder Knoten auf seinen übergeordneten Knoten im Baum verweisen kann.

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

Als Nächstes können Sie __setattr__ im Klassenbaum sogar überschreiben, sodass es beim erneuten Zuweisen des übergeordneten Elements als untergeordnetes Element von diesem übergeordneten Element entfernt wird. Viele coole Sachen mit diesem Muster.


Das Elternteil ist im obigen Beispiel für t [0] [1] [2] gebrochen. AttributeError: 'int' Objekt hat kein Attribut 'parent'
MatthieuBizien

@oao Das ist nicht kaputt. Sie geben t [0] [1] [2] = 3 an. Daher ist t [0] [1] [2] kein Standarddikttyp, sondern ein Zahlentyp (da Standarddikt verwendet wird, um Standardeinstellungen für vorzunehmen fehlende Elemente). Wenn Sie möchten, dass es sich um ein Standarddiktat handelt, müssen Sie t [0] [1] [2] ohne die Zuweisung verwenden.
Sandy Chapman

7

Für einen Baum mit bestellten Kindern würde ich normalerweise so etwas tun (obwohl etwas weniger allgemein, zugeschnitten auf das, was ich tue):

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)

Sie könnten etwas tun, das mit a dictoder using vergleichbar ist , DictMixinoder es sind modernere Nachkommen, wenn Sie möchten, dass ungeordnete Kinder per Schlüssel aufgerufen werden.


7

Es kann sich lohnen, einen eigenen Tree Wrapper zu schreiben, der auf einem azyklisch gerichteten Diagramm unter Verwendung der networkx- Bibliothek basiert .


5

Eine weitere gute und benutzerfreundliche Implementierung von Bäumen in Python ist pyTree: https://github.com/caesar0301/pyTree

pyTree bietet auch die Möglichkeit, den Baum zu visualisieren:

Harry[harry]
|___ Jane[jane]
|    |___ Diane[diane]
|         |___ George[george]
|              |___ Jill[jill]
|         |___ Mary[mary]
|    |___ Mark[mark]
|___ Bill[bill]

2
Ein Plus für den Versuch, den Baum zu visualisieren, obwohl das Rendering schrecklich war.
HelloGoodbye


4

Hier ist etwas, woran ich gearbeitet habe.

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)

Verwendung als solche (Zahlen als Beispielwerte): t = Tree(1, Tree(2, Tree(4)), Tree(3, Tree(5)))


3

Würde BTrees helfen? Sie sind Teil des Codes der Zope Object Database. Das Herunterladen des gesamten ZODB-Pakets ist etwas übertrieben, aber ich hoffe, dass das BTrees-Modul zumindest etwas trennbar ist.


2

Ich denke aus meiner eigenen Erfahrung mit Problemen mit fortgeschritteneren Datenstrukturen, dass das Wichtigste, was Sie hier tun können, darin besteht, ein gutes Wissen über das allgemeine Konzept von Tress als Datenstrukturen zu erlangen. Wenn Sie den grundlegenden Mechanismus hinter dem Konzept verstehen, ist es recht einfach, die Lösung zu implementieren, die zu Ihrem Problem passt. Es gibt viele gute Quellen, die das Konzept beschreiben. Was mich vor Jahren bei diesem speziellen Problem "gerettet" hat, war Abschnitt 2.3 in "Die Kunst der Computerprogrammierung".

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.