doppelt verlinkte liste c++

leooo

Grünschnabel
hallo leute!

solangsam bin ich echt am verzweifeln... ich sitze nun schon fast den ganzen tag an dem einen problem und hoffe ihr könnt mir weiterhelfen!
wie ihr aus dem titel ja schon entnehmen könnt, geht es dabei um doppelt verlinkte listen.

ich verstehe zwar was der sinn des ganzen ist, aber wenn es zur umsetzung kommt versteh ich garnix mehr.

ich versuche nun mit der lösung der aufgabe das ganze zu verstehen, komm aber auch da nicht wirklich weiter.
hab mal kommentiert was ich dazu denke... aber beim schreiben hab ich schon gemerkt dass das alles nicht so wirklich stimmen kann...
vielleicht kann mir ja einer von euch helfen! vielleicht hat ja einer von euch lust mir diesen code einmal für ganz doofe zu erklären. bin wirklich am verzweifeln!! oder kennt ein super tutorial wo die vorgehensweise beschrieben ist... ich find leider nichts :(
ganz lieben dank!!
(sorry für den langen code...)

Code:
#include <iostream>
#include <string>
using namespace std;
 
 
struct Knoten	//Knoten erstellen
{
	Knoten *next; //pfeil nach rechts
	Knoten *last;	//pfeil nach links
	string info; //wort
};
 
void haengAn(Knoten *& kn, string s)//übergab  von speiher a und wort
{
 
	Knoten * ptr = new Knoten;	//speicherplatz für den neuen knoten dynamisch erstellen
	ptr->last = kn;	//zeigt auf den vorherigen knoten
	ptr->info = s; //wort übergabe
	ptr->next = NULL; //nächster zeiger zeigt auf null aber warum?
 
	Knoten * ptr2 = ptr->last; //neuer behälter verlinkt mit behälter davor(?)
	if(ptr2 != NULL) //wenn ptr2 nicht leer ist dann
		ptr2->next = ptr;//neuer behälter bekommt neue verlinkung
	kn = ptr; //übergabe mit dem neuen wort an das hauptprogramm
}
 
string gibAlle(Knoten * kn)
{
	Knoten *ptr = kn; //knoten bekommt wert vom knoten aus unterprogramm
	string s = "";//leerzeichen
 
	if(ptr != NULL)//wenn der zeiger auf etwas zeigt dann..//
		while(ptr->last != NULL)//..und der zeiger nach links nicht "leer" ist..
			ptr	= ptr->last;//wird neue verlinkung erstellt
 
	while(ptr != NULL)//******** wieso wird das hier nochmal abgefragt?
	{
		s += ptr->info +" ";//aneinanderreihen der strings
		ptr = ptr->next;//verlinkung zum nächsten knoten
	}
 
	delete ptr;
	return s;
}
 
void loesch(Knoten *&kn) //zum löschen eines knotens
{
	Knoten * ptr = kn;//ptr bekommt den wert von kn
 
	while(ptr != NULL)//wenn dieser nicht null ist dann...
	{
		kn = kn->last;//ergibt für mich überhaupt keinn sinn
	    delete ptr;
	    ptr = kn;
	}
}

void main()
{
	Knoten* speicherA = NULL;// erster knoten zeigt auf null
	Knoten* speicherB = NULL;//erster knoten zeigt auf null
 
	haengAn(speicherA, "Fischers");
	haengAn(speicherA, "Fritze");
 
	haengAn(speicherB, "kauft");
	haengAn(speicherB, "frische");
	haengAn(speicherB, "fesche");
	haengAn(speicherB, "fette");
	haengAn(speicherB, "Fische");
 
	std::cout << gibAlle(speicherA) << std::endl;
	std::cout << gibAlle(speicherB) << std::endl;
 
	haengAn(speicherA, gibAlle(speicherB));
	loesch(speicherB);
 
	std::cout << gibAlle(speicherA) << std::endl;
	std::cout << gibAlle(speicherB) << std::endl;
 
	loesch(speicherA);
}
 
Hi und Willkommen bei tutorials.de :)

