Recherche d'une bonne structure de données Python Tree [fermé]

92

Je recherche une bonne classe de structure de données Tree. Je suis tombé sur ce paquet , mais comme je suis relativement nouveau dans Python (pas en programmation), je ne sais pas s'il y en a de meilleurs.

J'aimerais entendre les pythonistes ici - avez-vous un script d'arborescence préféré que vous utilisez régulièrement et que vous recommanderiez?

[Éditer]

Pour clarifier, par «arbre», je veux dire un simple arbre non ordonné (Hmm, c'est un peu une définition récursive - mais j'espère que cela clarifie un peu les choses). En ce qui concerne ce pour quoi j'ai besoin de l'arbre (c'est-à-dire le cas d'utilisation). Je lis des données d'arbre à partir d'un fichier plat et je dois créer un arbre à partir des données et parcourir tous les nœuds de l'arborescence.

morpheous
la source
1
En attendant, il existe une structure de données arborescente simple, légère et extensible: anytree.readthedocs.io/en/latest
c0fec0de

Réponses:

38

Roulez le vôtre. Par exemple, modélisez simplement votre arbre sous forme de liste de liste. Vous devez détailler vos besoins spécifiques avant que les gens puissent fournir une meilleure recommandation.

En réponse à la question de HelloGoodbye, voici un exemple de code pour itérer un arbre.

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

Un problème est que cette implémentation récursive est O (n log n). Cela fonctionne bien pour tous les arbres avec lesquels je dois m'occuper. Peut-être que le sous-générateur de Python 3 aiderait.

Wai Yip Tung
la source
Comment faites-vous une boucle sur tous les éléments d'un tel arbre d'une manière «pythonique»?
HelloGoodbye
En règle générale, vous parcourez une arborescence à l'aide de DFS ou BFS. J'implémente généralement un générateur utilisant DFS comme def walk (tree): ...
Wai Yip Tung
1
Qu'est-ce que DFS et BFS? Ces acronymes sont nouveaux pour moi.
HelloGoodbye
1
Ajout d'un exemple de code pour DFS.
Wai Yip Tung le
1
La recherche en profondeur d'abord signifie que les enfants d'un nœud sont visités avant ses frères et sœurs. donc si vous avez `[A, [B, [C, D]], [E, [F, G]]]`, alors, en supposant que vous visitez B avant E, vous visitez également C et D avant E. Largeur- La première recherche signifie que tous les nœuds du même niveau sont visités avant l'un de leurs enfants, donc B et E seraient tous deux visités avant l'un des points C, D, F ou G.
Mark Reed
76

Vous pouvez construire un bel arbre de dictionnaires comme ceci:

import collections

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

Ce n'est peut-être pas exactement ce que vous voulez mais c'est très utile! Les valeurs sont enregistrées uniquement dans les nœuds feuilles. Voici un exemple de son fonctionnement:

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

Pour plus d'informations, jetez un œil à l'essentiel .

Stefan
la source
1
Wow, utiliser defaultdict est une idée géniale!
laike9m
Super et j'utilise toujours essayer sauf avec les setters.
Jimmy Kane
5
un inconvénient est qu'il est très délicat d'ajouter des méthodes liées aux manipulations d'arbres. également ceci est dans wiki et appelé autovivification: en.wikipedia.org/wiki/Autovivification#Python
denfromufa
41

J'ai trouvé un module écrit par Brett Alistair Kromkamp qui n'était pas terminé. Je l'ai terminé et je l'ai rendu public sur github et l'ai renommé comme treelib(original pyTree):

https://github.com/caesar0301/treelib

Que cela vous aide ...

caesar0301
la source
5
licence est GPL, quel dommage
denfromufa
12
Cette licence a été donnée alors que je ne savais même pas ce que signifiait une licence. Je sais que c'est un module simple mais utile. Depuis la version 1.3.0, je le redistribue sous licence Apache. Vous pouvez maintenant l'utiliser là où vous en avez besoin avec la déclamation des droits d'auteur d'origine.
caesar0301
9

En vous basant sur la réponse donnée ci-dessus avec l'arborescence à une seule ligne utilisant defaultdict , vous pouvez en faire une classe. Cela vous permettra de configurer les valeurs par défaut dans un constructeur et de construire dessus par d'autres moyens.

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

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

Cet exemple vous permet de faire une référence arrière afin que chaque nœud puisse faire référence à son parent dans l'arborescence.

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

Ensuite, vous pouvez même remplacer __setattr__ sur l'arborescence de classe afin que lors de la réaffectation du parent, il le supprime en tant qu'enfant de ce parent. Beaucoup de trucs sympas avec ce modèle.

Sandy Chapman
la source
Le parent est rompu pour t [0] [1] [2] dans l'exemple ci-dessus. AttributeError: l'objet 'int' n'a pas d'attribut 'parent'
MatthieuBizien
@oao Ce n'est pas cassé. Vous spécifiez t [0] [1] [2] = 3. Par conséquent, t [0] [1] [2] ne sera pas un type defaultdict, mais un type Number (comme defaultdict est utilisé pour définir les valeurs par défaut pour éléments manquants). Si vous voulez que ce soit un defaultdict, vous devez utiliser t [0] [1] [2] sans l'affectation.
Sandy Chapman
7

Pour un arbre avec des enfants ordonnés, je ferais généralement quelque chose comme ça (bien qu'un peu moins générique, adapté à ce que je fais):

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)

Vous pouvez faire quelque chose de comparable avec un dictou en utilisant ou avec DictMixindes descendants plus modernes si vous voulez que les enfants non ordonnés soient accessibles par clé.

Matt Anderson
la source
7

Cela peut valoir la peine d'écrire votre propre wrapper d'arbre basé sur un graphe dirigé acyclique en utilisant la bibliothèque networkx .

Andrew Walker
la source
5

PyTree est une autre implémentation bonne et facile à utiliser des arbres en Python: https://github.com/caesar0301/pyTree

pyTree fournit également la possibilité de visualiser l'arbre:

Harry[harry]
|___ Jane[jane]
|    |___ Diane[diane]
|         |___ George[george]
|              |___ Jill[jill]
|         |___ Mary[mary]
|    |___ Mark[mark]
|___ Bill[bill]
aronadaal
la source
2
Un plus pour essayer de visualiser l'arbre, même si le rendu était horrible.
HelloGoodbye
1
Duplicata de la réponse déjà existante de casear0301 .
Jean-François Corbett
4

Voici quelque chose sur lequel je travaillais.

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)

Utiliser en tant que tel (nombres utilisés comme valeurs d'exemple): t = Tree(1, Tree(2, Tree(4)), Tree(3, Tree(5)))

Aaron Robson
la source
3

Would arbre binaire aide? Ils font partie du code de la base de données d'objets Zope. Le téléchargement de l'ensemble du package ZODB est un peu exagéré, mais j'espère que le module BTrees serait au moins quelque peu séparable.

Jenn D.
la source
2

Je pense, d'après ma propre expérience sur les problèmes avec des structures de données plus avancées, que la chose la plus importante que vous puissiez faire ici, c'est d'acquérir une bonne connaissance du concept général d'arbres en tant que structures de données. Si vous comprenez le mécanisme de base derrière le concept, il sera assez facile de mettre en œuvre la solution qui correspond à votre problème. Il existe de nombreuses bonnes sources décrivant le concept. Ce qui m'a "sauvé" il y a des années sur ce problème particulier était la section 2.3 de "L'art de la programmation informatique".

U. Hjort
la source