kw2

Werbung
Planung
• einfache Dateibehandlung (externe Dateien, Öffnen,
Lesen/Schreiben, Schließen).
• Diskussion des Problems, die Wörter in einem gegebenen Text
zu zählen und sie mit ihrer Häufigkeit alphabetisch
geordnet auszugeben.
Zunächst: Dateien. Lese aus einer Eingabe-Datei, schreibe
in eine Ausgabe-Datei.
Programm: nächste Folie.
#include <fstream.h>
#include <conio.h>
#include <stdlib.h>
const int Max_LG = 30;
void main() {
ifstream lesen;
ofstream schreiben;
char Gelesen[Max_LG];
lesen.open("prog-11.cpp");
if (!lesen) {
cout << "Fehler\n";
exit(-1);
}
schreiben.open("aus.out");
if (!schreiben) {
cout << " Fehler\n";
exit(-1);
}
while (!lesen.eof()) {
lesen >> Gelesen;
schreiben << Gelesen
<< endl;
}
lesen.close();
schreiben.close();
}
Zu beachten:
• #include <fstream.h> bindet die Bibliothek ein.
• ifstream lesen: von der Datei-Variablen lesen soll
gelesen werden, sie muß also einen Wert bekommen und
zum Lesen geöffnet werden (mit
lesen.open("prog-11.cpp");
Erfolg beim Öffnen: lesen != 0,
Mißerfolg: lesen == 0 [z.B.: Datei existiert nicht])
• Benutzung: wie cin
• Testen: lesen.eof() (!= 0 genau dann, wenn
das Ende der Datei noch nicht erreicht ist)
• Nach Benutzung: schließen mit lesen.close()
• Analog: ofstream für die Ausgabe.
Punkte:
• Benutzung von Dateien: wie Standard Ein-/Ausgabe
• ifstream: Eingabe, ofstream: Ausgabe
• Bindung von Datei-Variablen an Dateien beim Öffnen.
Schließen der Datei beim Verlassen des entsprechenden
Blocks.
• Werden Dateien zum Schreiben geöffnet, so geht ihr
vorheriger Inhalt verloren!
Wörter zählen
Problem:
• zähle die Wörter in einem gegebenen Text
• gib sie mit ihrer Häufigkeit alphabetisch geordnet aus
Datenstruktur: (erweiterter) binärer Suchbaum
text
zaehler
LSohn
RSohn
struct BinBaum {
char text[maxLen];
int zaehler;
BinBaum * LSohn, *RSohn;
};
Strategie:
• Suchen nach einer Zeichenkette im binären Suchbaum
• Zeichenkette nicht gefunden: neuen Knoten einfügen,
Zähler zu 1 initialisieren
• Zeichenkette gefunden: Zähler um 1 erhöhen
BinBaum * Einfuegen(BinBaum *B, char * k) {
void strcpy(char *, char *);
int strcmp(char *, char *);
if (B == NULL) {
BinBaum *Hilf = new BinBaum;
strcpy(Hilf->text, k);
Hilf->zaehler = 1;
Hilf->LSohn = Hilf->RSohn = NULL;
return Hilf;
}
else {
int Vergl = strcmp(B->text,k);
if (Vergl < 0)
B->RSohn = Einfuegen(B->RSohn, k);
else if (Vergl > 0)
B->LSohn = Einfuegen(B->LSohn, k);
else if (Vergl == 0)
B->zaehler += 1;
return B;
}
}
Alphabetisch geordnete Ausgabe?
Durchlaufe den binären Suchbaum mit Wurzel w
rekursiv wie folgt:
• Durchlauf durch den linken Unterbaum von w
• Ausdruck der Wurzel w
• Durchlauf durch den rechten Unterbaum von w
Resultat: geordnete Ausgabe
Beispiel:
17
17
6
4
6
23
7
18
26
4
23
7
18
26
Wie beweist man das?
Durch vollständige Induktion nach der Anzahl der Knoten.
Der Induktionsbeginn (kein Knoten) ist trivial.
Der Induktionsschritt:
der linke Unterbaum wird geordnet ausgegeben (IV),
dann wird die Wurzel ausgegeben,
dann wird der rechte Unterbaum geordnet ausgegeben (IV).
Die Wurzel steht bzgl. der Ordnung in der Mitte.
void Ausdrucken(BinBaum *K, ofstream *aus) {
void KnotenDruck(BinBaum *, ofstream *);
if (K != NULL) {
Ausdrucken(K->LSohn, aus);
KnotenDruck(K, aus);
Ausdrucken(K->RSohn, aus);
}
}
void main() {
BinBaum * Einlesen(ifstream *), *BST;
void Ausdrucken(BinBaum *, ofstream *);
ifstream *EingabeDatei;
ofstream *Ausgabe = new ofstream("von.aus");
EingabeDatei = new ifstream("von.txt");
if (!EingabeDatei) {
cout << "Problem: Eingabe\n";
exit(-1);
}
BST = Einlesen(EingabeDatei);
Ausdrucken(BST, Ausgabe);
}
Bemerkenswert:
• Ein- und Ausgabedateien werden als Zeiger auf
ifstream und ofstream deklariert.
• beachte die Initialisierung:
ifstream *EingabeDatei;
EingabeDatei = new ifstream("von.txt");
mit der Variante
ofstream *Ausgabe = new ofstream("von.aus");
BinBaum * Einlesen(ifstream *inp) {
BinBaum *bst = NULL,
* Einfuegen(BinBaum *, char *);
char gelesen[maxLen];
*inp >> gelesen;
while (!(*inp).eof()) {
bst = Einfuegen(bst, gelesen);
*inp >> gelesen;
}
return bst;
}
Feinheiten: *inp und (*inp).eof()
Analog: Ausgabe
void KnotenDruck(BinBaum *T, ofstream *aus){
void Schreiben(char *, int, ofstream *);
Schreiben(T->text, T->zaehler, aus);
}
void Schreiben(char * s, int k, ofstream *aus) {
*aus << k << "\t\t\t" << s << endl;
}
Herr von Ribbeck auf Ribbeck im Havelland,
Ein Birnbaum in seinem Garten stand,
Und kam die goldene Herbsteszeit
Und die Birnen leuchteten weit und breit,
Da stopfte, wenn's Mittag vom Turme scholl,
Der von Ribbeck sich beide Taschen voll,
Und kam in Pantinen ein Junge daher,
So rief er: »Junge, wiste 'ne Beer?«
Und kam ein Mädel, so rief er: »Lütt Dirn,
Kumm man röwer, ick hebb 'ne Birn.«
So ging es viel Jahre, bis lobesam
Der von Ribbeck auf Ribbeck zu sterben kam.
Er fühlte sein Ende. 's war Herbsteszeit,
Wieder lachten die Birnen weit und breit;
Da sagte von Ribbeck: »Ich scheide nun ab.
Legt mir eine Birne mit ins Grab.«
Und drei Tage drauf, aus dem Doppeldachhaus,
Trugen von Ribbeck sie hinaus,
Alle Bauern und Büdner mit Feiergesicht
Sangen »Jesus meine Zuversicht«,
Und die Kinder klagten, das Herze schwer:
»He is dod nu. Wer giwt uns nu 'ne Beer?«
1
1
12
1
1
1
1
1
1
1
4
2
1
1
1
1
1
1
Trugen
Turme
Und
Wer
Wieder
Zuversicht«,
ab,
ab.
alte,
alten
auf
aus
bat,
beide
bis
breit,
breit.
breit;
Durchlauf durch Bäume
17
6
4
Diese Art des Durchlaufs
heißt Inorder-Durchlauf.
23
7
18
26
Inorder(Wurzel BLinks)
w
Inorder
(
BLinks
BRechts
)=
Druck(w)
Inorder(Wurzel BRechts)
Druck(w)
w
(
Präorder
BLinks
BRechts
)=
Präorder(Wurzel BLinks)
Präorder(Wurzel BRechts)
17
6
4
23
7
18
17 # 6 # 4 # 7 # 23 # 18 # 26
26
Postorder(Wurzel BLinks)
w
Postorder
(
BLinks
BRechts
)=
Postorder(Wurzel BRechts)
Druck(w)
17
6
4
23
7
18
4 # 7 # 6 # 18 # 26 # 23 # 17
26
Strategie bei allen drei Durchlaufarten heißt Tiefensuche (es
wird zunächst in die Tiefe und nicht in die Breite gegangen).
Alternative: Breitensuche - trage den Baum schichtenweise ab.
Beispiel:
17
6
4
17 # 6 # 23 # 4 # 7 # 18 # 26
23
7
18
Implementation?
26
Herunterladen