Wie kann ich einen Baum in Python implementieren?

Antworten:

230

anytree

Ich empfehle https://pypi.python.org/pypi/anytree (ich bin der Autor)

Beispiel

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

Eigenschaften

anytree hat auch eine leistungsstarke API mit:

  • einfache Baumerstellung
  • einfache Baumänderung
  • Baumiteration vorbestellen
  • Baum-Iteration nach der Bestellung
  • relative und absolute Knotenpfade auflösen
  • Gehen von einem Knoten zum anderen.
  • Baum-Rendering (siehe Beispiel oben)
  • Anschließen / Trennen von Knotenverbindungen
c0fec0de
quelle
31
Einfach die beste Antwort, andere erfinden das Rad neu.
Ondrej
66
Es ist eine gute Form, anzugeben, dass Sie der Autor des Pakets sind, das Sie in Ihrer Antwort empfehlen.
John Y
3
@ c0fec0de Ich liebe dich !!!! Diese Bibliothek ist erstaunlich, hat sogar eine Visualisierungsfunktion
Layser
2
@Ondrej Nun, die anderen Antworten sind weniger abhängig und die ursprüngliche Frage stellte sich nach eingebauten Datenstrukturen. Während anytreees sich wahrscheinlich um eine großartige Bibliothek handelt, handelt es sich um eine Python-Frage, nicht um eine Node.js-Frage.
Rob Rose
Ich bin über Google auf diese Antwort gestoßen. Diese Bibliothek ist wirklich schön. Ich mag besonders die Möglichkeit, mit der Mixin-Klasse aus jedem Objekt einen Baum zu machen!
R Nck Nöthing 8.
104

Python verfügt nicht über die umfangreiche Auswahl an "integrierten" Datenstrukturen wie Java. Da Python jedoch dynamisch ist, ist es einfach, einen allgemeinen Baum zu erstellen. Ein Binärbaum könnte beispielsweise sein:

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

Sie können es so verwenden:

root = Tree()
root.data = "root"
root.left = Tree()
root.left.data = "left"
root.right = Tree()
root.right.data = "right"
Greg Hewgill
quelle
109
Dies erklärt nicht wirklich viel über das Erstellen einer nützlichen Baumimplementierung.
Mike Graham
14
Die Frage ist mit Python3 markiert, es besteht dann keine Notwendigkeit, class Treevom Objekt abzuleiten
cfi
3
@cfi Das Ableiten von objectist manchmal nur eine Richtlinie: Wenn eine Klasse von keiner anderen Basisklasse erbt, erbt sie explizit vom Objekt. Dies gilt auch für verschachtelte Klassen. Siehe Google Python Style Guide
Konrad Reiche
16
@platzhirsch: Bitte lesen und zitieren Sie die Richtlinie vollständig: Google weist ausdrücklich darauf hin, dass dies erforderlich ist, damit Python 2-Code wie erwartet funktioniert, und empfohlen, um die Kompatibilität mit Py3 zu verbessern. Hier geht es um Py3-Code. Es ist nicht erforderlich, zusätzliche, ältere Eingaben vorzunehmen.
cfi
13
Das ist ein binärer Baum, kein allgemeiner, wie gewünscht.
Michael Dorner
49

Ein generischer Baum ist ein Knoten mit null oder mehr untergeordneten Knoten, von denen jeder ein richtiger (Baum-) Knoten ist. Es ist nicht dasselbe wie ein Binärbaum, es handelt sich um unterschiedliche Datenstrukturen, obwohl beide eine bestimmte Terminologie haben.

In Python gibt es keine integrierte Datenstruktur für generische Bäume, diese lässt sich jedoch problemlos mit Klassen implementieren.

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
quelle
Erstaunlich, dies kann auch leicht als Grafik verwendet werden! Das einzige Problem, das ich gesehen habe, ist: Wie kann ich den linken Knoten vom rechten Knoten unterscheiden?
Angelo Polotto
3
Nach Kinderindex. Links sind in diesem Fall immer Kinder [0].
Freund Allein
38

Du kannst es versuchen:

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

Wie hier vorgeschlagen: https://gist.github.com/2012250