Zum struct knoten:
Hier erstellst du noch keinen Knoten.
Hier wird festgelegt, was ein Knoten ist und was er enthalten soll.
Aber einen wirklich existierenden Knoten gibts noch nicht.

Zu haengAn:
Warum next auf NULL zeigt?
NULL ist in C und C++ sowas wie "Nichts".
Und da das neue Element am Schluss der Liste angehängt werden soll, kommt danach nichts mehr.
Angenommen, eine Liste mit drei Elementen A B und C.
Dann zeigt:
next von A auf B
next von B auf C
last von B auf A
last von C auf B
next von C auf NULL, weil danach nichts mehr kommt
last von A auf NULL, weil davor nichts ist

Die nächsten drei Zeilen: Das neue Element weiss ja jetzt, dass es aus next NULL hat (weil es am Schluss dazugehängt wird) und dass last das ehemals Letzte ist.
Aber: Dieses vorige letzte (das als kn übergeben wurde) muss ja auch noch wissen, das nach ihm was neues kommt.
Also bekommt es ein next.
Das ganze aber nur, wenn als kn nicht NULL übergeben wurde.
Das würde bedeuten, das noch nichts da ist und das neue Element das Erste ist.

Die letzte Zeile: Das kn, dass man übergeben hat, war ursprünglich das letzte Element der Liste.
Jetzt ist aber das neue Element am Schluss.
Damit die Variable im main (oder woher die Funktion sonst aufgerufen wird) auch weiterhin das letzte bleibt, wird diese von der Funktion aus umgeändert - auf das Neue.

Zu gibAlle:
Kommentar Zeile 1: Da ist was verwechselt. Der Wert kommt von main. Das UnterProgramm (oder auch Funktion) ist aber gibAlle.
Nächste Zeile (string s): "" ist kein Leerzeichen. Ein Leerzeichen ist " ", die lange Taste auf der Tastatur. "" hat nicht einmal das, ist einfach leer.

Das if danach: Wenn das Übergebene NULL ist, ist wie schon gesagt nichts da. Kein einziges Element. Dann gibts auch nichts zum Ausgeben.
Wenn aber was da ist, nimmt man last, von dem wieder last usw. bis man ganz am Anfang ankommt (Grundsätzlich wird von haengAn ja immer das letzte Element als Ausgangspunkt genommen). Das erste Element hat als last NULL, das sollte die Schleifenbedingung erklären.

Mit dem nächsten while und seinem Inhalt wird wieder von vorn nach hinten gespult und dabei die ganzen Strings aus den infos zusammengesammelt.
Das ist ja der Sinn der Funktion: Alle Strings in einen stopfen.
Warum "das hier nochmal abgefragt wird"?
1: Es geht nach jedem Element weiter zum next, bis irgendwann wieder mal das Ende und somit NULL da ist. Deshalb die Bedingung, damit man rechtzeitig aufhört.
2: Wenn schon von Anfang an kein Element in der Liste war muss auch dieses while nicht gemacht werden. Zweil Fliegen mit einer Klappe.

Die letzten zwei Zeilen: Das return passt soweit, aber...
delete ptr!? Wieso? Weg damit.
Die Funktion hier soll Strings in einen stopfen, keine Sachen wahllos löschen.

Rest kommt noch...unten
 
Zuletzt bearbeitet:
wow danke schonmal! jetzt seh ich schon etwas klarer.
nur diesen teil hier hab ich glaub ich noch nicht ganz verstanden

Knoten * ptr2 = ptr->last;
if(ptr2 != NULL)
ptr2->next = ptr;
kn = ptr; /
ich sag hier also dem quasi erstem knoten (knoten*ptr2) das er auch ein next hat... aber warum steht dann da ptr ->last?
und das kn= ptr bedeutet ds nun ptr den letzten platz eingenommen hat richtig?

vielen dank dass du so schnell geantwortet hast! ich freu mich auf den rest:)
 
