Sie sollen die Funktionalität einer doppelt verlinkten Liste in der Programmiersprache C implementieren. Dazu schreiben Sie ein Programm, dem man über die Kommandozeile Zahlen übergeben kann, aus der Sie im nächsten Schritt die Liste erzeugen. Ein beispielhafter Aufruf Ihres Programms könnte wie folgt aussehen:
./DLLTest 3 4 2 1
Für jede eingegebene Zahl erzeugen Sie einen Knoten, der Ihrer Liste hinzugefügt wird. Jeder Knoten node soll einen Zeiger prev auf den Vorgänger, einen Zeiger next auf den Nachfolger und einen Wert val besitzen. Implementieren Sie für das Hinzufügen eines Knotens zur Liste die Funktion addNode(…).
Sobald Sie die Liste vollständig erzeugt haben, geben Sie deren Inhalt auf der Konsole aus. Implementieren Sie dazu die Funktion printList(…).
Vergessen Sie nicht am Ende Ihres Programms jeglichen von Ihnen allokierten Speicher wieder freizugeben. Die Freigabe des Speichers der Liste soll in einer Funktion clearList(…) geschehen.
Nach dem Schließen des Programms wird nicht freigegebener Speicher vom System freigegeben. Doch wenn das Programm länger läuft, kann der Speicherverbrauch massiv ansteigen (= Memory Leak).
Zusätzlich zu CyborgBetas hilfreichem, laber-freiem on-topic-post* :
Im clearList kommt noch ein unbekanntes „anf“ vor - das kann so ja nicht compilieren, d.h. da wirst du wohl nochmal drüberschauen. Den Knackpunkt, dass man einen einzelnen Knoten nicht löschen darf, solange man nicht weiß, wo man danach hin geht, scheinst du ja schon erkannt zu haben:
free(current);
current = current->next; // KRACH!
Ansonsten wirst du früher oder später merken, dass bestimmte „Muster“ mehrfach auftreten. Man müßte jetzt genauer überlegen, was bei einem MergeSort alles an Operationen gemacht wird, aber einiges, was jetzt in „addNode“ steht, könnte ggf. ausgelagert werden. Man KÖNNTE (!) (nur um die Idee zu verdeutlichen!) Helferlein definieren wie etwa
void appendAsNext(node *n, node* next) {
...
}
(oder ähnlich), die die Teile zusammenfassen, die gemacht werden müssen, damit der Zustand „konsistent“ ist. Es geht darum, dass z.B. die Invariante n->next->prev == n (für n!=NULL und n->next!=NULL)
nach JEDEM Funktionsaufruf erfüllt sein muss. Solche Sachen in jeder Funktion aufs neue, lokal durch händisches Pointer-Jonglieren sicherzustellen kann fehleranfällig sein.
EDIT: Sollte die while(pointer->next != NULL)-Schleife in der „addNode“-Funktion durch das Speichern des jeweils aktuellen „end“-Nodes nicht vermieden werden können?
Solange das Programm es Performanz-Technisch verkraftet würde ich auf die „redundante“ Speicherung der Endknoten-Adresse (end) verzichten und dafür lieber das Suchen des letzten Knotens in eine eigene Funktion auslagern, die dann in den anderen Funktionen benutzt wird…
Redundante Speicherung birgt nämlich immer die Gefahr der Inkonsistenz.
[ot]
Der C-Code-Formatter ist gerade kaputt. Lieber code verwenden
[/ot]
Sicher könnte man die “addNode” etwas vereinfachen. Aber die Initialisierungen wie start->next = NULL; usw. darf man NICHT weglassen. malloc allokiert nur, aber in dem Speicher kann noch Müll stehen. (mit calloc wäre das anders)
start wird überhaupt nicht gelöscht, und sobald das Listenende erreicht ist, temp2 null ist, wird das temp-Element zu dieses Zeitpunkt, also das letzte Element, auch nicht gelöscht
fange mit temp = start an, befreie in jedem Fall temp in der Schleife,
vorher aber noch next holen, erst in temp2 ablegen, nach dem Befreien in temp schreiben,
kein break nötig, while-Bedingung zur nächsten Runde nutzen
oder statt Schleife rekursiver Aufruf, wie ja auch beim Merge
beim Merge, falls das wirklich schon was tut, prev-Verlinkungen auch würdigen, neu setzen
Danke ich werde das noch korrigieren. Allerdings von der Programmausgabe scheint es schon zu “passen” oder gibt es da Grenzfälle wo mein Programm nicht die richtige Ausgabe ausgibt?
Tipp 1 war doppelter Code, kann kaum schaden,
Tipp 2 war falsche Speicherfreigabe, wird sich kaum in der Ausgabe bemerkbar machen, aber könnte trotzdem als mächtig falsch gelten
Tipp 3 war falsche prev-Links, die nutzt du bisher nirgendwo, insofern programmtechnisch sekundär, aber gewiss auch nicht schön
okay, was ich aber nicht verstehe, wenn der Speicher nach Programmende eh freigegeben wird. Brauch ich ja quasi auch keine Funktion clearList() aufrufen, weil Sie ja kurz vor Programmende läuft und der Speicher ja kurze Zeit später sowieso vom BS freigegeben würde oder?
Vorweg: Eine “vernünftige” autom. Codeformatierung bekommst du nur mit Eclipse, NetBeans, Visual Studio oder Ähnlichen (nicht kostenlosen) Ides hin.
Dann hast du ja doch ziemlich viel geändert. Ich dachte, du “kopierst” das von mir einfach.
Dann MergeSort auf einer verketteten Liste stelle ich mir schwierig vor. MergeSort geht ja so, das die Mitte ermittelt werden muss. Laufzeit ist dann nicht O(1) sondern O(n/2).
Allerdings setzt du dann ein Elem., z. B. aus der rechten Teilhälfte, an den Anfang. Dadurch stimmen dann die Pointer der Parameter der anderen Aufrufe nicht mehr.
Div:
4 3 1 2
4 3 und 1 2
4 und 3 und 1 und 2
Con:
usw.
Ok, mal anders gefragt, welche Funktion(en) funktioniert noch nicht richtig?