![]() |
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 |
Re: Baum-Interator implementieren
Zitat:
Daher habe ich mir überlegt, daß auf dem Stack nicht der Knoten selbst abgelegt wird sondern dessen Index. So kann ich, wenn ich den nächsten Nachbarn benötige, einfach den Index + 1 Nachbarn verwenden. (und ggf. Maßnahmen ergreifen falls es den nicht gibt) Da muß ich dann aber wiederrum höllisch aufpassen, daß nicht während des Vorgangs eine Knoten eingefügt wird, der meinen Index durcheinander bringt. Vielleicht sollte ich doch den Knoten in den Stack schreiben und der Knoten gibt dann seinen aktuellen Index zurück. Wenn der Knoten aber in mehreren Bäumen verwendet wird weiß der Knoten auch wieder nicht welchen Index er zurückgeben soll. Da müßte ich noch einen Bezug zum Kontext herstellen können - man ist das kompliziert :zwinker: Irgendwo habe ich mal gelesen, daß man dafür sogenannte "robuste Iteratoren" implementieren kann. Der registriert sich beim Baum und bekommt dann Infos wenn ein Knoten eingefügt bzw. gelöscht wird. So kann dann entsprechend auf den verschobenen Index reagiert werden. Ansonsten entspricht dein Versuch auch etwa meinen Vorstellungen. |
Re: Baum-Interator implementieren
Zitat:
Zitat:
Wenn ich jetzt also ein Element gefunden habe, welches meinen Kriterien entspricht und ich dann aber weitersuchen möchte ob es noch mehr davon gibt dann beginnt ja eine neue Rekursion. So kann ich weiter nach unten in den Baum suchen aber beim aufsteigen komme ich dann genau zu meinem Problem. Wo weitermachen wenn das Parent-Element nicht seine Nachbarn kennt? |
Re: Baum-Interator implementieren
Zitat:
Der Teufel liegt eigentlich immer im Detail. |
Re: Baum-Interator implementieren
Möchtest Du wirklich die Knoten in mehreren Bäumen benutzen oder nur die Daten? Bei einer sauberen Trennung zwischen der Verwaltung (Knoten) und den Daten (mit einem Verweis auf die Daten in den Knoten) sollte es doch möglich sein, die Daten mehrfach zu nutzen. Bei der Verwendung von Interfaces bekommst Du die Referenzzählung sogar umsonst. :wink: Von der mehrfachen Verwendung der Knoten würde ich abraten, weil es meiner Meinung nach die Datenstruktur allzu sehr einschränkt.
Gruß Hawkeye |
Re: Baum-Interator implementieren
Zitat:
Ich habe mir die Klassen für die Knoten erstellt und davon meine Daten-Klassen abgeleitet. Vielleicht ist es wirklich flexibler wenn ich diese beiden Dinge voneinander trenne. |
Re: Baum-Interator implementieren
Zitat:
Zitat:
mfg Christian |
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:17 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-2025 by Thomas Breitkreuz