Binärer Baum in C?
Geizhals » Forum » Programmierung » Binärer Baum in C? (18 Beiträge, 15 Mal gelesen) Top-100 | Fresh-100
Du bist nicht angemeldet. [ Login/Registrieren ]
.
Re: Binärer Baum in C?
Fly
23.04.2002, 02:28:46
Primär glaub ich mal, dass Du uns irgendwas vorenthältst, weil root ned definiert ist. :)

Im Endeffekt geht's darum, dass Du die Selbstähnlichkeit so eines Baumes ausnutzen kannst. Zeichne Dir so 'nen Baum mal auf. Ich mein's ernst, Papier, Bleistift, zeichnen! So 3-4 Ebenen dürften reichen.

So. Als nächstes, vergiss für 'nen Moment C. Nix mehr an programmieren denken, jetzt wird's künstlerisch! :)

Jetzt schau Dir mal die Wurzel an (den Knoten ohne Vorgänger), und seine Nachfolger. Sprich, den ganzen Baum. So. Jetzt schau Dir den linken Nachfolger an, und seine Nachfolger. Du wirst feststellen, er ist dem ganzen Baum sehr ähnlich, nur "kleiner".

Weiters ist es von Vorteil, wenn Du Dir die Knoten von "innen" betrachtest. Also wennst so tust, als ob Du "im" Knoten die Ausgabe machst. Versuch's Dir vorzustellen. Nicht an Code denken! Vorstellen! Schau auf den 1. Knoten. Was müssen wir tun?

Nun, im Endeffekt nur 3 Schritte:

1. Wenn es einen linken Nachfolger gibt, sag diesem, er soll sich ausgeben.
2. Gib mich aus.
3. Wenn's einen rechten Nachfolger gibt, sag diesem, er soll sich ausgeben.

Die komische Formulierung "sag diesem..." hat folgenden Sinn: Dieser Nachfolger, bekommt ebenfalls wieder diesen 3-Punkte-Plan. Das heisst, er schaut nach ob er einen linken nachfolger hat... dieser wieder ... dieser wieder... usw.

Da wir zu Schritt 2 im 1. Knoten erst kommen, wenn wir mit Schritt 3 im linken Nachfolger fertig sind, wird dieser vor dem 1. Knoten ausgegeben. Das heisst, wir machen bei Schritt 2 in jeder Rekursion erst weiter, wenn der Nachfolger komplett fertig ist, dieser Knoten wird erst ausgegeben, wenn wir aus dem Nachfolger "zurückkommen".

Der Code selbst ist recht einfach (umschreiben für Deine Zwecke darfst ihn allerdings doch selbst :)).

void printnode (node* current)
{
  if (current->left) printnode (current->left);
  OutputCurrentnode();
  if (current->right) printnode (current->right);
}

Was der Code macht sind im Wesentlichen die 3 Schritte, die ich oben besprochen hab.

Zuerst wird geprüft, ob's einen linken Nachfolger gibt (schau bitte auf Deiner Zeichnung von vorhin mit!). Falls ja, wird in diesen "gesprungen", und die Ausgaberoutine für diesen aufgerufen. Dieser macht das gleiche und prüft, ob er einen linken Nachfolger hat, dieser wieder, und wieder... Es ist WESENTLICH anzumerken, dass im Ur-Knoten, und in jedem seiner linken Nachfolger, die wir anspringen, inzwischen GAR NIX passiert, da wird derzeit nix ausgegeben und gar nix gemacht bis wir wieder "zurück" sind!

Wenn wir dann irgendwann einen Knoten finden, der keinen linken Nachfolger hat passiert in der 1. Zeile nix und wir kommen zur 2. IN DIESEM KNOTEN. Da wird dann der Inhalt ausgegeben. Dann kommen wir zur 3. Zeile, und wenn's einen rechten Nachfolger gibt, wird das Spiel mit diesem wiederholt. Gibt's keinen sind wir mit diesem Knoten fertig. Dann geht's zurück zum Vorgänger, dort kommen wir damit in die 2. Zeile (remember, wir haben vorher gesagt es passiert in diesem Knoten nix bis wir aus dem Nachfolger zurück sind, der "steht" immer noch, wie alle seine Vorgänger, auf der 1. Zeile und wartet darauf, dass die Nachfolger fertig werden).

Dort passiert nun das gleiche, Output, rechter Nachfolger, usw.

Das Spiel setzt sich nun durch den ganzen Baum durch fort, bis alle Knoten ausgegeben sind.


Shadows can be made real
if you kill in their name.
Antworten PM Übersicht Chronologisch Zum Vorgänger
 
Melden nicht möglich
...
Re(3): Binärer Baum in C?
Fly
23.04.2002, 10:55:28
Du greifst auf die Knoten gar nicht direkt zu. Du nutzt die Ähnlichkeit aus.

Der Trick dabei ist, dass Du die Funktion aus sich selbst heraus nochmal aufrufst, mit den Nachfolgern. So Marke "divide and conquer". Die Wurzel hat keinen Schimmer, wie weit sie nach unten gehen wird, sie gibt einfach die "Kontrolle" mal an den linken und mal an den rechten Nachfolger weiter (dazwischen wird ihr Inhalt ausgegeben). Diese Nachfolger machen nun genau das gleiche. Jeder Knoten "sieht" dabei nur sich selbst und (so vorhanden) seine Nachfolger.

Aufgerufen wird die Rekursion, indem Du als Parameter für den neuen Aufruf entweder den linken (also root->left) oder den rechten (root->right) übergibst. Dass der Parameter root heissen soll is' dabei vielleicht ein klein wenig verwirrend, weil es wird ein einziges Mal (nämlich beim Aktivieren von "aussen") mit dem Wurzelknoten aufgerufen. Alle anderen Aufrufe passieren von innerhalb der RDPrint Funktion! Der Wurzelknoten ruft's also mit seinem linken Nachfolger auf, der macht das gleiche, und der wieder, und der wieder... bis es keinen linken Nachfolger mehr gibt. Wieviele Aufrufe da passieren und wie lang's dauert, wieviele Nachfolger es da gibt und wo die hängen, das "weiss" der Wurzelknoten nicht. Er wartet einfach darauf, dass die Ausführung wieder zu ihm zurückkommt.

Nehmen wir an, wir haben folgenden Tree:

     4
  2     6
1  3  5 7

Wir rufen's mit der Wurzel (4) auf. Diese sieht, sie hat einen linken Nachfolger (2) und ruft die Funktion mit diesem auf. 2 merkt, er hat einen linken Nachfolger (1) und ruft die Funktion mit diesem auf. 1 hat keinen Linken nachfolger (1. Zeile fertig).

1 wird ausgegeben. (2. Zeile fertig)

1 merkt er hat keinen rechten Nachfolger (3. Zeile fertig). Damit ist die Funktion in 1 fertig und die Ausführung kehrt zurück zu 2. 2 ist jetzt mit der 1. Zeile des Codes fertig.

2 wird ausgegeben

2 merkt, es hat einen rechten Nachfolger (3) und führt die Funktion mit diesem als parameter aus. 3 geht's jetzt so wie 1 (d.h. kein linker Nachfolger, Ausgabe, kein rechter Nachfolger, Funktion fertig).

Danach geht die Ausführung zurück an 2. 2 ist mit der 3. Zeile jetzt auch fertig (das war die Übergabe an 3) und beendet seine Funktion. Damit geht die Ausführung zurück an 4. 4 ist jetzt mit seiner 1. Zeile fertig.

4 wird ausgegeben

Danach wiederholt sich das ganze Spiel mit dem rechten Ast des Baumes (ich erspar mir jetzt die Tipperei).

Warum Du's als ** definieren willst versteh' ich nun nicht ganz, 'n Zeiger würde reichen. Ich komm' auch noch nicht dahinter, wozu die verkette Liste da drin nutzen soll.


Shadows can be made real
if you kill in their name.
Antworten PM Übersicht Chronologisch Zum Vorgänger
 
Melden nicht möglich
 

Dieses Forum ist eine frei zugängliche Diskussionsplattform.
Der Betreiber übernimmt keine Verantwortung für den Inhalt der Beiträge und behält sich das Recht vor, Beiträge mit rechtswidrigem oder anstößigem Inhalt zu löschen.
Datenschutzerklärung