Comment puis-je implémenter une arborescence en Python?

Réponses:

233

anytree

Je recommande https://pypi.python.org/pypi/anytree (je suis l'auteur)

Exemple

from anytree import Node, RenderTree

udo = Node("Udo")
marc = Node("Marc", parent=udo)
lian = Node("Lian", parent=marc)
dan = Node("Dan", parent=udo)
jet = Node("Jet", parent=dan)
jan = Node("Jan", parent=dan)
joe = Node("Joe", parent=dan)

print(udo)
Node('/Udo')
print(joe)
Node('/Udo/Dan/Joe')

for pre, fill, node in RenderTree(udo):
    print("%s%s" % (pre, node.name))
Udo
├── Marc
   └── Lian
└── Dan
    ├── Jet
    ├── Jan
    └── Joe

print(dan.children)
(Node('/Udo/Dan/Jet'), Node('/Udo/Dan/Jan'), Node('/Udo/Dan/Joe'))

Caractéristiques

anytree dispose également d'une puissante API avec:

  • création d'arbre simple
  • modification d'arbre simple
  • pré-commande d'itération d'arbre
  • itération d'arbre post-commande
  • résoudre les chemins de nœuds relatifs et absolus
  • marchant d'un nœud à un autre.
  • rendu d'arbre (voir l'exemple ci-dessus)
  • connexion / déconnexion de nœuds
c0fec0de
la source
31
Tout simplement la meilleure réponse, d'autres réinventent la roue.
Ondrej
66
Il est bon de divulguer que vous êtes l'auteur du package que vous recommandez dans votre réponse.
John Y
3
@ c0fec0de je t'aime !!!! Cette bibliothèque est incroyable, a même une fonctionnalité de visualisation
layser
2
@Ondrej et les autres réponses sont moins dépendantes et la question d'origine portait sur les structures de données intégrées. Bien qu'il anytrees'agisse probablement d'une excellente bibliothèque, il s'agit d'une question python, pas d'une question Node.js.
Rob Rose
Je suis tombé sur cette réponse via Google. Cette bibliothèque est vraiment sympa. J'aime particulièrement la possibilité d'utiliser la classe mixin pour créer un arbre de n'importe quel objet!
Rÿck Nöthing
104

Python n'a pas la gamme assez étendue de structures de données "intégrées" comme Java. Cependant, comme Python est dynamique, une arborescence générale est facile à créer. Par exemple, un arbre binaire peut être:

class Tree:
    def __init__(self):
        self.left = None
        self.right = None
        self.data = None

Vous pouvez l'utiliser comme ceci:

root = Tree()
root.data = "root"
root.left = Tree()
root.left.data = "left"
root.right = Tree()
root.right.data = "right"
Greg Hewgill
la source
109
Cela n'explique pas vraiment beaucoup sur la façon de faire une implémentation d'arbre utile.
Mike Graham
14
La question est étiquetée avec Python3, il n'est donc pas nécessaire de dériver class Treede l'objet
cfi
3
@cfi La dérivation objectn'est parfois qu'une indication: si une classe hérite d'aucune autre classe de base, hérite explicitement de l'objet. Cela s'applique également aux classes imbriquées. Voir Google Python Style Guide
Konrad Reiche
16
@platzhirsch: Veuillez lire et citer la directive complètement: Google souligne explicitement que cela est nécessaire pour que le code Python 2 fonctionne comme prévu et recommandé pour améliorer la compatibilité avec Py3. Ici, nous parlons de code Py3. Il n'est pas nécessaire de faire un typage supplémentaire.
cfi
13
C'est un arbre binaire, pas un arbre général comme demandé.
Michael Dorner
49

Un arbre générique est un nœud avec zéro ou plusieurs enfants, chacun un nœud (arbre) approprié. Ce n'est pas la même chose qu'un arbre binaire, ce sont des structures de données différentes, bien que les deux partagent une certaine terminologie.

Il n'y a pas de structure de données intégrée pour les arbres génériques en Python, mais elle est facilement implémentée avec des classes.

class Tree(object):
    "Generic tree node."
    def __init__(self, name='root', children=None):
        self.name = name
        self.children = []
        if children is not None:
            for child in children:
                self.add_child(child)
    def __repr__(self):
        return self.name
    def add_child(self, node):
        assert isinstance(node, Tree)
        self.children.append(node)