Ib33X
quelle
Wenn Sie auf eine beliebige Anzahl von Ebenen erweitern möchten, überprüfen Sie: stackoverflow.com/a/43237270/511809
natbusa
Dies beschattet den eingebauten Funktions-Hash.
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
quelle
3
Können Sie nur einige Anmerkungen hinzufügen, um Ihren Code und Ihre Implementierung vorzustellen?
Michele d'Amico
Vielen Dank für die vollständige Implementierung von Binary Tree mit Dienstprogrammfunktionen. Da es sich um Python 2 handelt, habe ich eine Übersicht über die Implementierung von Binary Tree (Py3) für Benutzer erstellt , die eine Python 3-Version benötigen.
CᴴᴀZ
16

Es sind keine Bäume eingebaut, aber Sie können einfach einen erstellen, indem Sie einen Knotentyp aus List unterordnen und die Traversal-Methoden schreiben. Wenn Sie dies tun, habe ich Bisekt nützlich gefunden.

Es gibt auch viele Implementierungen auf PyPi , die Sie durchsuchen können.

Wenn ich mich richtig erinnere, enthält die Python-Standardbibliothek keine Baumdatenstrukturen aus demselben Grund wie die .NET-Basisklassenbibliothek: Die Speicherlokalität wird reduziert, was zu mehr Cache-Fehlern führt. Auf modernen Prozessoren ist es normalerweise schneller, nur einen großen Teil des Speichers in den Cache zu bringen, und "zeigerreiche" Datenstrukturen negieren den Vorteil.

Justin R.
quelle
2
Zu Ihrer Information: Die Interwebs sind voller Hass gegen Boost. Anscheinend soll es ein RIESIGER Schmerz sein, damit umzugehen, zumal die Unterstützung dafür eingestellt wurde. Also würde ich empfehlen, sich davon fernzuhalten
inspectorG4dget
Vielen Dank. Ich hatte persönlich keine Probleme, aber ich möchte nicht irreführen, also habe ich diesen Verweis entfernt.
Justin R.
11

Ich habe einen verwurzelten Baum als Wörterbuch implementiert {child:parent}. So könnte beispielsweise mit dem Wurzelknoten 0ein Baum folgendermaßen aussehen:

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

Diese Struktur machte es ziemlich einfach, auf einem Pfad von einem beliebigen Knoten zur Wurzel nach oben zu gehen, was für das Problem, an dem ich arbeitete, relevant war.

Pfote
quelle
1
So dachte ich darüber nach, bis ich die Antwort sah. Obwohl ein Baum ein Elternteil mit zwei Kindern ist und Sie untergehen möchten, können Sie dies tun {parent:[leftchild,rightchild]}.
JFA
1
Eine andere Möglichkeit besteht darin, Listen von Listen zu verwenden, bei denen das erste (oder mehrere) Element in der Liste der Knotenwert ist und die folgenden zwei verschachtelten Listen die linken und rechten Teilbäume darstellen (oder mehr für n-ary Baum).
Pepr
9

Greg Hewgills Antwort ist großartig, aber wenn Sie mehr Knoten pro Ebene benötigen, können Sie sie mit einem Listenwörterbuch erstellen: Verwenden Sie dann die Methode, um entweder nach Name oder Reihenfolge (wie ID) auf sie zuzugreifen.

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

Erstellen Sie jetzt einfach eine Wurzel und bauen Sie sie auf: Beispiel:

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

Das sollte ausreichen, damit Sie herausfinden, wie dies funktioniert

Bruno
quelle
In dieser Antwort fehlt etwas. Ich habe diese Lösung in den letzten 2 Tagen ausprobiert und ich denke, Sie haben einen logischen Ablauf bei der Objektadditionsmethode. Ich werde meine Antwort auf diese Frage einreichen. Bitte überprüfen Sie dies und lassen Sie mich wissen, ob ich helfen kann.
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

Funktioniert als Wörterbuch, bietet jedoch so viele verschachtelte Wörter, wie Sie möchten. Versuche Folgendes:

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']            = '*'

wird ein verschachteltes Diktat liefern ... das in der Tat als Baum funktioniert.

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

