![]() |
Baum-Interator implementieren
Hallo,
ich habe ein Baumstruktur und möchte für diese Struktur einen Iterator entwickeln. Prinzipiell ist mir klar wie ein Iterator funktioniert. Es soll ein externen Iterator werden, also der Klient steuert den Ablauf. Was mir noch nicht so richtig klar ist, ist die Implementation des Methode "Next", also der Aufruf des nächsten Elements. Ich stelle mir das folgendermaßen vor: - ich übergebe das root-Element - der erste Aufruf von Next gibt des erste Kind zurück - der nächste Aufruf gib das erste Kind des Kindes zurück, sofern vorhanden => somit wird in die Tiefe gegangen - hat das aktuelle Kind keine Kinder so wird der nächste Nachbar/Bruder zurückgegeben Soweit ist mir das erstmal klar. Ich bin mir aber noch nicht sicher wie ich folgende Situation abbilde: Der Iterator steht aktuell auf einem Kind, welches das Letzte des Eltern-Elements ist. Jetzt wird "Next" aufgerufen. Da das aktuelle Kind keine eigenen Kinder hat und selbst das Letzt des Elternelements ist so muß "Next" den Bruder des Eltern-Elements zurückgeben. Genau hier liegt mein Problem. Welche Möglichkeiten gibt es den Bruder des Eltern-Elements herauszubekommen. Mir fallen 2 Möglichkeiten ein, die mir beide nicht 100%ig gefallen. 1. Ich gehe zum Eltern-Element und frage dessen Eltern-Element nach der Liste seine Kinder. In dieser List suche ich mein Eltern-Element (von dem ich den Bruder haben möchte) und nehme den Nachfolger. - Hat den Nachteil, daß hier ganz schön viel traversiert werden muß. 2. Beim einfügen des Elements in den Baum speichert dieses Element einen Pointer auf den Nachfoger. - Diese Lösung hat aber den Nachteil, daß einiges mehr an Verwaltungsaufwand entsteht. Zudem kann ich dann das Element auch nicht in 2 unterschiedlichen Bäumen verwenden. Ich hoffe ich habe mich nicht zu kompliziert ausgedrückt und ihr habt ne tolle Idee für mich :zwinker: Schon mal Vielen Dank - Daniel |
Re: Baum-Interator implementieren
Wenn du einen Baum hast, nutzt du doch hoffentlich verlinkte Listen für die Elemente? Dann wäre der Bruder ganz einfach rauszubekommen: Parent.Next ;) Dabei speichert Parent in einem Element das Elternelement, Child das Kindelement, Next das nächste und Previous das vorherige Element^^
|
Re: Baum-Interator implementieren
Zitat:
|
Re: Baum-Interator implementieren
Hallo Daniel,
Du könntest in einem vorbereitenden Schritt mit einer rekursiven Routine den Baum durchlaufen und dabei Verweise auf alle besuchten Knoten in einem (dynamischen) Array ablegen. Die Next-Routine muß dann dieses Array nur noch sequentiell abarbeiten. Gruß Hawkeye |
Re: Baum-Interator implementieren
Zitat:
Wie würde das dann laufen. Wo werden die Links gespeichert? Ich möchte die Links ungern in den Elementen speichern da ich diese dann nicht in mehreren Bäumen gleichzeitg verwenden kann. Wenn sich das ohne viel Verwaltungsaufwand lösen läßt ist das sicher eine gute Idee. Zitat:
Zitat:
Aber mir ist da auch noch was eingefallen. Was haltet ihr davon, wenn man innerhalb des Iterators einen Stack verwaltet. Jedes mal wenn ich eine Ebene in die Tiefe gehe wird ein neues Element auf den Stack gelegt, welches Informationen enthält, welchen Index das Element hat (von dem ich komme). Wenn ich dann wieder eine Ebene aufsteige bekomme ich so einfach den Index des Nachfolgers heraus und lösche das oberste Stack-Element. |
Re: Baum-Interator implementieren
Hallo Daniel,
Zitat:
Nachtrag: Bei weiterem Nachdenken komme ich zu dem Schluss, dass ich viel zu viele Annahmen mache, wo von deiner Seite fast keine Information über die Implementierung der Baumstruktur vorliegt. Ob du den Stack einsetzt oder besser mit Markierungen arbeitest, das hängt zum Teil auch von der Implementierung der Knoten ab. Grüße vom marabu |
Re: Baum-Interator implementieren
Zitat:
Könntest du mal kurz Umreißen wie du das Problem mit Markierungen angehen würdest? Danke! |
Re: Baum-Interator implementieren
Hallo Daniel,
eine Markierung der Knoten hätte meiner Meinung nach den Nachteil, daß bei Änderungen im Baum alle Knoten zurückgesetzt werden müssen. Da Du offenbar mit einer großen Zahl von Knoten arbeitest, ist dies eine sehr teure Operation. Ist der zusätzliche Aufwand zur Erstellung einer linearen Liste von Knoten wirklich so groß, wenn Du sowieso alle Knoten im Baum besuchen möchtest? Bei riesigen Bäumen fällt da eher der zusätzlich benötgte Speicherplatz ins Gewicht. Das ist dann der Preis, den Du für eine simple Next-Funktion bezahlst. Dein Vorschlag mit dem Stack läßt sich sicher umsetzen, ohne die Knoten mit zusätzlichen Daten zu belasten. Der folgende Code ist ein Versuch(!), der von folgenden Voraussetzungen ausgeht: 1. Jeder Knoten besitzt eine Methode FirstChild, die einen Zeiger auf das erste Kind des Knotens liefert. 2. jeder Knoten besitzt eine Methode NextSibling, die einen Zeiger auf den rechten Bruder des Knotens liefert. 3. Es existiert ein Stack mit den Methoden Push, Pop und IsEmpty.
Delphi-Quellcode:
Ich hoffe, es sind nicht allzu viele Fehler drin.
type
TIterator = class private // Zeiger auf den nächsten zu liefernden Knoten FNext : TNode; // Zeiger auf die Wurzel des Baums FRoot : TNode; public // Konstruktor constructor Create (aRoot: TNode); // liefert den nächsten Knoten function Next: TNode; // Setzt den Iterator zurück procedure Reset; end; // TIterator consturctor TIterator.Create (aRoot: TNode); begin FRoot := aRoot; Reset; end; function TIterator.Next: TNode; begin // Zeiger auf den nächsten abzuarbeitenden Knoten des Baums liefern Result := FNext; // Nächsten abzuarbeitenden Knoten ermitteln, falls noch Knoten vorhanden sind if Assigned(FNext) then // Prüfe, ob der aktuelle Knoten Kinder besitzt if Assigned(FNext.FirstChild) then begin // Der aktuelle Knoten besitzt Kinder. // Aktuellen Knoten im Stack speichern, Zeiger auf das erste Kind holen Stack.Push (FNext); FNext := FNext.FirstChild; end else repeat begin // Falls der aktuelle Knoten einen Bruder besitzt, ist dies der nächste Knoten FNext := FNext.NextSibling; if Assigned(FNext) then Break; // Der Teilbaum wurde komplett abgearbeitet, zurück zur vorigen Ebene if Stack.IsEmpty then FNext := NIL else FNext := Stack.Pop; end; // while Assigned() until (FNext = NIL); end; procedure TIterator.Reset; begin FNext := FRoot; end; Gruß Hawkeye |
Re: Baum-Interator implementieren
Muss es unbedingt n Iterator sein? Reichts vielleicht auch, einfach nur ne rekursive Funktion zu benutzen:
Delphi-Quellcode:
Wenn du unbedingt n Iterator haben willst, kannst du das so auch machen:
//Pseudocode:
TNode = class private ... FChildren: TNodeList; // Typed TObjectList public ... property Chrildren: TNodeList read ... write ...; end; TBaum = class private ... FRoot: TNode; public ... procedure HandleAllNodes(AProc: <CallBackFunction>); ... property Root read FRoot write FRoot; end; procedure TBaum.HandleAllNodes(...); begin // rekursiv alle Nodes durchgehen und die CallBackFunction aufrufen end;
Delphi-Quellcode:
Is vielleicht nicht die Beste Lösung, aber ne einfache... Oder hab ich was vergessen/falsch verstanden?
TIterator = class
private ... FCurrentNode: Integer; // Nummer des Knotens, der zuletzt ermittelt wurde FCounter: Integer; // Counter für Next; public ... procedure Reset; function Next: TNode; end; function TIterator.Next: TNode; begin // solange FCounter <= TCurrentNode // rekursiv durchsuchen // wenn FCounter = TCurrentNode // Suche abbrechen und Node zurückliefern end; mfg Christian |
Re: Baum-Interator implementieren
Hallo Daniel,
Zitat:
Grüße vom marabu |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:16 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz