C++ Programm mit Liste zerlegetext_neu.cpp
Das Beispiel aus dem Kapitel "Strings" soll nun mit Hilfe der Klasse ContainerListe
realisiert werden. D.h. Es werden zunächst die Klassen ContainerListe
und
Liste
geschrieben und in die include-Files ContainerListe.h, bzw. Liste.h abgelegt.
In das Programm zerlegetext.cpp werden sie dann mit include-Befehlen eingebunden. Die Funktion
zerlegeText()
wird nun so modifiziert, dass ihr nicht ein Zeiger auf ein
string-Array, sondern auf ein Objekt vom Typ ContainerListe übergeben wird, in das sie dann die
gefundenen Wörter hineinlegt.
Schauen wir uns zunächst zerlegetext_neu.cpp an, und versuchen zu verstehen, wie dort ein Objekt der Klasse ContainerListe benutzt wird:
#include <string> #include <iostream> #include "Liste.h" #include "ListenContainer.h" using namespace std; bool istTrennzeichen(char zeichen, string trennzeichen) { for(int i=0;i<trennzeichen.size();i++) { if(zeichen == trennzeichen.at(i)) return true; } return false; } void zerlegeText(ListenContainer* mLC,string text,string trennzeichen) { int wortbeginn = 0; int wortende = 0; for(int i=0;i<text.size();i++) { if( !istTrennzeichen(text.at(i),trennzeichen) ) { wortbeginn = i; while( i+1<text.size() && !istTrennzeichen(text.at(i+1),trennzeichen) ) i++; wortende = i; mLC->append(text.substr(wortbeginn,wortende-wortbeginn+1)); } } } int main(void) { string text = "Das ist ein Text."; string trennzeichen = ".,;: "; ListenContainer mLC; //einige Tests vorab: mLC.append("Test0"); mLC.append("Test1"); mLC.append("Test2"); mLC.del(1); cout<<"GROESSE der Liste="<<mLC.getSize()<<endl; cout<<"Wort Nr."<<1<<":"<<mLC.get(1)<<endl; mLC.clear(); //einige Tests vorab: ENDE zerlegeText(&mLC,text,trennzeichen); cout<<"GROESSE der Liste="<<mLC.getSize()<<endl; for(int i=0;i<mLC.getSize();i++) cout<<"Wort Nr."<<i<<":"<<mLC.get(i)<<endl; }
Code 0-1: zerlegetext_neu.cpp
Schauen wir uns nun die Implementierungen der Klassen ContainerListe
und Liste
an. Dazu vorab:
Ein Problem, das beim linearen Durchsuchen der Liste auftaucht, wurde noch nicht behandelt: Wie erkennt man, dass ein Element das letzte Element ist?
Eine mögliche Lösung ist, das aktuelle Element darauf hin zu prüfen, ob es seinerseits einen Nachfolger besitzt. Indem man nachfolger-Zeiger, die auf kein Objekt verweisen zu Null-Pointern macht, sie also auf 0 setzt, kann dieser Zustand klar definiert werden.
Achtung: der Mechanismus NULL aus C funktioniert in C++ nicht richtig, deshalb immer 0 und nicht NULL verwenden.
Angenommen die Referenz auf das erste Element, also das kopfelement selbst, zeigt auf 0. Dann kann man nicht damit beginnen nach Nachfolgern zu suchen. Um eine einheitliche Behandlung in den Algorithmen zu gewährleisten, bleibt deshalb das erste Element leer, d.h. es enthält keine Daten und zählt auch nicht zur eigentlichen Liste dazu.
using namespace std; class Liste { public: Liste() { nachfolger = 0; } Liste(string indaten) { daten = indaten; nachfolger = 0; } Liste *nachfolger; string daten; };
Code 0-2: Liste.h
using namespace std; class ListenContainer { private: Liste kopfelement; public: ListenContainer() { //Zunächst leere Liste erzeugen: kopfelement.nachfolger = 0; } //Übergebenes String in neues Listen-Element packen und dieses an das Ende der Liste hängen void append(string text) { Liste* element = new Liste(text); Liste* zeiger = &kopfelement; while(zeiger->nachfolger!=0) zeiger = zeiger->nachfolger; zeiger->nachfolger = element; } //Refrerenz auf das i-te Listenelement suchen und dessen String-Inhalt zurückgeben string get(int index) { Liste* zeiger = kopfelement.nachfolger; for(int i=0;i<index;i++) { if(zeiger == 0) return 0; zeiger = zeiger->nachfolger; } return zeiger->daten; } //i-tes Listenelement löschen void del(int index) { //Hier muss der Zeiger auf das vorangehende und das nachfolgende Element //efunden werden. Liste* zeiger = kopfelement.nachfolger; Liste* zeigervor = &kopfelement; Liste* zeigernach = 0; for(int i=0;i<index;i++) { if(zeiger == 0) return; zeigervor = zeiger; zeiger = zeiger->nachfolger; } zeigernach = zeiger->nachfolger; //Vorgänger-Element mit Nachfolger-Element verbinden: zeigervor->nachfolger = zeigernach; //Speicher für aktuelles Element freigeben: delete zeiger; } //die ganze Liste löschen. void clear() { Liste* zeiger; Liste* zeigervor = &kopfelement; //Speicher bereinigen: while(kopfelement.nachfolger != 0) { zeiger = kopfelement.nachfolger; zeigervor = &kopfelement; while(zeiger->nachfolger != 0) { zeigervor = zeiger; zeiger = zeiger->nachfolger; } zeigervor->nachfolger=0; delete zeiger; } } //Liefert die Länge der Liste zurück int getSize() { int laenge = 0; Liste* zeiger = &kopfelement; while(zeiger->nachfolger!=0) { laenge++; zeiger = zeiger->nachfolger; } return laenge; } };
Code 0-3: ListenContainer.h