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 lists
queues
, 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. h1
a
li
, 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
node
destree
- Kante ist die Verbindung zwischen zwei
nodes
- Kind ist ein
node
, das einparent node
hat - Elternteil ist ein
node
, das einedge
zu einemchild node
hat - Blatt ist ein
node
, das keinchild node
imtree
hat - 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: value
left_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 string
a
‚ 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
node
keinleft child
hat, erstellen wir einfach ein neuesnode
und setzen es auf dasleft_child
des aktuellen Knotens. - Wenn es das
left child
hat, erstellen wir einen neuen Knoten und setzen ihn an die Stelle des aktuellenleft child
. Weisen Sie diesesleft child node
demleft child
des 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:
-
a
node
wird dasroot
unseresbinary Tree
sein -
a
left child
istb
node
-
a
right child
istc
node
-
b
right child
istd
node
b
node
hat keinleft child
) -
c
left child
iste
node
-
c
right child
istf
node
- beide
e
undf
nodes
haben 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 root
node
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-order
in-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 child
und drucken Sie es. Dies ist, wenn, und nur wenn, es einleft child
hat. - Gehen Sie zum
right child
und drucken Sie es. Dies ist, wenn, und nur wenn, es einright child
hat.
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 child
und drucken Sie es. Das ist, wenn, und nur wenn, es einleft child
hat. - Drucken Sie den Wert des
node
aus - Gehen Sie zum
right child
und drucken Sie es. Dies ist, wenn, und nur wenn, es einright child
hat.
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 child
und drucken Sie es. Dies ist, wenn, und nur wenn, es einleft child
hat. - Gehen Sie zum
right child
und drucken Sie es. Dies ist, wenn, und nur wenn, es einright child
hat. - Drucke den Wert des
node
aus
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
node
mit Wert 1 - Ebene/Tiefe 1:
nodes
mit den Werten 2 und 5 - Level/Tiefe 2:
nodes
mit 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
root
node
in dasqueue
mit der Methodeput
ein. - Iterieren Sie, solange das
queue
nicht leer ist. - Ermitteln Sie das erste
node
imqueue
, und geben Sie dann seinen Wert aus. - Fügen Sie sowohl das
left
als auch dasright
children
in dasqueue
(wenn das aktuellenode
daschildren
hat). - Erledigt. Wir werden den Wert jedes
node,
stufenweise ausgeben, mit unseremqueue
Helfer.
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 Tree
node
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
subtree
7-5-8-6 muss auf der rechten Seite sein, und dassubtree
2-1-3 muss auf der linken Seite sein. - B ist die einzig richtige Option. Sie erfüllt die
Binary Search Tree
Eigenschaft. - C hat ein Problem: das
node
mit dem Wert 4. Es muss auf der linken Seite desroot
stehen, 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.
Node
mit dem Wert 50 hat einleft child
21. Da 4 kleiner als 21 ist, fügen Sie es auf der linken Seite diesesnode
ein. - 32 ist kleiner als 50.
Node
mit dem Wert 50 hat einleft child
21. Da 32 größer als 21 ist, fügen Sie 32 auf der rechten Seite diesesnode
ein. - 100 ist größer als 50.
Node
mit dem Wert 50 hat eineright child
76. Da 100 größer als 76 ist, fügen Sie 100 auf der rechten Seite diesesnode
ein. - 64 ist größer als 50.
Node
mit dem Wert 50 hat einenright child
76. Da 64 kleiner als 76 ist, fügen Sie 64 auf der linken Seite diesesnode
ein. - 52 ist größer als 50.
Node
mit dem Wert 50 hat einenright child
76. Da 52 kleiner als 76 ist, hatnode
mit dem Wert 76 einleft child
64. 52 ist kleiner als 64, also fügen Sie 54 auf der linken Seite diesesnode
ein.
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
node
größer als der des aktuellennode,
ist, gehe nach rechtssubtree
. Wenn das aktuellenode
keinright child
hat, fügen Sie es dort ein, sonst gehen Sie zurück zu Schritt 1. - Wenn der Wert des neuen
node
kleiner ist als der des aktuellennode
, gehen Sie zum linkensubtree
. Wenn das aktuellenode
keinleft child
hat, 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
node
gleich dem aktuellen Wert desnode,
ist, verwenden Sie Regel Nummer 3. Überlegen Sie, ob Sie gleiche Werte auf der linken Seite dessubtree
einfü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. right
children
. 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 root
node
. Alle linken subtree
nodes
werden kleinere Werte haben als das root
node
. Und alle rechten subtree
nodes
werden größere Werte als die root
node
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
root
node
als 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 Vergleichtrue
ergibt, dann können wir sagen: „Ja! Unsertree
hat 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 root
node
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
node
mit keinemchildren
leaf
node
).
# |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
node
mit nur einem Kind (left
oderright
Kind).
# |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
node
mit 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
value
undparent
. Wir wollen dasnode
finden, das diesesvalue
hat, und das Elternteil desnode
ist wichtig für das Entfernen desnode
. - Zweitens: Beachten Sie den Rückgabewert. Unser Algorithmus gibt einen booleschen Wert zurück. Er gibt
True
zurück, wenn er dasnode
findet und es entfernt. Andernfalls gibt esFalse
zurück. - Von Zeile 2 bis Zeile 9: Wir beginnen mit der Suche nach dem
node
, das dasvalue
enthält, das wir suchen. Wenn dasvalue
kleiner als dascurrent nodevalue
ist, gehen wir zu demleft subtree
, rekursiv (wenn, und nur wenn, dascurrent node
einleft child
hat). Wenn dasvalue
größ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
node
ohnechildren
ab, und es ist dasleft child
von seinemparent
. Wir entfernen dasnode
, indem wir dasparent
desleft child
aufNone
setzen. - Zeilen 14 und 15: Wir decken das
node
ohnechildren
ab, und es ist dasright child
von seinemparent
. Wir entfernen dasnode
, indem wir dasparent
desright child
aufNone
setzen. - Methode Knoten löschen: Im Folgenden zeige ich den
clear_node
-Code. Er setzt den Knotenleft child , right child
, und seinvalue
aufNone
. - Von Zeile 16 bis Zeile 18: Wir überdecken das
node
mit nur einemchild
left child
), und zwar mit demleft child
von dessenparent
. Wir setzen dasparent
desleft child
auf dasnode
desleft child
(das einzige Kind, das es hat). - Von Zeile 19 bis Zeile 21: Wir überdecken das
node
mit nur einemchild
left child
), und zwar mit demright child
aus seinemparent
. Wir setzen dasparent
desright child
auf dasnode
desleft child
(das einzige Kind, das es hat). - Von Zeile 22 bis Zeile 24: Wir überdecken das
node
mit nur einemchild
right child
), und zwar mit demleft child
aus seinemparent
. Wir setzen dasparent
desleft child
auf dasnode
desright child
(das einzige Kind, das es hat). - Von Zeile 25 bis Zeile 27: Wir überdecken das
node
mit nur einemchild
right child
), und zwar mit demright child
aus seinemparent
. Wir setzen dasparent
desright child
auf dasnode
desright child
(das einzige Kind, das es hat). - Von Zeile 28 bis Zeile 30: Wir überdecken das
node
mit den beidenleft
undright
Kindern. Wir holen dasnode
mit dem kleinstenvalue
(der Code wird unten gezeigt) und setzen es auf dasvalue
descurrent node
. Anschließend entfernen wir das kleinstenode
. - Zeile 32: Wenn wir das gesuchte
node
finden, muss esTrue
zurückgeben. Von Zeile 11 bis Zeile 31 behandeln wir diesen Fall. Also einfachTrue
zurückgeben und das war’s.
- Um die Methode
clear_node
zu verwenden: Setzen Sie denNone
Wert auf alle drei Attribute – (value
left_child
, undright_child
)
def clear_node(self): self.value = None self.left_child = None self.right_child = None
- Um die Methode
find_minimum_value
zu 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