Post by Niels MenkeHi NG,
Verzeiht mir falls das ne häufig gestellte Frage ist, aber per google
war nichts zu finden...
Das ist schwer zu glauben :-)
Post by Niels MenkeIch soll eine doppelt verkettete Liste programmieren, mit Templates und
den Methoden push, pop, top (lesen des obersten Elements), empty
(liefert true falls liste leer) und dump_elements (alle elemente ausgeben).
Mein Problem: Ich blick nicht so recht, wie ich das machen soll, da
Vorlesung und Skript doch sehr dürftig ausfielen. Hat vielleicht jemand
ein gutes Programmierbeispiel für mein Problem, über dem ich zwecks
Verständnis meditieren könnte?
Der heisseste Tip den ich Dir geben kann, ist: schnap Dir Zettel
und Bleistift und spiel mal ein bischen mit doppelt verketteten Listen
rum. Du kriegst so ein Gefuehl dafuer wie die einzelnen Operationen
laufen muessen und in welcher Reihenfolge welcher Pointer umzusetzen
ist.
Bsp. einen Knoten am Ende einer Liste anhaengen.
Dies sei die Liste (Jeder Knoten besteht aus einem
Wert und 2 Pointern. Der erste Pointer moege next
heisen, der zweite prev)
Root
+------+
| o |
+---|--+
|
v
+-------+ +------+ +-------+
| 3 | | 4 | | 5 |
| o---------->| o--------->| NULL |
| NULL |<----------o |<----------o |
+-------+ +------+ +-------+
und jetzt hast Du da einen neuen Knoten, der hinten ran muss:
Root
+------+
| o |
+---|--+
|
v
+-------+ +------+ +-------+
| 3 | | 4 | | 5 |
| o---------->| o--------->| NULL |
| NULL |<----------o |<----------o |
+-------+ +------+ +-------+
NewNode
+------+
| o------------+
+------+ |
v
+------+
| 6 |
| NULL |
| NULL |
+------+
Nur, wie macht man das? Zunaechst mal, wird es wahrscheinlich
das Bestreben sein, einen Pointer auf das letzte Listenelement
zu kriegen. Das erscheint logisch, den dort muss ja die Liste
manipuliert werden :-) Also ist es Dein erstes Ziel in diesen
Zustand zu kommen:
Root
+------+
| o |
+---|--+
|
v
+-------+ +------+ +-------+
| 3 | | 4 | | 5 |
| o---------->| o--------->| NULL |
| NULL |<----------o |<----------o |
+-------+ +------+ +-------+
^
|
Temp |
+--------+ |
| o------------------------------+
+--------+
NewNode
+------+
| o------------+
+------+ |
v
+------+
| 6 |
| NULL |
| NULL |
+------+
Temp zeigt also aufs letzte Element. Hmm. Wie kommt er dort hin?
Nun Temp uebernimmt zunaechst mal den Wert von Root und 'hangelt'
sich am next Pointer nach rechts, bis der letzte Knoten erreicht
ist. Hmm. Woran erkennt man den letzten Knoten? Schau auf die Zeichnung
und vergleiche den Knoten mit den anderen in der Liste! Richtig:
sein next Pointer ist NULL.
In Code gegossen sieht das ganze dann so aus:
Temp = Root;
while( Temp->next != 0 )
Temp = Temp->next;
Da muss dann noch eine Behandlung des Falles Root == 0 rein, aber
im wesentlichen wars das.
OK. Nun ist der Temp Pointer am letzten Knoten, wie wird der neue
Knoten dort eingehaengt? Indem ein paar Pointer verbogen werden.
Das Endziel sieht so aus:
Root
+------+
| o |
+---|--+
|
v
+-------+ +------+ +-------+
| 3 | | 4 | | 5 |
| o---------->| o--------->| o----------+
| NULL |<----------o |<----------o |<--+ |
+-------+ +------+ +-------+ | |
^ | |
| | |
Temp | | |
+--------+ | | |
| o------------------------------+ | |
+--------+ | |
| |
NewNode | |
+------+ | |
| o------------+ | |
+------+ | | |
v | |
+------+ | |
| 6 | | |
+---->| NULL | | |
| +-----o | | |
| | +------+ | |
| | | |
| +-------------------------------+ |
| |
+-------------------------------------+
und jetzt heist es eine Reihenfolge von Zuweisungen zu finden, die
genau dieses Ergebnis erzeugt. Ausgangspunkt aller Manipulationen
sind immer die Pointer Temp und NewNode. Immer wenn Du in der
Zeichnung einem Pfeil folgen musst, weil Du im dortigen Rechteck
ein Feld aufsuchen musst, schreibst Du ein ->
zB. Ich moechte den Pfeil realisieren, der vom Knoten '5' zum neuen
Knoten '6' fuehrt:
Root
+------+
| o |
+---|--+
|
v
+-------+ +------+ +-------+
| 3 | | 4 | | 5 |
| o---------->| o--------->| NULL |
| NULL |<----------o |<----------o |
+-------+ +------+ +-------+
^
|
Temp |
+--------+ |
| o------------------------------+
+--------+
NewNode
+------+
| o------------+
+------+ |
v
+------+
| 6 |
| NULL |
| NULL |
+------+
von Tmp ausgehend erreiche ich den Knoten '5', indem ich dem Pfeil
folge:
Tmp->
Im dortigen Rechteck brauche ich das next Feld
Tmp->next
Damit habe ich identifiziert wo der Pfeil starten soll. Wo soll
er hin zeigen: Nun, auf das gleiche Rechteck, auf das auch
NewNode zeigt. Also heist die ganze Anweisung:
Tmp->next = NewNode;
und das Ergebnis sieht so aus:
Root
+------+
| o |
+---|--+
|
v
+-------+ +------+ +-------+
| 3 | | 4 | | 5 |
| o---------->| o--------->| o----------+
| NULL |<----------o |<----------o | |
+-------+ +------+ +-------+ |
^ |
| |
Temp | |
+--------+ | |
| o------------------------------+ |
+--------+ |
|
NewNode |
+------+ |
| o------------+ |
+------+ | |
v |
+------+ |
| 6 | |
+---->| NULL | |
| | NULL | |
| +------+ |
| |
| |
| |
+-------------------------------------+
Vergleicht man mit dem angestrebten Ergebnis, so fehlt
nur noch der Reuckwaertspfeil von '6' nach '5'.
Wie kann ich das Feld an dem der Pfeil starten muss identifizieren?
Moegliche Ausgangspunkte sind die Pointer Temp oder NewNode.
Nun am einfachsten, kommt man an das Feld heran, wenn man
ueber NewNode geht: NewNode, immer dem Pfeil entlang und im
Rechteck das prev Feld:
NewNode->prev
Es geht aber auch anders. Ich kann bei Temp starten, dem Pfeil folgen,
im Rechteck das next Feld aufsuchen, nochmals einem Pfeil folgen, bis
ich schliesslich im gesuchten Rechteck lande, von wo ich das prev
Feld brauche. Oder in Code:
Temp->next->prev
Wofuer Du Dich entscheidest ist Deine Sache, auf jeden Fall muss der neue
Pfeil auf den Knoten '5' zeigen. Der ist einfach zu finden: Temp zeigt
schon drauf. Also in Code
NewNode->prev = Temp;
oder aber
Temp->next->prev = Temp;
Tja. das wars. Der neue Knoten ist eingehaengt.
Wie stehts mit Sonderfaellen. Was ist wenn die Liste
leer ist (Root == NULL)? Die Faelle musst Du Dir noch
ueberlegen und ev. Aenderungen am Bisherigen anbringen.
Aber: Unterschaetze nicht den Wert von Papier und Bleistift!
Niemand, und ich meine niemand, kann eine lineare Liste, ob
einfach oder doppelt verkettet, beim ersten Mal fehlerfrei
programmieren. P&B sind da eine exzellente Hilfe zum ausknobeln
und was noch viel wichtiger ist: bei der Fehlersuche. Bei der
Fehlersuche drehst Du den Spiess um: Du spielst Computer und
durchlaeufst Deine Funktion. Am Papier zeichnest Du alle
Aenderungen die Dir die Funktion vorschreibt mit. Normalerweise
sieht man auf diese Weise sehr schnell woran's denn scheitert.
Aber: Uebung macht den Meister. Ich wuerde mal schaetzen, das
ein Durchschnittsprogrammierer so 5 bis 7 Anlauefe braucht, bis
er eine lineare Liste fehlerfrei, einfach so und ohne
grosses Nachdenken, hinkriegt.
--
Karl Heinz Buchegger
***@gascad.at
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+***@bud.prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-***@bud.prima.de