zu loesch:
Verständnisfehler: Das löscht nicht einen Knoten, sondern alle. Die ganze Liste.
Da als Ausgangspunkt immer der letzte Knoten genommen wird zuerst den letzten, dann vorletzten usw...
Und jetzt mal zum Überlegen: Wenn man den letzten Knoten löscht ist er weg.
Dann kann man nicht mehr per last zum vorletzten.
Deshalb muss man zuerst nachschauen, was in last ist, sich das irgendwo merken und erst dann löschen.

In der Schleife wird sich zuerst last gemerkt, dann gelöscht und drittens der ehemals vorletzte/jetzt letzte Knoten als Ausgangspunkt genommen, um das Ganze wieder zu machen. Solange, bis keine Knoten mehr da sind.

Und noch zum main:
Bei den ersten zwei Zeilen: Hmm..die Pointer zeigen auf NULL, stimmt.
Aber nur falls es unklar ist: Die zwei Knoten existieren zu dem Zeitpunkt noch gar nicht. NULL=Nichts
Erst, wenn das erste haengAn merkt "da ist noch gar nichts" wird wirklich ein Knoten in die Welt gesetzt.
Der Rest sollte eigentlich klar sein, oder?

Zu deinem neuen Beitrag:
Angenommen, es besteht eine Liste mit zwei Knoten A und B.
Dazu soll jetzt ein neuer Knoten C.
C weiß schon, das nach ihm NULL ist. C weiß auch, dass (wenn fertig dazugefügt ist) vor ihm B sein wird.
B weiß aber noch nicht, dass nach ihm C kommt. B denkt noch immer an NULL.
In der Funktion werden zwei Hilfsvariablen verwendet: ptr zeigt auf das neue Element C, und ptr2 auf ptr->last.
Also C->last. Und weil C ja schon weiss, dass vor ihm B ist, zeigt ptr2 auf B.

Das if danach: B existiert, ist also nicht NULL. Und weiter zur letzten wichtigen Zeile:
Wie gesagt, das einzige Problem zu dem Zeitpunkt ist, dass B seinen neuen Nachfolger nicht kennt.
Also wird hier dem ptr2>next ptr zugewiesen. next von B zeigt damit auf C.
Fertig.

Wenn du noch Fragen hast: Immer her damit :D
Heute bin ich wieder in Schreiblaune...

Gruß
 
Zuletzt bearbeitet:
vielen vielen dank!
hab leider noch ein paar fragen
Nächste Zeile (string s): "" ist kein Leerzeichen. Ein Leerzeichen ist " ", die lange Taste auf der Tastatur. "" hat nicht einmal das, ist einfach leer.

stimmt das hab ich falsch gesehen :) aber warum wird das dann hin geschrieben? hätte man es nicht einfach weg lassen können?

Warum "das hier nochmal abgefragt wird"?
hier handelt es sich dann doch um das nächste element oder? wrum wird hier dann nicht auch noch überprüft ob der next zeiger auf NULL zeigt... weil es egal ist oder? es würde dann ja beim nächsten durchgang beim ersten while überprüft werden, richtig?

sonst hab ich es glaub ich mehr oder weniger verstanden... vielen vielen dank! du hast mir wirklich sehr geholfen! falls mir nochwas einfällt dann poste ich hier nochmal :)
 
Zum "Leerzeichen"-String: In einer Schleife später in der Funktion wird mit s+=... immer was angehängt.
Genauer gesagt zum vorhandenen String am Ende noch was dazugehängt.
Dazu muss aber schon ein String vorhanden sein. In dem Fall ist er zwar komplett leer, gilt aber als String.

Zum "Nochmal abfragen": Wegen dem vorderen Teil der Funktion steht ptr zu dem Zeitpunkt auf dem ersten Element. A.
A wird überprüft. Dann wird was mit dem String gemacht. Dann springt ptr ein next weiter zu B.
B überprüfen, Stringzueg, mit next zu C...
Also das jeweilige next zu prüfen ist wie du sagst sinnlos, weil es sowieso noch drankommt.

Gruß
 
Zurück