#    *
#   /|\
#  1 2 +
#     / \
#    3   4
t = Tree('*', [Tree('1'),
               Tree('2'),
               Tree('+', [Tree('3'),
                          Tree('4')])])
Rudá Moura
la source
Incroyable, cela peut aussi être facilement utilisé comme graphique! Le seul problème que j'ai vu est: comment puis-je différencier le nœud gauche du nœud droit?
Ângelo Polotto
3
Par index des enfants. Gauche sera toujours des enfants [0] dans ce cas.
Freund Allein
38

Tu peux essayer:

from collections import defaultdict
def tree(): return defaultdict(tree)
users = tree()
users['harold']['username'] = 'hrldcpr'
users['handler']['username'] = 'matthandlersux'

Comme suggéré ici: https://gist.github.com/2012250

Ib33X
la source
si vous souhaitez étendre à une quantité arbitraire de niveaux, vérifiez: stackoverflow.com/a/43237270/511809
natbusa
cela masque le hachage de fonction intégré.
Tritium21
20
class Node:
    """
    Class Node
    """
    def __init__(self, value):
        self.left = None
        self.data = value
        self.right = None

class Tree:
    """
    Class tree will provide a tree as well as utility functions.
    """

    def createNode(self, data):
        """
        Utility function to create a node.
        """
        return Node(data)

    def insert(self, node , data):
        """
        Insert function will insert a node into tree.
        Duplicate keys are not allowed.
        """
        #if tree is empty , return a root node
        if node is None:
            return self.createNode(data)
        # if data is smaller than parent , insert it into left side
        if data < node.data:
            node.left = self.insert(node.left, data)
        elif data > node.data:
            node.right = self.insert(node.right, data)

        return node


    def search(self, node, data):
        """
        Search function will search a node into tree.
        """
        # if root is None or root is the search data.
        if node is None or node.data == data:
            return node

        if node.data < data:
            return self.search(node.right, data)
        else:
            return self.search(node.left, data)



    def deleteNode(self,node,data):
        """
        Delete function will delete a node into tree.
        Not complete , may need some more scenarion that we can handle
        Now it is handling only leaf.
        """

        # Check if tree is empty.
        if node is None:
            return None

        # searching key into BST.
        if data < node.data:
            node.left = self.deleteNode(node.left, data)
        elif data > node.data:
            node.right = self.deleteNode(node.right, data)
        else: # reach to the node that need to delete from BST.
            if node.left is None and node.right is None:
                del node
            if node.left == None:
                temp = node.right
                del node
                return  temp
            elif node.right == None:
                temp = node.left
                del node
                return temp

        return node






    def traverseInorder(self, root):
        """
        traverse function will print all the node in the tree.
        """
        if root is not None:
            self.traverseInorder(root.left)
            print root.data
            self.traverseInorder(root.right)

    def traversePreorder(self, root):
        """
        traverse function will print all the node in the tree.
        """
        if root is not None:
            print root.data
            self.traversePreorder(root.left)
            self.traversePreorder(root.right)

    def traversePostorder(self, root):
        """
        traverse function will print all the node in the tree.
        """
        if root is not None:
            self.traversePostorder(root.left)
            self.traversePostorder(root.right)
            print root.data


def main():
    root = None
    tree = Tree()
    root = tree.insert(root, 10)
    print root
    tree.insert(root, 20)
    tree.insert(root, 30)
    tree.insert(root, 40)
    tree.insert(root, 70)
    tree.insert(root, 60)
    tree.insert(root, 80)

    print "Traverse Inorder"
    tree.traverseInorder(root)

    print "Traverse Preorder"
    tree.traversePreorder(root)

    print "Traverse Postorder"
    tree.traversePostorder(root)


if __name__ == "__main__":
    main()
shivam garg
la source
3
Pouvez-vous ajouter quelques notes pour présenter votre code et votre implémentation?
Michele d'Amico
Merci pour l'implémentation complète de l'arbre binaire avec des fonctions utilitaires. Comme il s'agit de Python 2, j'ai créé un résumé pour l' implémentation de l'arbre binaire (Py3) pour les personnes ayant besoin d'une version Python 3.
CᴴᴀZ
16

Il n'y a pas d'arbres intégrés, mais vous pouvez facilement en créer un en sous-classant un type de nœud dans List et en écrivant les méthodes de traversée. Si tu fais ça, j'ai trouvé la bissecte utile.

