Ein sortierter binärer Baum ist durch miteinander verknüpfte Datensätze (oft "Knoten" genannt) gekennzeichnet. Jeder dieser Knoten enthält im folgenden Beispiel eine Zahl sowie Referenzen auf bis zu zwei "Nachfolger". Hier soll der sogenannte "linke" eine Referenz auf einen Knoten sein, der eine kleinere Zahl beinhaltet, und der "rechte" eine größere Zahl (wir gehen hier der Einfachheit halber davon aus, daß keine Zahl mehrmals auftritt).
9 / \ 7 10 / \ 2 14 / \ 1 3
Ein solcher Baum läßt sich schrittweise von der "Wurzel" aus (hier: Nummer 9) aufbauen. Wie man sieht, befinden sich in den Teilbäumen, die an den Knoten jeweils links hängen, nur kleinere Zahlen als im betreffenden Knoten und im jeweils rechten Teilbaum nur größere. Diejenigen Knoten, die keine Nachfolger mehr besitzen (hier: 1, 3 und 14) werden "Blätter" genannt.
$ref_hash = { 'zahl' => $zahl, 'links' => $ref_links, 'rechts' => $ref_rechts }; |
Im fertigen Baum wird dann jeder einzelne Knoten durch eine
Referenz auf einen solchen Hash dargestellt, wobei $zahl
jeweils die (zu sortierende) Zahl enthält und $ref_links
sowie $ref_rechts
auf die beiden Nachfolger zeigen. Ist
nur ein oder gar kein Nachfolger (wie in einem Blatt) vorhanden,
so seien die entsprechenden Referenzen gleich "undef
".
Um einen solchen Knoten mit einer entsprechenden Zahl zum Leben zu erwecken, definieren wir folgendes Unterprogramm:
sub knoten { return ( { 'zahl' => $_[0], 'links' => undef, 'rechts' => undef } ); } |
D.h., der Aufruf knoten(9)
liefert eine Referenz
auf einen Hash, dessen Schlüssel zahl
den
Wert 9 hat und dessen Werte von links
und
rechts
nicht definiert sind.
Damit kann man schon die Wurzel des Baumes erzeugen:
#!/usr/local/bin/perl -w sub knoten { return ( { 'zahl' => $_[0], 'links' => undef, 'rechts' => undef } ); } $ref_wurzel = knoten(9); |
Um aus den restlichen Elementen einer zu sortierenden Liste den
Suchbaum aufzubauen, beginnt man jeweils bei der Wurzel und
vergleicht die neue Zahl mit der Zahl in der Wurzel. Ist das
neue Element kleiner, so geht man zum linken Nachfolger und
wiederholt den Vergleich, ansonsten geht man zum rechten
Nachfolger. Dieses Verfahren wird so lange wiederholt, bis
man auf eine undefinierte Referenz stößt. Dort
wird dann das neue Element als Blatt an den Baum gehängt,
indem in dem letzten Knoten die entsprechende Referenz links
oder rechts
mit Hilfe des knoten()
-Unterprogramms
definiert wird.
In Perl ließe sich dieser Algorithmus zum Beispiel wie folgt programmieren:
#!/usr/local/bin/perl -w @liste = ( 9, 10, 7, 14, 2, 3, 1 ); sub knoten { return ( { 'zahl' => $_[0], 'links' => undef, 'rechts' => undef } ); } sub erstelle_baum { $ref_liste = shift; ### Wurzelknoten erstellen $zahl = shift(@$ref_liste); $ref_wurzel = knoten($zahl); foreach $zahl (@$ref_liste) { ### beginne bei der Wurzel $ref = $ref_wurzel; ### (Endlosschleife) while(1) { ### Vergleich der Zahlen if($zahl < $$ref{'zahl'}) { if(defined($$ref{'links'})) { ### gehe nach links $ref = $$ref{'links'}; } else { ### neues Blatt $$ref{'links'} = knoten($zahl); last; ### verlasse while(1) { } } } else { if(defined($$ref{'rechts'})) { ### gehe nach rechts $ref = $$ref{'rechts'}; } else { ### neues Blatt $$ref{'rechts'} = knoten($zahl); last; ### verlasse while(1) { } } } } } return($ref_wurzel); } $ref_wurzel = erstelle_baum(\@liste); |
Durch den Rückgabewert der Subroutine (eine Referenz auf die Wurzel) kann später auf den Suchbaum zugegriffen werden.
Nun benötigen wir natürlich noch Programmcode, mit dessen
Hilfe die im Suchbaum sortierten Daten ausgegeben werden können.
Dabei geht man am besten nach folgender Methode vor: Beginnend bei
der Wurzel betrachte man einen (aktuellen) Knoten. Besitzt dieser
Knoten einen linken Teilbaum, mache den linken Nachfolger zum
aktuellen Knoten und wiederhole die Abfrage. Falls kein linker
Nachfolger vorhanden ist (links
ist undef
),
gebe die Zahl des aktuellen Knotens aus. Anschließend
teste, ob ein rechter Teilbaum vorhanden ist. Falls ja, wird der
rechte Nachfolger zum aktuellen Knoten, sonst geht man zum
letzten (darüberliegenden) Knoten zurück. Wie man
zeigen kann, wird mit Hilfe dieses Verfahrens der gesamte Suchbaum
durchlaufen und alle Elemente werden dabei (sortiert) ausgegeben.
Implementierung in Perl:
#!/usr/local/bin/perl -w @liste = ( 9, 10, 7, 14, 2, 3, 1 ); sub knoten { return ( { 'zahl' => $_[0], 'links' => undef, 'rechts' => undef } ); } ## 'sub erstelle_baum { ... }' wie im letzten Beispiel $ref_wurzel = erstelle_baum(\@liste); sub ausgabe { ### 'my' hier wichtig wegen Rekursion ! my $ref = shift; ### suche links (rekursiv) ausgabe($$ref{'links'}) if defined($$ref{'links'}); ### Ausgabe der Zahl print "$$ref{'zahl'}\n"; ### suche rechts (rekursiv) ausgabe($$ref{'rechts'}) if defined($$ref{'rechts'}); } ausgabe($ref_wurzel); |
1 2 3 7 9 10 14 |
Autor: Eike Grote | Letzte Änderung: 06.09.1998 |