Wenn Sie zum ersten Mal programmieren lernen, ist es üblich, Arrays als „Hauptdatenstruktur“ zu lernen.
Endlich werden Sie auch über hash tables lernen. Wenn Sie ein Informatikstudium anstreben, müssen Sie einen Kurs über Datenstrukturen belegen. Sie werden auch über linked listsqueues, und stacks lernen. Diese Datenstrukturen werden „lineare“ Datenstrukturen genannt, weil sie alle einen logischen Anfang und ein logisches Ende haben.
Wenn wir anfangen, etwas über trees und graphs zu lernen, kann es wirklich verwirrend werden. Wir speichern Daten nicht auf lineare Weise. Beide Datenstrukturen speichern Daten auf eine bestimmte Art und Weise.
Dieser Beitrag soll Ihnen helfen, die Baum-Datenstruktur besser zu verstehen und jede Verwirrung zu klären, die Sie darüber haben könnten.
In diesem Artikel werden wir lernen:
- Was ist ein Baum
- Beispiele für Bäume
- Seine Terminologie und wie er funktioniert
- Wie man Baumstrukturen in Code implementiert.
Lassen Sie uns diese Lernreise beginnen 🙂
Definition
Bei Programmieranfängern ist es üblich, die linearen Datenstrukturen besser zu verstehen als Datenstrukturen wie Bäume und Graphen.
Bäume sind als nicht-lineare Datenstruktur bekannt. Sie speichern Daten nicht auf lineare Weise. Sie organisieren Daten hierarchisch.
Lassen Sie uns in Beispiele aus dem wirklichen Leben eintauchen!
Was meine ich, wenn ich von hierarchisch spreche?
Stellen Sie sich einen Stammbaum mit Beziehungen aus allen Generationen vor: Großeltern, Eltern, Kinder, Geschwister, usw. Wir organisieren Stammbäume üblicherweise hierarchisch.
Die obige Zeichnung ist mein Stammbaum. Tossico, Akikazu, Hitomi, und Takemi sind meine Großeltern.
Toshiaki und Juliana sind meine Eltern.
TK, Yuji, Bruno und Kaio sind die Kinder meiner Eltern (ich und meine Brüder).
Die Struktur einer Organisation ist ein weiteres Beispiel für eine Hierarchie.
In HTML funktioniert das Document Object Model (DOM) als Baum.
Das HTML-Tag enthält weitere Tags. Wir haben ein head Tag und ein body Tag. Diese Tags enthalten bestimmte Elemente. Das head-Tag hat die Tags meta und title. Das body-Tag hat Elemente, die in der Benutzeroberfläche angezeigt werden, z. B. h1ali, usw.
Eine technische Definition
Ein tree ist eine Sammlung von Entitäten namens nodes. Knoten sind durch edges verbunden. Jedes node enthält ein value oder data, und es kann ein child node haben oder nicht.
Das first node des tree wird als root bezeichnet. Wenn dieses root node durch ein weiteres node verbunden ist, das root ist dann ein parent node und das verbundene node ist ein child.
Alle Tree nodes sind durch Links namens edges verbunden. Es ist ein wichtiger Teil von trees, denn es verwaltet die Beziehung zwischen nodes.
Leaves sind die letzten nodes auf einem tree. Sie sind Knoten ohne Kinder. Wie bei echten Bäumen haben wir das root, das branches und schließlich das leaves.
Weitere wichtige Konzepte, die Sie verstehen sollten, sind height und depth.
Das height eines tree ist die Länge des längsten Pfades zu einem leaf.
Das depth eines node ist die Länge des Pfades zu seinem root.
Zusammenfassung der Terminologie
- Wurzel ist das oberste
nodedestree - Kante ist die Verbindung zwischen zwei
nodes - Kind ist ein
node, das einparent nodehat - Elternteil ist ein
node, das einedgezu einemchild nodehat - Blatt ist ein
node, das keinchild nodeimtreehat - Höhe ist die Länge des längsten Pfades zu einem
leaf - Tiefe ist die Länge des Pfades zu seinem
root
Binärbäume
Nun besprechen wir einen speziellen Typ von tree. Wir nennen ihnbinary tree.
„In der Informatik ist ein Binärbaum eine Baumdatenstruktur, in der jeder Knoten höchstens zwei Kinder hat, die als linkes Kind und rechtes Kind bezeichnet werden.“ – Wikipedia
Sehen wir uns also ein Beispiel für einen binary tree an.
Lassen Sie uns einen Binärbaum codieren
Das erste, was wir bei der Implementierung eines binary tree beachten müssen, ist, dass es eine Sammlung von nodes ist. Jedes node hat drei Attribute: valueleft_child, und right_child.
Wie implementieren wir ein einfaches binary tree, das mit diesen drei Eigenschaften initialisiert wird?
Lassen Sie uns einen Blick darauf werfen.
class BinaryTree: def __init__(self, value): self.value = value self.left_child = None self.right_child = None
Hier ist es. Unsere binary tree Klasse.
Wenn wir ein Objekt instanzieren, übergeben wir das value (die Daten des Knotens) als Parameter. Sehen Sie sich das left_child und das right_child an. Beide sind auf None eingestellt.
Warum?
Weil wir unser node erstellen, hat es keine Kinder. Wir haben nur das node data.
Lassen Sie uns das testen:
tree = BinaryTree('a')print(tree.value) # aprint(tree.left_child) # Noneprint(tree.right_child) # None
Das ist es.
Wir können das stringa‚ als value an unser Binary Tree node übergeben. Wenn wir das value, das left_child und das right_child ausgeben, können wir die Werte sehen.
Lassen Sie uns zum Einfügeteil gehen. Was müssen wir hier tun?
Wir werden eine Methode implementieren, um ein neues node in das right und in das left einzufügen.
Hier sind die Regeln:
- Wenn das aktuelle
nodekeinleft childhat, erstellen wir einfach ein neuesnodeund setzen es auf dasleft_childdes aktuellen Knotens. - Wenn es das
left childhat, erstellen wir einen neuen Knoten und setzen ihn an die Stelle des aktuellenleft child. Weisen Sie diesesleft child nodedemleft childdes neuen Knotens zu.
Lassen Sie es uns auszeichnen. 🙂
Hier ist der Code:
Wenn der aktuelle Knoten kein left child hat, erstellen wir einfach einen neuen Knoten und setzen ihn auf das left_child des aktuellen Knotens. Oder wir erstellen einen neuen Knoten und setzen ihn an die Stelle des aktuellen left child. Dieses left child node weisen wir dem left child des neuen Knotens zu.
Und dasselbe machen wir, um ein right child node einzufügen.
Erledigt. 🙂
Aber nicht ganz. Wir müssen es noch testen.
Lassen Sie uns folgendestree aufbauen:
Zusammenfassend die Darstellung dieses Baumes:
-
anodewird dasrootunseresbinary Treesein -
aleft childistbnode -
aright childistcnode -
bright childistdnodebnodehat keinleft child) -
cleft childistenode -
cright childistfnode - beide
eundfnodeshaben keine Kinder
So ist hier der Code für das tree:
Das Einfügen ist erledigt.
Nun müssen wir uns Gedanken über das tree Traversal machen.
Wir haben hier zwei Möglichkeiten: Depth-First Search (DFS) und Breadth-First Search (BFS).
- DFS „ist ein Algorithmus zum Traversieren oder Durchsuchen einer Baumdatenstruktur. Man beginnt an der Wurzel und sucht so weit wie möglich entlang jedes Zweiges, bevor man zurückgeht.“ – Wikipedia
- BFS „ist ein Algorithmus zum Traversieren oder Suchen von Baumdatenstrukturen. Er beginnt an der Baumwurzel und erkundet zunächst die Nachbarknoten, bevor er sich zu den Nachbarn der nächsten Ebene bewegt.“ – Wikipedia
Lassen Sie uns also in die einzelnen Baum-Traversal-Typen eintauchen.
Depth-First Search (DFS)
DFS erkundet einen Pfad bis zu einem Blatt, bevor es zurückgeht und einen anderen Pfad erkundet. Schauen wir uns ein Beispiel mit dieser Art von Traversal an.
Das Ergebnis für diesen Algorithmus wird 1-2-3-4-5-6-7 sein.
Warum?
Lassen Sie es uns aufschlüsseln.
- Beginnen Sie bei der
root(1). Drucken Sie es.
2. Gehen Sie zum left child (2). Drucken Sie es.
3. Gehen Sie dann zum left child (3). Drucken Sie es aus. (Dieses node hat keine Kinder)
4. Gehen Sie zurück und gehen Sie zum right child (4). Drucken Sie es aus. (Dieses node hat keine Kinder)
5. Gehen Sie zurück zum rootnode und gehen Sie zum right child (5). Drucken Sie es.
6. Gehen Sie zum left child (6). Drucken Sie es aus. (Dieses node hat keine Kinder)
7. Gehen Sie zurück und gehen Sie zu dem right child (7). Drucken Sie es aus. (Dieses node hat keine Kinder)
8. Erledigt.
Wenn wir tief in das Blatt gehen und zurückverfolgen, nennt man das DFS-Algorithmus.
Nun, da wir mit diesem Traversal-Algorithmus vertraut sind, werden wir die Arten von DFS besprechen: pre-orderin-order und post-order.
Vorbestellung
Das ist genau das, was wir im obigen Beispiel gemacht haben.
- Drucken Sie den Wert des
node. - Gehen Sie zum
left childund drucken Sie es. Dies ist, wenn, und nur wenn, es einleft childhat. - Gehen Sie zum
right childund drucken Sie es. Dies ist, wenn, und nur wenn, es einright childhat.
In-Ordnung
Das Ergebnis des In-Ordnung-Algorithmus für dieses tree Beispiel ist 3-2-4-1-6-5-7.
Die linke zuerst, die mittlere als zweite und die rechte als letzte.
Nun wollen wir es codieren.
def in_order(self): if self.left_child: self.left_child.in_order() print(self.value) if self.right_child: self.right_child.in_order()
- Gehen Sie zum
left childund drucken Sie es. Das ist, wenn, und nur wenn, es einleft childhat. - Drucken Sie den Wert des
nodeaus - Gehen Sie zum
right childund drucken Sie es. Dies ist, wenn, und nur wenn, es einright childhat.
Nachordnung
Das Ergebnis des post order Algorithmus für dieses tree Beispiel ist 3-4-2-6-7-5-1.
Das linke zuerst, das rechte als zweites und das mittlere als letztes.
Lassen Sie uns das codieren.
- Gehen Sie zu dem
left childund drucken Sie es. Dies ist, wenn, und nur wenn, es einleft childhat. - Gehen Sie zum
right childund drucken Sie es. Dies ist, wenn, und nur wenn, es einright childhat. - Drucke den Wert des
nodeaus
Breadth-First Search (BFS)
Der BFS-Algorithmus durchläuft das tree Ebene für Ebene und Tiefe für Tiefe.
Hier ist ein Beispiel, das hilft, diesen Algorithmus besser zu erklären:
So durchlaufen wir Ebene für Ebene. In diesem Beispiel ist das Ergebnis 1-2-5-3-4-6-7.
- Ebene/Tiefe 0: nur
nodemit Wert 1 - Ebene/Tiefe 1:
nodesmit den Werten 2 und 5 - Level/Tiefe 2:
nodesmit den Werten 3, 4, 6 und 7
Nun geht es ans Programmieren.
Um einen BFS-Algorithmus zu implementieren, nehmen wir die queue Datenstruktur zu Hilfe.
Wie funktioniert das?
Hier ist die Erklärung.
- Zuerst fügen Sie die
rootnodein dasqueuemit der Methodeputein. - Iterieren Sie, solange das
queuenicht leer ist. - Ermitteln Sie das erste
nodeimqueue, und geben Sie dann seinen Wert aus. - Fügen Sie sowohl das
leftals auch dasrightchildrenin dasqueue(wenn das aktuellenodedaschildrenhat). - Erledigt. Wir werden den Wert jedes
node,stufenweise ausgeben, mit unseremqueueHelfer.
Binärer Suchbaum
„Ein binärer Suchbaum wird manchmal auch als geordneter oder sortierter binärer Baum bezeichnet, und er hält seine Werte in sortierter Reihenfolge, so dass Nachschlagen und andere Operationen das Prinzip der binären Suche nutzen können“ – Wikipedia
Eine wichtige Eigenschaft eines Binary Search Tree ist, dass der Wert eines Binary Search Treenode größer ist als der Wert der Nachkommenschaft seines left child, aber kleiner als der Wert der Nachkommen seines right child.„
Hier ist eine Aufschlüsselung der obigen Abbildung:
- A ist invertiert. Das
subtree7-5-8-6 muss auf der rechten Seite sein, und dassubtree2-1-3 muss auf der linken Seite sein. - B ist die einzig richtige Option. Sie erfüllt die
Binary Search TreeEigenschaft. - C hat ein Problem: das
nodemit dem Wert 4. Es muss auf der linken Seite desrootstehen, weil es kleiner als 5 ist.
Lassen Sie uns einen binären Suchbaum programmieren!
Nun ist es Zeit zu programmieren!
Was werden wir hier sehen? Wir werden neue Knoten einfügen, nach einem Wert suchen, Knoten löschen und den Rest des tree.
Lassen Sie uns beginnen.
Einfügen: Hinzufügen neuer Knoten zu unserem Baum
Stellen Sie sich vor, dass wir ein leeres tree haben und wir neue nodes mit den folgenden Werten in dieser Reihenfolge hinzufügen wollen: 50, 76, 21, 4, 32, 100, 64, 52.
Das erste, was wir wissen müssen, ist, ob 50 das root in unserem Baum ist.
Wir können nun beginnen, node um node einzufügen.
- 76 ist größer als 50, also wird 76 auf der rechten Seite eingefügt.
- 21 ist kleiner als 50, also wird 21 auf der linken Seite eingefügt.
- 4 ist kleiner als 50.
Nodemit dem Wert 50 hat einleft child21. Da 4 kleiner als 21 ist, fügen Sie es auf der linken Seite diesesnodeein. - 32 ist kleiner als 50.
Nodemit dem Wert 50 hat einleft child21. Da 32 größer als 21 ist, fügen Sie 32 auf der rechten Seite diesesnodeein. - 100 ist größer als 50.
Nodemit dem Wert 50 hat eineright child76. Da 100 größer als 76 ist, fügen Sie 100 auf der rechten Seite diesesnodeein. - 64 ist größer als 50.
Nodemit dem Wert 50 hat einenright child76. Da 64 kleiner als 76 ist, fügen Sie 64 auf der linken Seite diesesnodeein. - 52 ist größer als 50.
Nodemit dem Wert 50 hat einenright child76. Da 52 kleiner als 76 ist, hatnodemit dem Wert 76 einleft child64. 52 ist kleiner als 64, also fügen Sie 54 auf der linken Seite diesesnodeein.
Erkennen Sie hier ein Muster?
Lassen Sie es uns aufschlüsseln.
- Ist der neue
node-Wert größer oder kleiner als der aktuellenode? - Wenn der Wert des neuen
nodegrößer als der des aktuellennode,ist, gehe nach rechtssubtree. Wenn das aktuellenodekeinright childhat, fügen Sie es dort ein, sonst gehen Sie zurück zu Schritt 1. - Wenn der Wert des neuen
nodekleiner ist als der des aktuellennode, gehen Sie zum linkensubtree. Wenn das aktuellenodekeinleft childhat, fügen Sie es dort ein, ansonsten gehen Sie zurück zu Schritt 1. - Spezialfälle haben wir hier nicht behandelt. Wenn der Wert eines neuen
nodegleich dem aktuellen Wert desnode,ist, verwenden Sie Regel Nummer 3. Überlegen Sie, ob Sie gleiche Werte auf der linken Seite dessubtreeeinfügen wollen.
Nun lassen Sie uns das Ganze codieren.
Es scheint sehr einfach zu sein.
Der mächtige Teil dieses Algorithmus ist der Rekursionsteil, der sich in Zeile 9 und Zeile 13 befindet. Beide Codezeilen rufen die Methode insert_node auf und verwenden sie für das left bzw. rightchildren. Die Zeilen 11 und 15 sind diejenigen, die das Einfügen für jedes child durchführen.
Lassen Sie uns nach dem Knotenwert suchen… Oder auch nicht…
Der Algorithmus, den wir jetzt bauen werden, dreht sich um die Suche. Für einen gegebenen Wert (Integer-Zahl) werden wir sagen, ob unser Binary Search Tree diesen Wert hat oder nicht.
Ein wichtiger Punkt ist, wie wir den Algorithmus zum Einfügen des Baums definiert haben. Zuerst haben wir unser rootnode. Alle linken subtreenodes werden kleinere Werte haben als das rootnode. Und alle rechten subtreenodes werden größere Werte als die rootnode haben.
Schauen wir uns ein Beispiel an.
Stellen Sie sich vor, wir haben dieses tree.
Nun wollen wir wissen, ob wir einen Knoten haben, der auf dem Wert 52 basiert.
Lassen Sie uns das aufschlüsseln.
- Wir beginnen mit dem
rootnodeals unserem aktuellennode. Ist der angegebene Wert kleiner als der aktuellenode-Wert? Wenn ja, dann suchen wir ihn auf dem linkensubtree. - Ist der angegebene Wert größer als der aktuelle
node-Wert? Wenn ja, dann suchen wir ihn auf dem rechtensubtree. - Wenn die Regeln #1 und #2 beide falsch sind, können wir den aktuellen
node-Wert und den gegebenen Wert vergleichen, wenn sie gleich sind. Wenn der Vergleichtrueergibt, dann können wir sagen: „Ja! Unsertreehat den gegebenen Wert“, andernfalls sagen wir: „Nein, hat es nicht.“
Nun lassen Sie uns das programmieren.
Schreiben wir den Code auf:
- Die Zeilen 8 und 9 fallen unter Regel #1.
- Die Zeilen 10 und 11 fallen unter Regel #2.
- Die Zeile 13 fällt unter Regel #3.
Wie testen wir das?
Lassen Sie uns unser Binary Search Tree erstellen, indem wir das rootnode mit dem Wert 15 initialisieren.
bst = BinarySearchTree(15)
Und nun werden wir viele neue nodes einfügen.
Für jedes eingefügte node werden wir testen, ob unsere find_node-Methode wirklich funktioniert.
Ja, sie funktioniert für diese gegebenen Werte! Testen wir auf einen Wert, der in unserem Binary Search Tree nicht existiert.
print(bst.find_node(0)) # False
Oh ja.
Unsere Suche ist beendet.
Löschen: Entfernen und Organisieren
Löschen ist ein komplexerer Algorithmus, weil wir verschiedene Fälle behandeln müssen. Für einen bestimmten Wert müssen wir das node mit diesem Wert entfernen. Stellen Sie sich die folgenden Szenarien für dieses node vor: es hat kein children, hat ein einzelnes child oder hat zwei children.
- Szenario 1: Ein
nodemit keinemchildrenleafnode).
# |50| |50|# / \ / \# |30| |70| (DELETE 20) ---> |30| |70|# / \ \# |20| |40| |40|
Wenn das node, das wir löschen wollen, keine Kinder hat, löschen wir es einfach. Der Algorithmus muss das tree nicht umorganisieren.
- Szenario #2: Ein
nodemit nur einem Kind (leftoderrightKind).
# |50| |50|# / \ / \# |30| |70| (DELETE 30) ---> |20| |70|# / # |20|
In diesem Fall muss unser Algorithmus dafür sorgen, dass das Elternteil des node auf den Knoten child zeigt. Wenn das node das left child ist, lassen wir das Elternteil des left child auf das child zeigen. Wenn das node das right child seines Elternteils ist, lassen wir das Elternteil des right child auf das child zeigen.
- Szenario #3: Ein
nodemit zwei Kindern.
# |50| |50|# / \ / \# |30| |70| (DELETE 30) ---> |40| |70|# / \ /# |20| |40| |20|
Wenn das node 2 Kinder hat, müssen wir das node mit dem kleinsten Wert finden, ausgehend vom node des right child. Wir werden dieses node mit dem Minimalwert an die Stelle des node setzen, das wir entfernen wollen.
Es ist Zeit für den Code.
- Zuerst: Beachten Sie die Parameter
valueundparent. Wir wollen dasnodefinden, das diesesvaluehat, und das Elternteil desnodeist wichtig für das Entfernen desnode. - Zweitens: Beachten Sie den Rückgabewert. Unser Algorithmus gibt einen booleschen Wert zurück. Er gibt
Truezurück, wenn er dasnodefindet und es entfernt. Andernfalls gibt esFalsezurück. - Von Zeile 2 bis Zeile 9: Wir beginnen mit der Suche nach dem
node, das dasvalueenthält, das wir suchen. Wenn dasvaluekleiner als dascurrent nodevalueist, gehen wir zu demleft subtree, rekursiv (wenn, und nur wenn, dascurrent nodeeinleft childhat). Wenn dasvaluegrößer ist, gehen Sie zumright subtree, rekursiv. - Zeile 10: Wir beginnen, über den
remove-Algorithmus nachzudenken. - Von Zeile 11 bis Zeile 13: Wir decken das
nodeohnechildrenab, und es ist dasleft childvon seinemparent. Wir entfernen dasnode, indem wir dasparentdesleft childaufNonesetzen. - Zeilen 14 und 15: Wir decken das
nodeohnechildrenab, und es ist dasright childvon seinemparent. Wir entfernen dasnode, indem wir dasparentdesright childaufNonesetzen. - Methode Knoten löschen: Im Folgenden zeige ich den
clear_node-Code. Er setzt den Knotenleft child , right child, und seinvalueaufNone. - Von Zeile 16 bis Zeile 18: Wir überdecken das
nodemit nur einemchildleft child), und zwar mit demleft childvon dessenparent. Wir setzen dasparentdesleft childauf dasnodedesleft child(das einzige Kind, das es hat). - Von Zeile 19 bis Zeile 21: Wir überdecken das
nodemit nur einemchildleft child), und zwar mit demright childaus seinemparent. Wir setzen dasparentdesright childauf dasnodedesleft child(das einzige Kind, das es hat). - Von Zeile 22 bis Zeile 24: Wir überdecken das
nodemit nur einemchildright child), und zwar mit demleft childaus seinemparent. Wir setzen dasparentdesleft childauf dasnodedesright child(das einzige Kind, das es hat). - Von Zeile 25 bis Zeile 27: Wir überdecken das
nodemit nur einemchildright child), und zwar mit demright childaus seinemparent. Wir setzen dasparentdesright childauf dasnodedesright child(das einzige Kind, das es hat). - Von Zeile 28 bis Zeile 30: Wir überdecken das
nodemit den beidenleftundrightKindern. Wir holen dasnodemit dem kleinstenvalue(der Code wird unten gezeigt) und setzen es auf dasvaluedescurrent node. Anschließend entfernen wir das kleinstenode. - Zeile 32: Wenn wir das gesuchte
nodefinden, muss esTruezurückgeben. Von Zeile 11 bis Zeile 31 behandeln wir diesen Fall. Also einfachTruezurückgeben und das war’s.
- Um die Methode
clear_nodezu verwenden: Setzen Sie denNoneWert auf alle drei Attribute – (valueleft_child, undright_child)
def clear_node(self): self.value = None self.left_child = None self.right_child = None
- Um die Methode
find_minimum_valuezu verwenden: Gehen Sie ganz nach unten links. Wenn wir keine weiteren Knoten finden, haben wir den kleinsten gefunden.
def find_minimum_value(self): if self.left_child: return self.left_child.find_minimum_value() else: return self.value
Nun wollen wir es testen.
Wir werden dieses tree benutzen, um unseren remove_node Algorithmus zu testen.
# |15|# / \# |10| |20|# / \ / \# |8| |12| |17| |25|# \# |19|
Lassen Sie uns das node mit der value 8 entfernen. Es ist ein node ohne Kind.
print(bst.remove_node(8, None)) # Truebst.pre_order_traversal()# |15|# / \# |10| |20|# \ / \# |12| |17| |25|# \# |19|
Entfernen wir nun das node mit dem value 17. Das ist ein node mit nur einem Kind.
print(bst.remove_node(17, None)) # Truebst.pre_order_traversal()# |15|# / \# |10| |20|# \ / \# |12| |19| |25|
Zuletzt entfernen wir ein node mit zwei Kindern. Dies ist das root unseres tree.
print(bst.remove_node(15, None)) # Truebst.pre_order_traversal()# |19|# / \# |10| |20|# \ \# |12| |25|
Die Tests sind nun abgeschlossen. 🙂
Das war’s erstmal!
Wir haben hier eine Menge gelernt.
Glückwunsch zur Fertigstellung dieses dichten Inhalts. Es ist wirklich schwer, ein Konzept zu verstehen, das wir nicht kennen. Aber Sie haben es geschafft 🙂
Dies ist ein weiterer Schritt vorwärts auf meiner Reise zum Lernen und Beherrschen von Algorithmen und Datenstrukturen. Sie können die Dokumentation meiner kompletten Reise hier auf meiner Renaissance Developer-Publikation sehen.
Viel Spaß, weiter lernen und programmieren.
Mein Twitter & Github. ☺
Zusätzliche Ressourcen
- Einführung in die Baumdatenstruktur von mycodeschool
- Baum von Wikipedia
- How To Not Be Stumped By Trees von dem talentierten Vaidehi Joshi
- Einführung in Bäume, Vorlesung von Professor Jonathan Cohen
- Einführung in Bäume, Vorlesung von Professor David Schmidt
- Intro to Trees, Vorlesung von Professor Victor Adamchik
- Trees with Gayle Laakmann McDowell
- Binary Tree Implementation and Tests by TK
- Coursera Course: Data Structures von der University of California, San Diego
- Coursera-Kurs: Data Structures and Performance von der University of California, San Diego
- Binary Search Tree Konzepte und Implementierung von Paul Programming
- Binary Search Tree Implementierung und Tests von TK
- Tree Traversal von Wikipedia
- Binary Search Tree Remove Node Algorithm von GeeksforGeeks
- Binary Search Tree Remove Node Algorithm von Algolist
- Learning Python From Zero to Hero