Il existe également de nombreuses implémentations sur PyPi que vous pouvez parcourir.

Si je me souviens bien, la bibliothèque standard Python n'inclut pas de structures de données arborescentes pour la même raison que la bibliothèque de classes de base .NET ne le fait pas: la localité de la mémoire est réduite, ce qui entraîne plus de ratés de cache. Sur les processeurs modernes, il est généralement plus rapide d'apporter simplement une grande partie de la mémoire dans le cache, et les structures de données "riches en pointeurs" annulent l'avantage.

Justin R.
la source
2
FYI: Les interwebs sont enduits de haine contre Boost. Apparemment, c'est censé être une douleur ÉNORME à gérer, d'autant plus que son soutien a été interrompu. Je recommanderais donc de rester à l'écart de cela
inspecteurG4dget
Merci. Je n'ai eu aucun problème personnellement, mais je ne veux pas induire en erreur, j'ai donc supprimé cette référence.
Justin R.
11

J'ai implémenté un arbre enraciné comme un dictionnaire {child:parent}. Ainsi, par exemple avec le nœud racine 0, un arbre pourrait ressembler à ceci:

tree={1:0, 2:0, 3:1, 4:2, 5:3}

Cette structure permettait assez facilement de remonter le long d'un chemin depuis n'importe quel nœud jusqu'à la racine, ce qui était pertinent pour le problème sur lequel je travaillais.

