kramann.info
© Guido Kramann

Login: Passwort:










Informatik3
1 Vom_struct_zur_Klasse
..1.1 Vom_struct_zur_Klasse
..1.2 struct_Programm
..1.3 Klassen_Programm
..1.4 Offene_Fragen
..1.5 Historie
..1.6 Objektabstraktion
..1.7 OO_Kundenverwaltung
..1.8 Objektfaehigkeiten
..1.9 Formatierung
..1.10 Motivation
..1.11 Uebung1
..1.12 Uebung2
2 UML
..2.1 Volumenberechnung
..2.2 UML_Klassendiagramm
..2.3 Konstruktor
..2.4 Statische_Variable
3 Strings
..3.1 Klassenbibliotheken
..3.2 stringUML
..3.3 Uebung3
4 Initialisierungen
4 bluej
5 Zeiger_und_Arrays
..5.1 Zeiger
..5.2 Zeiger_und_Funktion
..5.3 Uebung4
6 Vererbung
..6.1 MesswerteUML
..6.2 MesswerteProgramm
..6.3 VererbungsProgramm
..6.4 Vector
..6.5 Uebung
7 Modifikatoren
..7.1 public_Vererbung
..7.2 protected_Vererbung
8 Listen_und_Templates
..8.1 Containertypen
....8.1.1 ListeUML
....8.1.2 ListeProgramm
..8.2 Templates
....8.2.1 Listentemplate
....8.2.2 STLvectorTemplate
..8.3 Uebung5
..8.4 Uebung6
..8.5 Uebung7
9 Java
..9.1 Uebung
..9.2 GettingStarted
..9.3 Animation
..9.4 Hybrid
..9.5 Threads
10 Delegation
11 LayoutProjekt
12 Fenster
13 Uebung
14 Zwischenprojekt
..14.1 Befehle
..14.2 Planung
..14.3 JNI
..14.4 JNIumsetzen
..14.5 Anwendungsklasse
..14.6 GUI01
..14.7 GUI02
15 Rasterlayout
..15.1 Bilder_Packages
..15.2 interfaces
..15.3 ArrayList
..15.4 clone
..15.5 Uebung
16 Nuetzliches
..16.1 Threads
..16.2 Animation
..16.3 RungeKutta
..16.4 Loesungsansatz
..16.5 Internetprogrammierung
....16.5.1 Codegenerierung
....16.5.2 PHP_Programmierung
....16.5.3 PHP_OOP
....16.5.4 Java
17 Algorithmen
..17.1 RungeKutta
..17.2 Loesungsansatz
..17.3 Evoopt
..17.4 Uebung12
..17.5 Uebung8_2014
..17.6 Ausdruecke
18 Uebung10
19 UML_ALT
..19.1 Flaechenberechnung
..19.2 UML_Flaechenberechnung
..19.3 Implementierung
..19.4 ListeUML
..19.5 ListenImplementierung
..19.6 Anwendung

8.1.2 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 8.1.2-1: zerlegetext_neu.cpp

zerlegetext_neu.cpp und .h-Dateien gezipt

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 8.1.2-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 8.1.2-3: ListenContainer.h