... Wenn Sie bereits ein Diktat haben, wird jedes Level auf einen Baum gewirkt:

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

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

Auf diese Weise können Sie jede Diktatstufe nach Ihren Wünschen bearbeiten / hinzufügen / entfernen. Alle Diktiermethoden für das Durchqueren usw. gelten weiterhin.

Natbusa
quelle
2
Gibt es einen Grund , warum Sie wählen zu verlängern dictstatt defaultdict? Nach meinen Tests sollte das Erweitern defaultdictanstelle des Diktierens und das Hinzufügen self.default_factory = type(self)zum Anfang von init auf die gleiche Weise funktionieren.
Rob Rose
Mir fehlt hier wahrscheinlich etwas. Wie navigieren Sie in dieser Struktur? Es scheint sehr schwierig zu sein, von Kindern zu Eltern oder zu Geschwistern zu gelangen
Stormsson
6

Ich habe Bäume mit verschachtelten Diktaten implementiert. Das ist ganz einfach und hat bei mir mit ziemlich großen Datenmengen funktioniert. Ich habe unten ein Beispiel gepostet, und Sie können mehr unter Google-Code sehen

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

Ich habe eine Python [3] -Baumimplementierung auf meiner Website veröffentlicht: http://www.quesucede.com/page/show/id/python_3_tree_implementation .

Hoffe, es ist von Nutzen,

Ok, hier ist der 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
quelle
4

Wenn jemand einen einfacheren Weg benötigt, ist ein Baum nur eine rekursiv verschachtelte Liste (da set nicht hashbar ist):

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

Wobei jeder Zweig ein Paar ist: [Objekt, [Kinder]]
und jedes Blatt ein Paar ist: [Objekt, []]

Wenn Sie jedoch eine Klasse mit Methoden benötigen, können Sie anytree verwenden.

Hugo Trentesaux
quelle
1

Welche Operationen benötigen Sie? In Python gibt es oft eine gute Lösung, wenn Sie ein Diktat oder eine Liste mit dem Halbierungsmodul verwenden.

Es gibt viele, viele Baumimplementierungen auf PyPI , und viele Baumtypen sind fast trivial, um sich in reinem Python zu implementieren. Dies ist jedoch selten notwendig.

Mike Graham
quelle
0

Eine weitere Baumimplementierung basiert lose auf Brunos Antwort :

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

Und ein Beispiel für die Verwendung:

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)

Welches sollte ausgeben:

                        Wurzelknoten                        
     // \              
Untergeordneter Knoten 0 Untergeordneter Knoten 1 Untergeordneter Knoten 2        
                   | / \.       
             Enkel 1.0 Enkel 2.0 Enkel 2.1
Solomon Ucko
quelle
0

Ich schlage die networkx Bibliothek vor.

NetworkX ist ein Python-Paket zum Erstellen, Bearbeiten und Studieren der Struktur, Dynamik und Funktionen komplexer Netzwerke.

Ein Beispiel für das Bauen eines Baumes:

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

Ich bin nicht sicher, was Sie unter einem " allgemeinen Baum" verstehen ,
aber die Bibliothek ermöglicht es jedem Knoten, ein beliebiges hashbares Objekt zu sein , und es gibt keine Einschränkung hinsichtlich der Anzahl der untergeordneten Knoten, die jeder Knoten hat.

Die Bibliothek bietet auch Diagrammalgorithmen für Bäume und Visualisierungsfunktionen .

Gal Avineri
quelle
-2

Wenn Sie eine Baumdatenstruktur erstellen möchten, müssen Sie zuerst das treeElement-Objekt erstellen. Wenn Sie das treeElement-Objekt erstellen, können Sie entscheiden, wie sich Ihr Baum verhält.

Dazu folgt die TreeElement-Klasse:

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

Jetzt müssen wir dieses Element verwenden, um den Baum zu erstellen. In diesem Beispiel verwende ich den A * -Baum.

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)

Sie können beliebige Elemente zum Objekt hinzufügen / daraus entfernen, die Struktur jedoch intect.

MAULIK MODI
quelle
-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
quelle
Dies scheint die Frage überhaupt nicht lesbar zu beantworten.
AlBlue