patte
la source
1
C'est ainsi que j'envisageais de le faire, jusqu'à ce que je voie la réponse. Bien qu'un arbre soit un parent avec deux enfants, et si vous voulez descendre, vous pouvez le faire {parent:[leftchild,rightchild]}.
JFA
1
Une autre façon consiste à utiliser des listes de listes où le premier (ou plusieurs) élément de la liste est la valeur du nœud, et les deux listes imbriquées suivantes représentent ses sous-arbres gauche et droit (ou plus pour l'arbre n-aire).
pepr
9

La réponse de Greg Hewgill est excellente mais si vous avez besoin de plus de nœuds par niveau, vous pouvez utiliser une liste | dictionnaire pour les créer: Et puis utilisez la méthode pour y accéder par nom ou par ordre (comme id)

class node(object):
    def __init__(self):
        self.name=None
        self.node=[]
        self.otherInfo = None
        self.prev=None
    def nex(self,child):
        "Gets a node by number"
        return self.node[child]
    def prev(self):
        return self.prev
    def goto(self,data):
        "Gets the node by name"
        for child in range(0,len(self.node)):
            if(self.node[child].name==data):
                return self.node[child]
    def add(self):
        node1=node()
        self.node.append(node1)
        node1.prev=self
        return node1

Il suffit maintenant de créer une racine et de la construire: ex:

tree=node()  #create a node
tree.name="root" #name it root
tree.otherInfo="blue" #or what ever 
tree=tree.add() #add a node to the root
tree.name="node1" #name it

    root
   /
child1

tree=tree.add()
tree.name="grandchild1"

       root
      /
   child1
   /
grandchild1

tree=tree.prev()
tree=tree.add()
tree.name="gchild2"

          root
           /
        child1
        /    \
grandchild1 gchild2

tree=tree.prev()
tree=tree.prev()
tree=tree.add()
tree=tree.name="child2"

              root
             /   \
        child1  child2
       /     \
grandchild1 gchild2


tree=tree.prev()
tree=tree.goto("child1") or tree=tree.nex(0)
tree.name="changed"

              root
              /   \
         changed   child2
        /      \
  grandchild1  gchild2

Cela devrait vous suffire pour commencer à comprendre comment faire fonctionner cela

Bruno
la source
Il manque quelque chose dans cette réponse, j'essayais cette solution depuis 2 jours et je pense que vous avez un flux logique dans la méthode d'ajout d'objet. Je soumettrai ma réponse à cette question, veuillez vérifier cela et faites-moi savoir si je peux vous aider.
MAULIK MODI
8
class Tree(dict):
    """A tree implementation using python's autovivification feature."""
    def __missing__(self, key):
        value = self[key] = type(self)()
        return value

    #cast a (nested) dict to a (nested) Tree class
    def __init__(self, data={}):
        for k, data in data.items():
            if isinstance(data, dict):
                self[k] = type(self)(data)
            else:
                self[k] = data

fonctionne comme un dictionnaire, mais fournit autant de textes imbriqués que vous le souhaitez. Essayez ce qui suit:

your_tree = Tree()

your_tree['a']['1']['x']  = '@'
your_tree['a']['1']['y']  = '#'
your_tree['a']['2']['x']  = '$'
your_tree['a']['3']       = '%'
your_tree['b']            = '*'

fournira un dict imbriqué ... qui fonctionne comme un arbre en effet.

{'a': {'1': {'x': '@', 'y': '#'}, '2': {'x': '$'}, '3': '%'}, 'b': '*'}

... Si vous avez déjà un dict, il lancera chaque niveau dans un arbre:

d = {'foo': {'amy': {'what': 'runs'} } }
tree = Tree(d)

print(d['foo']['amy']['what']) # returns 'runs'
d['foo']['amy']['when'] = 'now' # add new branch

De cette façon, vous pouvez continuer à éditer / ajouter / supprimer chaque niveau de dict comme vous le souhaitez. Toutes les méthodes dict pour la traversée, etc., s'appliquent toujours.

natbusa
la source
2
Y a-t-il une raison pour laquelle vous avez choisi de prolonger dictau lieu de defaultdict? D'après mes tests, étendre defaultdictau lieu de dict puis ajouter self.default_factory = type(self)en haut d'init devrait fonctionner de la même manière.
Rob Rose
il me manque probablement quelque chose ici, comment naviguez-vous dans cette structure? il semble très difficile de passer des enfants aux parents, par exemple, ou aux frères et sœurs
Stormsson
6

J'ai implémenté des arbres à l'aide de dict imbriqués. C'est assez facile à faire et cela a fonctionné pour moi avec des ensembles de données assez volumineux. J'ai posté un exemple ci-dessous, et vous pouvez en voir plus sur le code Google

  def addBallotToTree(self, tree, ballotIndex, ballot=""):
    """Add one ballot to the tree.

    The root of the tree is a dictionary that has as keys the indicies of all 
    continuing and winning candidates.  For each candidate, the value is also
    a dictionary, and the keys of that dictionary include "n" and "bi".
    tree[c]["n"] is the number of ballots that rank candidate c first.
    tree[c]["bi"] is a list of ballot indices where the ballots rank c first.

    If candidate c is a winning candidate, then that portion of the tree is
    expanded to indicate the breakdown of the subsequently ranked candidates.
    In this situation, additional keys are added to the tree[c] dictionary
    corresponding to subsequently ranked candidates.
    tree[c]["n"] is the number of ballots that rank candidate c first.
    tree[c]["bi"] is a list of ballot indices where the ballots rank c first.
    tree[c][d]["n"] is the number of ballots that rank c first and d second.
    tree[c][d]["bi"] is a list of the corresponding ballot indices.

    Where the second ranked candidates is also a winner, then the tree is 
    expanded to the next level.  

    Losing candidates are ignored and treated as if they do not appear on the 
    ballots.  For example, tree[c][d]["n"] is the total number of ballots
    where candidate c is the first non-losing candidate, c is a winner, and
    d is the next non-losing candidate.  This will include the following
    ballots, where x represents a losing candidate:
    [c d]
    [x c d]
    [c x d]
    [x c x x d]

    During the count, the tree is dynamically updated as candidates change
    their status.  The parameter "tree" to this method may be the root of the
    tree or may be a sub-tree.
    """

    if ballot == "":
      # Add the complete ballot to the tree
      weight, ballot = self.b.getWeightedBallot(ballotIndex)
    else:
      # When ballot is not "", we are adding a truncated ballot to the tree,
      # because a higher-ranked candidate is a winner.
      weight = self.b.getWeight(ballotIndex)

    # Get the top choice among candidates still in the running
    # Note that we can't use Ballots.getTopChoiceFromWeightedBallot since
    # we are looking for the top choice over a truncated ballot.
    for c in ballot:
      if c in self.continuing | self.winners:
        break # c is the top choice so stop
    else:
      c = None # no candidates left on this ballot

    if c is None:
      # This will happen if the ballot contains only winning and losing
      # candidates.  The ballot index will not need to be transferred
      # again so it can be thrown away.
      return

    # Create space if necessary.
    if not tree.has_key(c):
      tree[c] = {}
      tree[c]["n"] = 0
      tree[c]["bi"] = []

    tree[c]["n"] += weight

    if c in self.winners:
      # Because candidate is a winner, a portion of the ballot goes to
      # the next candidate.  Pass on a truncated ballot so that the same
      # candidate doesn't get counted twice.
      i = ballot.index(c)
      ballot2 = ballot[i+1:]
      self.addBallotToTree(tree[c], ballotIndex, ballot2)
    else:
      # Candidate is in continuing so we stop here.
      tree[c]["bi"].append(ballotIndex)
gaefan
la source
5

J'ai publié une implémentation d'arborescence Python [3] sur mon site: http://www.quesucede.com/page/show/id/python_3_tree_implementation .

J'espère que c'est utile,

Ok, voici le code:

import uuid

def sanitize_id(id):
    return id.strip().replace(" ", "")

(_ADD, _DELETE, _INSERT) = range(3)
(_ROOT, _DEPTH, _WIDTH) = range(3)

class Node:

    def __init__(self, name, identifier=None, expanded=True):
        self.__identifier = (str(uuid.uuid1()) if identifier is None else
                sanitize_id(str(identifier)))
        self.name = name
        self.expanded = expanded
        self.__bpointer = None
        self.__fpointer = []

    @property
    def identifier(self):
        return self.__identifier

    @property
    def bpointer(self):
        return self.__bpointer

    @bpointer.setter
    def bpointer(self, value):
        if value is not None:
            self.__bpointer = sanitize_id(value)

    @property
    def fpointer(self):
        return self.__fpointer

    def update_fpointer(self, identifier, mode=_ADD):
        if mode is _ADD:
            self.__fpointer.append(sanitize_id(identifier))
        elif mode is _DELETE:
            self.__fpointer.remove(sanitize_id(identifier))
        elif mode is _INSERT:
            self.__fpointer = [sanitize_id(identifier)]

class Tree:

    def __init__(self):
        self.nodes = []

    def get_index(self, position):
        for index, node in enumerate(self.nodes):
            if node.identifier == position:
                break
        return index

    def create_node(self, name, identifier=None, parent=None):

        node = Node(name, identifier)
        self.nodes.append(node)
        self.__update_fpointer(parent, node.identifier, _ADD)
        node.bpointer = parent
        return node

    def show(self, position, level=_ROOT):
        queue = self[position].fpointer
        if level == _ROOT:
            print("{0} [{1}]".format(self[position].name,
                                     self[position].identifier))
        else:
            print("\t"*level, "{0} [{1}]".format(self[position].name,
                                                 self[position].identifier))
        if self[position].expanded:
            level += 1
            for element in queue:
                self.show(element, level)  # recursive call

    def expand_tree(self, position, mode=_DEPTH):
        # Python generator. Loosly based on an algorithm from 'Essential LISP' by
        # John R. Anderson, Albert T. Corbett, and Brian J. Reiser, page 239-241
        yield position
        queue = self[position].fpointer
        while queue:
            yield queue[0]
            expansion = self[queue[0]].fpointer
            if mode is _DEPTH:
                queue = expansion + queue[1:]  # depth-first
            elif mode is _WIDTH:
                queue = queue[1:] + expansion  # width-first

    def is_branch(self, position):
        return self[position].fpointer

    def __update_fpointer(self, position, identifier, mode):
        if position is None:
            return
        else:
            self[position].update_fpointer(identifier, mode)

    def __update_bpointer(self, position, identifier):
        self[position].bpointer = identifier

    def __getitem__(self, key):
        return self.nodes[self.get_index(key)]

    def __setitem__(self, key, item):
        self.nodes[self.get_index(key)] = item

    def __len__(self):
        return len(self.nodes)

    def __contains__(self, identifier):
        return [node.identifier for node in self.nodes
                if node.identifier is identifier]

if __name__ == "__main__":

    tree = Tree()
    tree.create_node("Harry", "harry")  # root node
    tree.create_node("Jane", "jane", parent = "harry")
    tree.create_node("Bill", "bill", parent = "harry")
    tree.create_node("Joe", "joe", parent = "jane")
    tree.create_node("Diane", "diane", parent = "jane")
    tree.create_node("George", "george", parent = "diane")
    tree.create_node("Mary", "mary", parent = "diane")
    tree.create_node("Jill", "jill", parent = "george")
    tree.create_node("Carol", "carol", parent = "jill")
    tree.create_node("Grace", "grace", parent = "bill")
    tree.create_node("Mark", "mark", parent = "jane")

    print("="*80)
    tree.show("harry")
    print("="*80)
    for node in tree.expand_tree("harry", mode=_WIDTH):
        print(node)
    print("="*80)
Brett Kromkamp
la source
4

Si quelqu'un a besoin d'un moyen plus simple de le faire, un arbre n'est qu'une liste imbriquée récursivement (puisque l'ensemble n'est pas hachable):

[root, [child_1, [[child_11, []], [child_12, []]], [child_2, []]]]

Où chaque branche est une paire: [ object, [children] ]
et chaque feuille est une paire:[ object, [] ]

Mais si vous avez besoin d'une classe avec des méthodes, vous pouvez utiliser n'importe quel arbre.

Hugo Trentesaux
la source
1

De quelles opérations avez-vous besoin? Il existe souvent une bonne solution en Python en utilisant un dict ou une liste avec le module bissect.

Il existe de nombreuses implémentations d'arborescence sur PyPI , et de nombreux types d'arborescence sont presque triviaux à implémenter vous-même en Python pur. Cependant, cela est rarement nécessaire.

Mike Graham
la source
0

Une autre implémentation d'arbre basée sur la réponse de Bruno :

class Node:
    def __init__(self):
        self.name: str = ''
        self.children: List[Node] = []
        self.parent: Node = self

    def __getitem__(self, i: int) -> 'Node':
        return self.children[i]

    def add_child(self):
        child = Node()
        self.children.append(child)
        child.parent = self
        return child

    def __str__(self) -> str:
        def _get_character(x, left, right) -> str:
            if x < left:
                return '/'
            elif x >= right:
                return '\\'
            else:
                return '|'

        if len(self.children):
            children_lines: Sequence[List[str]] = list(map(lambda child: str(child).split('\n'), self.children))
            widths: Sequence[int] = list(map(lambda child_lines: len(child_lines[0]), children_lines))
            max_height: int = max(map(len, children_lines))
            total_width: int = sum(widths) + len(widths) - 1
            left: int = (total_width - len(self.name) + 1) // 2
            right: int = left + len(self.name)

            return '\n'.join((
                self.name.center(total_width),
                ' '.join(map(lambda width, position: _get_character(position - width // 2, left, right).center(width),
                             widths, accumulate(widths, add))),
                *map(
                    lambda row: ' '.join(map(
                        lambda child_lines: child_lines[row] if row < len(child_lines) else ' ' * len(child_lines[0]),
                        children_lines)),
                    range(max_height))))
        else:
            return self.name

Et un exemple d'utilisation:

tree = Node()
tree.name = 'Root node'
tree.add_child()
tree[0].name = 'Child node 0'
tree.add_child()
tree[1].name = 'Child node 1'
tree.add_child()
tree[2].name = 'Child node 2'
tree[1].add_child()
tree[1][0].name = 'Grandchild 1.0'
tree[2].add_child()
tree[2][0].name = 'Grandchild 2.0'
tree[2].add_child()
tree[2][1].name = 'Grandchild 2.1'
print(tree)

Qui devrait produire:

                        Noeud principal                        
     / / \              
Nœud enfant 0 Nœud enfant 1 Nœud enfant 2        
                   | / \       
             Petit-enfant 1.0 Petit-enfant 2.0 Petit-enfant 2.1
Solomon Ucko
la source
0

Je suggère la bibliothèque networkx .

NetworkX est un package Python pour la création, la manipulation et l'étude de la structure, de la dynamique et des fonctions de réseaux complexes.

Un exemple de construction d'un arbre:

import networkx as nx
G = nx.Graph()
G.add_edge('A', 'B')
G.add_edge('B', 'C')
G.add_edge('B', 'D')
G.add_edge('A', 'E')
G.add_edge('E', 'F')

Je ne sais pas ce que vous entendez par " arbre général ",
mais la bibliothèque permet à chaque nœud d'être n'importe quel objet lavable , et il n'y a pas de contrainte sur le nombre d'enfants de chaque nœud.

La bibliothèque fournit également des algorithmes graphiques liés aux arborescences et aux capacités de visualisation .

Gal Avineri
la source
-2

Si vous souhaitez créer une structure de données arborescente, vous devez d'abord créer l'objet treeElement. Si vous créez l'objet treeElement, vous pouvez alors décider du comportement de votre arbre.

Pour ce faire, voici la classe TreeElement:

class TreeElement (object):

def __init__(self):
    self.elementName = None
    self.element = []
    self.previous = None
    self.elementScore = None
    self.elementParent = None
    self.elementPath = []
    self.treeLevel = 0

def goto(self, data):
    for child in range(0, len(self.element)):
        if (self.element[child].elementName == data):
            return self.element[child]

def add(self):

    single_element = TreeElement()
    single_element.elementName = self.elementName
    single_element.previous = self.elementParent
    single_element.elementScore = self.elementScore
    single_element.elementPath = self.elementPath
    single_element.treeLevel = self.treeLevel

    self.element.append(single_element)

    return single_element

Maintenant, nous devons utiliser cet élément pour créer l'arbre, j'utilise un arbre A * dans cet exemple.

class AStarAgent(Agent):
# Initialization Function: Called one time when the game starts
def registerInitialState(self, state):
    return;

# GetAction Function: Called with every frame
def getAction(self, state):

    # Sorting function for the queue
    def sortByHeuristic(each_element):

        if each_element.elementScore:
            individual_score = each_element.elementScore[0][0] + each_element.treeLevel
        else:
            individual_score = admissibleHeuristic(each_element)

        return individual_score

    # check the game is over or not
    if state.isWin():
        print('Job is done')
        return Directions.STOP
    elif state.isLose():
        print('you lost')
        return Directions.STOP

    # Create empty list for the next states
    astar_queue = []
    astar_leaf_queue = []
    astar_tree_level = 0
    parent_tree_level = 0

    # Create Tree from the give node element
    astar_tree = TreeElement()
    astar_tree.elementName = state
    astar_tree.treeLevel = astar_tree_level
    astar_tree = astar_tree.add()

    # Add first element into the queue
    astar_queue.append(astar_tree)

    # Traverse all the elements of the queue
    while astar_queue:

        # Sort the element from the queue
        if len(astar_queue) > 1:
            astar_queue.sort(key=lambda x: sortByHeuristic(x))

        # Get the first node from the queue
        astar_child_object = astar_queue.pop(0)
        astar_child_state = astar_child_object.elementName

        # get all legal actions for the current node
        current_actions = astar_child_state.getLegalPacmanActions()

        if current_actions:

            # get all the successor state for these actions
            for action in current_actions:

                # Get the successor of the current node
                next_state = astar_child_state.generatePacmanSuccessor(action)

                if next_state:

                    # evaluate the successor states using scoreEvaluation heuristic
                    element_scored = [(admissibleHeuristic(next_state), action)]

                    # Increase the level for the child
                    parent_tree_level = astar_tree.goto(astar_child_state)
                    if parent_tree_level:
                        astar_tree_level = parent_tree_level.treeLevel + 1
                    else:
                        astar_tree_level += 1

                    # create tree for the finding the data
                    astar_tree.elementName = next_state
                    astar_tree.elementParent = astar_child_state
                    astar_tree.elementScore = element_scored
                    astar_tree.elementPath.append(astar_child_state)
                    astar_tree.treeLevel = astar_tree_level
                    astar_object = astar_tree.add()

                    # If the state exists then add that to the queue
                    astar_queue.append(astar_object)

                else:
                    # Update the value leaf into the queue
                    astar_leaf_state = astar_tree.goto(astar_child_state)
                    astar_leaf_queue.append(astar_leaf_state)

Vous pouvez ajouter / supprimer des éléments de l'objet, mais rendre la structure intacte.

MAULIK MODI
la source
-4
def iterative_bfs(graph, start):
    '''iterative breadth first search from start'''
    bfs_tree = {start: {"parents":[], "children":[], "level":0}}
    q = [start]
    while q:
        current = q.pop(0)
        for v in graph[current]:
            if not v in bfs_tree:
                bfs_tree[v]={"parents":[current], "children":[], "level": bfs_tree[current]["level"] + 1}
                bfs_tree[current]["children"].append(v)
                q.append(v)
            else:
                if bfs_tree[v]["level"] > bfs_tree[current]["level"]:
                    bfs_tree[current]["children"].append(v)
                    bfs_tree[v]["parents"].append(current)
Gagan Nirmal
la source
Cela ne semble pas du tout répondre à la question d'une manière lisible.
AlBlue