Zur Themenübersicht
Binäre Suchbäume
Programmtechnische Umsetzung (Borland Delphi®)
Download des Delphi-Projektes (12kb). Bitte
Readme.txt lesen!
Die Knoten des Baums
Die Knoten können auf verschiedene Art und Weise umgesetzt werden. Die hier vorgestellte Realisierung beruht auf einer Klasse, welche von TTreeNode
abgeleitet wurde und den Namen TSTreeNode trägt.
Klassendefinition |
TSTreeNode = Class(TTreeNode) Private Function MaxValue : TSTreeNode; Function ReadValue : TSortable;
Procedure DeleteRoot;
Public Function Delete(PSortable : TSortable) : Boolean; Function Search(PSortable : TSortable) : TSTreeNode;
Function IsBalanced : Boolean;
Procedure Insert(PSortable : TSortable);
Property Value : TSortable Read ReadValue; End;
|
Einfügen eines Knotens
Das Einfügen eines neuen Knotens geschieht mit der Funktion Insert
. Als Parameter muß ein sortierbares Element (Typ TSortable
) übergeben werden. Ein Knoten, der neu eingefügt wird, ist automatisch ein Blatt.
Wenn der Knoten, welcher den Insert -Befehl keinen Wert enthält (also leer ist), so wird ihm der Wert des Insert übergebenen Parameters zugewiesen. Danach werden zwei neue (leere) Knoten erzeugt, die der aktuelle Knoten als Outdegree erhält. Dieses dient nur der Vereinfachung der Programmierung; der Outdegree des aktuellen Knotens beträgt also immer noch 0 (Blatt), obwohl er auf zwei (leere) Knoten zeigt. |
If IsEmpty Then Begin IValue := PSortable;
LeftNode := TSTreeNode.Create; RightNode := TSTreeNode.Create; End
|
Falls der Inhalt des übergebenen Elements kleiner als der des aktuellen Knotens ist, so wird dem Knoten links vom Aktuellen der Insert -Befehl erteilt. |
Else If PSortable.LT(TSortable(Value)) Then Begin TSTreeNode(LeftNode).Insert(PSortable); End
|
Andernfalls (der Inhalt ist also größer als oder gleich dem Inhalt des aktuellen Knotens) wird dem Knoten rechts vom Aktuellen der Insert -Befehl erteilt. |
Else Begin TSTreeNode(RightNode).Insert(PSortable); End;
|
Dadurch, daß jeder Knoten in Wirklichkeit den Outdegree 2 besitzt indem er auf leere Knoten zeigt, ist der rekursive Aufruf der Prozedur Insert
möglich. Andernfalls müßte vor jedem rekursiven Aufruf überprüft werden, ob TSTreeNode(LeftNode)
oder TSTreeNode(RightNode)
auf Nil
zeigt und gegebenenfalls neue Knoten erstellt werden.
Löschen eines Knotens
Die Methode, mit welcher ein Knoten gelöscht wird, hängt von seinem Outdegree ab. Das Löschen eines Knotens mit dem Outdegree 0 ist einfach, auch das Löschen eines Knotens mit dem Outdegree 1 stellt kein großes Problem dar. Wenn jedoch ein Knoten mit dem Outdegree 2 gelöscht werden soll, so gibt es zwei verschiedene Ersatzknoten. Dabei ist es also erforderlich, sich für einen von zwei Ersatzknoten zu entscheiden. Substituent kann entweder der Knoten mit dem größten Wert des linken Teilbaums oder der Knoten mit dem kleinsten Wert des rechten Teilbaums sein.
Das Löschen eines Knotens geschieht mit der öffentlichen Methode Function Delete(PSortable : TSortable) : Boolean;
. Diese Methode überprüft, ob ein Knoten mit dem Wert PSortable
in dem Baum vorhanden ist, ruft gegebenenfalls die private Löschmethode DeleteRoot
dieses Knotens auf, und gibt zurück, ob der Knoten erfolgreich gelöscht werden konnte. Die Methode Procedure DeleteRoot;
ist in vier Teile aufgeteilt.
Der Knoten ist ein Blatt (Outdegree = 0)Sicherheitshalber wird abgefragt, ob sich links sowie rechts vom Knoten Teilbäume befinden, bevor sie aus dem Speicher entfernt werden. Danach wird dem Knoten als LeftNode , RightNode und als IValue , welches den Inhalt des Knotens bezeichnet, Nil zugewiesen. Das Objekt, das den Inhalt des Knotens darstellt, wird hierbei nicht gelöscht, verbleibt also im Speicher. |
If Self.IsLeaf Then Begin If LeftNode <> Nil Then LeftNode.Remove;
If RightNode <> Nil Then RightNode.Remove;
Self.SetNil; End
|
Der Knoten hat den Outdegree 1, der linke Teilbaum ist leerHierbei wird zuerst der linke (leere) Teilbaum aus dem Speicher gelöscht, danach erhält der Knoten den Wert des rechten Knotens. Außerdem erhält er LeftNode und RightNode des rechten Knotens, bevor dieser ebenfalls gelöscht wird. |
Else If LeftNode.IsEmpty Then Begin LeftNode.Remove;
TmpLeft := RightNode.LeftNode; TmpRight := RightNode.RightNode;
IValue := RightNode.Value;
LeftNode := TmpLeft; RightNode := TmpRight;
RightNode.Remove; End
|
Der Knoten hat den Outdegree 1, der rechte Teilbaum ist leerDiese Löschmethode unterscheidet sich prinzipiell nicht von der Vorherigen; es wird nur zuerst der rechte Teilbaum gelöscht, der Knoten erhält LeftNode und RightNode des linken Knotens und abschließend wird der linke Knoten gelöscht. |
Else If RightNode.IsEmpty Then Begin RightNode.Remove;
TmpLeft := LeftNode.LeftNode; TmpRight := LeftNode.RightNode;
IValue := LeftNode.Value;
LeftNode := TmpLeft; RightNode := TmpRight;
LeftNode.Remove; End
|
Der Knoten hat den Outdegree 2Falls der Knoten nicht in eine der obigen Bedingungen paßt, also den Outdegree 2 hat, so wird nach dem Ersatzknoten Substitute gesucht, welcher bei dieser Realisierung der Knoten mit dem größten Wert im linken Teilbaum ist. Nachdem dieser Knoten gefunden wurde, erhält der aktuelle Knoten den Wert des Ersatzknotens, abschließend ruft sich die Methode DeleteRoot rekursiv auf. Da der rechte Teilbaum des Ersatzknotens leer sein muß (sonst wäre er nicht der größte im Teilbaum), ist hierdurch die Anzahl der rekursiven Aufrufe dieser Prozedur auf 1 beschränkt. Der linke Teilbaum des Ersatzknotens muß freilich nicht zwingend leer sein. |
Else Begin Substitute := TSTreeNode(LeftNode).MaxValue;
IValue := Substitute.Value;
Substitute.DeleteRoot; End;
|
Suchen eines Knotens im Baum
Das Suchen eines Knotens im Baum geschieht mit der Funktion Function Search(PSortable : TSortable) : TSTreeNode;
. Falls ein Knoten mit dem Wert von PSortable
gefunden werden konnte, so wird er zurückgegeben, andernfalls Nil
.
Der aktuelle Knoten ist leerWenn der aktuelle Knoten leer ist, so konnte ein Knoten mit dem Inhalt von PSortable nicht gefunden werden; es wird also Nil als Ergebnis zurückgeliefert. Die Suche ist hiermit beendet. |
If IsEmpty Then Begin Result := Nil; End
|
Der aktuelle Knoten ist nicht leerIn diesem Fall findet eine Reihe von Überprüfungen statt. Wenn der Inhalt von PSortable gleich dem des aktuellen Knotens ist, so wird der aktuelle Knoten als Ergebnis zurückgeliefert. Die Suche ist auch hiermit beendent. Andernfalls wird überprüft, ob der Inhalt von PSortable kleiner als der des aktuellen Knoten ist. Da diese Überprüfungen ebenso wie beim Einfügen auf Textebene stattfinden, ist 100 zum Beispiel kleiner als 50. Wenn dies der Fall ist, findet ein rekursiver Aufruf der Funktion Search statt, das zurückgelieferte Ergebnis ist das Ergebnis von TSTreeNode(LeftNode).Search(PSortable) , also das Ergebnis des Suchvorgangs im linken Teilbaum. Ist der Inhalt größer als der des aktuellen Knotens, so ist das Ergebnis das Resultat des Suchvorgangs im rechten Teilbaum. |
Else Begin If PSortable.Equal(TSortable(Value)) Then Begin Result := Self; End Else Begin If PSortable.LT(TSortable(Value)) Then Begin Result := TSTreeNode(LeftNode).Search(PSortable); End Else Begin Result := TSTreeNode(RightNode).Search(PSortable); End; End; End;
|
Der eigentliche Baum
Nachdem die Knoten definiert wurden stellt man fest, daß der eigentliche Baum nur eine Klasse ist, die Knoten verwaltet und auf die Methoden ebendieser zurückgreift. Deshalb ist es nicht überraschend, daß die meisten Methoden in diesem Fall nur dem Zeichnen des Baums auf einer Zeichenfläche (Typ TCanvas
) dienen.
TSTreeNodes = Class(TObject) Private ICanvas : TCanvas; ICanvasWidth : Word; ICanvasHeight : Word;
IRoot : TSTreeNode; ICurrent : TSTreeNode;
Function ReadCanvas : TCanvas; Function ReadCanvasWidth : Word; Function ReadCanvasHeight : Word;
Procedure WriteCanvas(PCanvas : TCanvas); Procedure WriteCanvasWidth(PWidth : Word); Procedure WriteCanvasHeight(PHeight : Word);
Function ReadRoot : TSTreeNode; Function ReadCurrent : TSTreeNode; Public Constructor Create;
Function Delete(PSortable : TSortable) : Boolean; Function Search(PSortable : TSortable) : TSTreeNode;
Procedure Left; Procedure Right; Procedure Reset; Procedure Insert(PSortable : TSortable);
Procedure Draw(PNode : TSTreeNode; ShowBalance : Boolean = False; Redraw : Boolean = True; PDepth : Integer = 0; PXPos : Integer = -1; DifX : Integer = -1);
Procedure DestroyNodes;
Property Canvas : TCanvas Read ReadCanvas Write WriteCanvas; Property CanvasWidth : Word Read ReadCanvasWidth Write WriteCanvasWidth; Property CanvasHeight : Word Read ReadCanvasHeight Write WriteCanvasHeight;
Property Root : TSTreeNode Read ReadRoot; Property Current : TSTreeNode Read ReadCurrent; End;
|
Zur
Themenübersicht |
Zum Seitenanfang |
|
Zur vorigen Seite |
Zur nächsten Seite  |
© 2001 LK 12 If ,
Moritz Möhrke und G. Kubitz |
Hannah-Arendt-Gymnasium, Lengerich |