DAP1-Folien-2019_2.fm
Folie-1
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen, Algorithmen
und Programmierung 1 (DAP 1)
Fakultät für Informatik
Wintersemester 2019/20
Stefan Dissmann
Folie-2
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Inhaltsverzeichnis
Abschnitt 0: Einführung Folie 4
Abschnitt 1: Einfache Algorithmen Folie 98
Abschnitt 2: Klasse und Objekt Folie 199
Abschnitt 3: Sortieralgorithmen Folie 297
Abschnitt 4: Rekursive Algorithmen Folie 397
Abschnitt 5: Datenkompression (Huffman-Codierung) Folie 469
Abschnitt 6: Datenstruktur Binärer Suchbaum Folie 540
Abschnitt 7: Vererbung und Polymorphie Folie 637
Abschnitt 8: Datenstruktur Doppelt verkettete Liste Folie 707
Abschnitt 9: Entwurfsmuster Iterator Folie 760
Abschnitt 10: Entwurfsmuster Strategie Folie 812
Abschnitt 11: Generische Klassen Folie 840
Abschnitt 12: Interface Folie 913
Abschnitt 13: Anonyme Klassen und Lambda-Ausdrücke Folie 954
Abschnitt 14: Beispiel: Mustererkennung Folie 1001
Abschnitt 15: Ausnahmebehandlung und Zugriff auf Dateien Folie 1056
Abschnitt 16: Grafische Benutzungsoberflächen – ein Beispiel Folie 1106
Abschnitt 17: Datenstruktur Hashtable Folie 1127
Abschnitt 18: Prioritätswarteschlange (Heap) Folie 1148
Abschnitt 19: Abspann: weitere Anweisungen, Operatoren und Konzepte in Java Folie 1195
Folie-3
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele
Nach erfolgreichem Abschluss des Moduls DAP 1 sollen
die teilnehmenden Studierenden
Programme in der Programmiersprache Java implementieren können,
Java-Klassen und -Bibliotheken nutzen können,
Java-Klassen und -Bibliotheken implementieren können,
einige wichtige Algorithmen mit ihren Implementierungen kennen,
einige wichtige Datenstrukturen mit ihren Implementierungen kennen,
eigene Algorithmen konzipieren und implementieren können,
eigene Datenstrukturen konzipieren und implementieren können,
Algorithmen und Datenstrukturen bewerten können,
objektorientierte Mechanismen anwenden können,
einige Entwurfsmuster einsetzen können,
einfache Ideen der Softwaretechnik einsetzen können.
Folie-4
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen, Algorithmen
und Programmierung 1 (DAP 1)
Fakultät für Informatik
Wintersemester 2019/20
Stefan Dissmann
Einführung
Folie-5
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele Einführung
Nach Durcharbeiten der Einführung sollen
die teilnehmenden Studierenden
ein erstes Verständnis von dem Begriff Datenstruktur besitzen
ein erstes Verständnis von dem Begriff Algorithmus besitzen
ein Beispiel für die Beziehung zwischen Datenstrukturen und Algorithmen angeben können
den Verarbeitungsablauf bei der Erstellung von Java-Programmen kennen
die Begriffe Syntax und Semantik unterscheiden und zuordnen können
Syntaxdiagramme lesen und entscheiden können,
ob ein Wort zu einer gegebenen Sprache gehört
Syntaxdiagramme für einfache Konstrukte selbst formulieren können
einfache, nur aus einer Klasse bestehende Java-Programme mit ausschließlich statischen
Methoden implementieren, übersetzen und ausführen lassen können
Fehler den Phasen Compilierung oder Ausführung zuordnen können
Folie-6
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
DAP
=
Datenstrukturen, Algorithmen
und Programmierung
Folie-7
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen und Algorithmen
1. Beispiel für eine Datenstruktur: ungeordnete Tabelle von Matrikelnummern
1: 165321 2: 173048 3: 164213 4: 156736 5: 138916 6: 154701 7: 160200 8: 172727
9: 172002 10: 161823 11: 156807 12: 173559 13: 147644 14: 141902 15: 164671 16: 160097
17: 156941 18: 165411 19: 155467 20: 161634 21: 155593 22: 121993 23: 165997 24: 156019
25: 158904 26: 147219 27: 158603 28: 164340 29: 172409 30: 173011 31: 173105 32: 155711
33: 161901 34: 158815 35: 160644 36: 165781 37: 158485 38: 172523 39: 138321 40: 161202
41: 173114 42: 158731 43: 172230 44: 156739 45: 164478 46: 164510 47: 161361 48: 165401
49: 164093 50: 155319 51: 173191 52: 156702 53: 165782 54: 161422 55: 138005 56: 158216
57: 155245 58: 160791 59: 165903 60: 160519 61: 161517 62: 156541 63: 147008 64: 164733
65: 147358 66: 172196 67: 161776 68: 158514 69: 160427 70: 160371 71: 172692 72: 173671
73: 160817 74: 164181 75: 158604 76: 172341 77: 173801 78: 165443 79: 158332 80: 156113
Folie-8
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen und Algorithmen (Fortsetzung)
1. Beispiel für eine Datenstruktur: ungeordnete Tabelle von Matrikelnummern
Aufgabe: Stelle fest, ob eine vorgegebene Nummer enthalten ist? (z.B. 166392)
1: 165321 2: 173048 3: 164213 4: 156736 5: 138916 6: 154701 7: 160200 8: 172727
9: 172002 10: 161823 11: 156807 12: 173559 13: 147644 14: 141902 15: 164671 16: 160097
17: 156941 18: 165411 19: 155467 20: 161634 21: 155593 22: 121993 23: 165997 24: 156019
25: 158904 26: 147219 27: 158603 28: 164340 29: 172409 30: 173011 31: 173105 32: 155711
33: 161901 34: 158815 35: 160644 36: 165781 37: 158485 38: 172523 39: 138321 40: 161202
41: 173114 42: 158731 43: 172230 44: 156739 45: 164478 46: 164510 47: 161361 48: 165401
49: 164093 50: 155319 51: 173191 52: 156702 53: 165782 54: 161422 55: 138005 56: 158216
57: 155245 58: 160791 59: 165903 60: 160519 61: 161517 62: 156541 63: 147008 64: 164733
65: 147358 66: 172196 67: 161776 68: 158514 69: 160427 70: 160371 71: 172692 72: 173671
73: 160817 74: 164181 75: 158604 76: 172341 77: 173801 78: 165443 79: 158332 80: 156113
Folie-9
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen und Algorithmen (Fortsetzung)
1. Beispiel für eine Datenstruktur: ungeordnete Tabelle von Matrikelnummern
Aufgabe: Stelle fest, ob eine vorgegebene Nummer enthalten ist? (z.B. 166392)
Algorithmus: Überprüfe nacheinander solange Einträge, bis die Nummer gefunden wurde.
1: 165321 2: 173048 3: 164213 4: 156736 5: 138916 6: 154701 7: 160200 8: 172727
9: 172002 10: 161823 11: 156807 12: 173559 13: 147644 14: 141902 15: 164671 16: 160097
17: 156941 18: 165411 19: 155467 20: 161634 21: 155593 22: 121993 23: 165997 24: 156019
25: 158904 26: 147219 27: 158603 28: 164340 29: 172409 30: 173011 31: 173105 32: 155711
33: 161901 34: 158815 35: 160644 36: 165781 37: 158485 38: 172523 39: 138321 40: 161202
41: 173114 42: 158731 43: 172230 44: 156739 45: 164478 46: 164510 47: 161361 48: 165401
49: 164093 50: 155319 51: 173191 52: 156702 53: 165782 54: 161422 55: 138005 56: 158216
57: 155245 58: 160791 59: 165903 60: 160519 61: 161517 62: 156541 63: 147008 64: 164733
65: 147358 66: 172196 67: 161776 68: 158514 69: 160427 70: 160371 71: 172692 72: 173671
73: 160817 74: 164181 75: 158604 76: 172341 77: 173801 78: 165443 79: 158332 80: 156113
Folie-10
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen und Algorithmen (Fortsetzung)
1. Beispiel für eine Datenstruktur: ungeordnete Tabelle von Matrikelnummern
Aufgabe: Stelle fest, ob eine vorgegebene Nummer enthalten ist? (z.B. 166392)
Algorithmus: Überprüfe nacheinander solange Einträge, bis die Nummer gefunden wurde.
1: 165321 2: 173048 3: 164213 4: 156736 5: 138916 6: 154701 7: 160200 8: 172727
9: 172002 10: 161823 11: 156807 12: 173559 13: 147644 14: 141902 15: 164671 16: 160097
17: 156941 18: 165411 19: 155467 20: 161634 21: 155593 22: 121993 23: 165997 24: 156019
25: 158904 26: 147219 27: 158603 28: 164340 29: 172409 30: 173011 31: 173105 32: 155711
33: 161901 34: 158815 35: 160644 36: 165781 37: 158485 38: 172523 39: 138321 40: 161202
41: 173114 42: 158731 43: 172230 44: 156739 45: 164478 46: 164510 47: 161361 48: 165401
49: 164093 50: 155319 51: 173191 52: 156702 53: 165782 54: 161422 55: 138005 56: 158216
57: 155245 58: 160791 59: 165903 60: 160519 61: 161517 62: 156541 63: 147008 64: 164733
65: 147358 66: 172196 67: 161776 68: 158514 69: 160427 70: 160371 71: 172692 72: 173671
73: 160817 74: 164181 75: 158604 76: 172341 77: 173801 78: 165443 79: 158332 80: 156113
Folie-11
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen und Algorithmen (Fortsetzung)
2. Beispiel für eine Datenstruktur: geordnete Tabelle von Matrikelnummern
1: 138749 2: 141013 3: 141082 4: 141092 5: 141322 6: 145461 7: 145532 8: 145671
9: 145981 10: 145982 11: 145990 12: 148273 13: 148285 14: 148321 15: 148451 16: 148469
17: 149020 18: 149021 19: 149114 20: 149145 21: 149203 22: 149341 23: 149415 24: 149441
25: 149709 26: 150106 27: 151445 28: 151491 29: 151807 30: 153771 31: 153901 32: 154122
33: 154136 34: 154209 35: 155241 36: 155351 37: 155414 38: 155701 39: 156106 40: 156109
41: 156200 42: 156234 43: 156521 44: 156760 45: 159304 46: 159346 47: 159471 48: 159564
49: 159573 50: 159580 51: 160224 52: 160227 53: 160306 54: 160412 55: 160423 56: 164127
57: 164130 58: 165291 59: 165296 60: 165304 61: 165902 62: 165936 63: 165939 64: 165967
65: 170412 66: 170567 67: 170581 68: 171040 69: 172231 70: 172265 71: 172351 72: 172396
73: 172457 74: 172471 75: 173100 76: 173204 77: 173217 78: 173244 79: 173501 80: 173785
Folie-12
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen und Algorithmen (Fortsetzung)
2. Beispiel für eine Datenstruktur: geordnete Tabelle von Matrikelnummern
Aufgabe: Stelle fest, ob eine vorgegebene Nummer enthalten ist? (z.B. 170567)
1: 138749 2: 141013 3: 141082 4: 141092 5: 141322 6: 145461 7: 145532 8: 145671
9: 145981 10: 145982 11: 145990 12: 148273 13: 148285 14: 148321 15: 148451 16: 148469
17: 149020 18: 149021 19: 149114 20: 149145 21: 149203 22: 149341 23: 149415 24: 149441
25: 149709 26: 150106 27: 151445 28: 151491 29: 151807 30: 153771 31: 153901 32: 154122
33: 154136 34: 154209 35: 155241 36: 155351 37: 155414 38: 155701 39: 156106 40: 156109
41: 156200 42: 156234 43: 156521 44: 156760 45: 159304 46: 159346 47: 159471 48: 159564
49: 159573 50: 159580 51: 160224 52: 160227 53: 160306 54: 160412 55: 160423 56: 164127
57: 164130 58: 165291 59: 165296 60: 165304 61: 165902 62: 165936 63: 165939 64: 165967
65: 170412 66: 170567 67: 170581 68: 171040 69: 172231 70: 172265 71: 172351 72: 172396
73: 172457 74: 172471 75: 173100 76: 173204 77: 173217 78: 173244 79: 173501 80: 173785
Folie-13
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen und Algorithmen (Fortsetzung)
2. Beispiel für eine Datenstruktur: geordnete Tabelle von Matrikelnummern
Aufgabe: Stelle fest, ob eine vorgegebene Nummer enthalten ist? (z.B. 170567)
bekannter Algorithmus: Überprüfe nacheinander solange Einträge, bis die Nummer gefunden wurde.
1: 138749 2: 141013 3: 141082 4: 141092 5: 141322 6: 145461 7: 145532 8: 145671
9: 145981 10: 145982 11: 145990 12: 148273 13: 148285 14: 148321 15: 148451 16: 148469
17: 149020 18: 149021 19: 149114 20: 149145 21: 149203 22: 149341 23: 149415 24: 149441
25: 149709 26: 150106 27: 151445 28: 151491 29: 151807 30: 153771 31: 153901 32: 154122
33: 154136 34: 154209 35: 155241 36: 155351 37: 155414 38: 155701 39: 156106 40: 156109
41: 156200 42: 156234 43: 156521 44: 156760 45: 159304 46: 159346 47: 159471 48: 159564
49: 159573 50: 159580 51: 160224 52: 160227 53: 160306 54: 160412 55: 160423 56: 164127
57: 164130 58: 165291 59: 165296 60: 165304 61: 165902 62: 165936 63: 165939 64: 165967
65: 170412 66: 170567 67: 170581 68: 171040 69: 172231 70: 172265 71: 172351 72: 172396
73: 172457 74: 172471 75: 173100 76: 173204 77: 173217 78: 173244 79: 173501 80: 173785
Diese sequentielle Suche nutzt die Sortierung nicht aus!
Folie-14
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen und Algorithmen (Fortsetzung)
2. Beispiel für eine Datenstruktur: geordnete Tabelle von Matrikelnummern
Aufgabe: Stelle fest, ob eine vorgegebene Nummer enthalten ist? (z.B. 170567)
anderer Algorithmus: Suche weiter in der passenden Hälfte des zuletzt betrachteten Bereichs.
1: 138749 2: 141013 3: 141082 4: 141092 5: 141322 6: 145461 7: 145532 8: 145671
9: 145981 10: 145982 11: 145990 12: 148273 13: 148285 14: 148321 15: 148451 16: 148469
17: 149020 18: 149021 19: 149114 20: 149145 21: 149203 22: 149341 23: 149415 24: 149441
25: 149709 26: 150106 27: 151445 28: 151491 29: 151807 30: 153771 31: 153901 32: 154122
33: 154136 34: 154209 35: 155241 36: 155351 37: 155414 38: 155701 39: 156106 40: 156109
41: 156200 42: 156234 43: 156521 44: 156760 45: 159304 46: 159346 47: 159471 48: 159564
49: 159573 50: 159580 51: 160224 52: 160227 53: 160306 54: 160412 55: 160423 56: 164127
57: 164130 58: 165291 59: 165296 60: 165304 61: 165902 62: 165936 63: 165939 64: 165967
65: 170412 66: 170567 67: 170581 68: 171040 69: 172231 70: 172265 71: 172351 72: 172396
73: 172457 74: 172471 75: 173100 76: 173204 77: 173217 78: 173244 79: 173501 80: 173785
Folie-15
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen und Algorithmen (Fortsetzung)
2. Beispiel für eine Datenstruktur: geordnete Tabelle von Matrikelnummern
Aufgabe: Stelle fest, ob eine vorgegebene Nummer enthalten ist? (z.B. 170567)
anderer Algorithmus: Suche weiter in der passenden Hälfte des zuletzt betrachteten Bereichs.
1: 138749 2: 141013 3: 141082 4: 141092 5: 141322 6: 145461 7: 145532 8: 145671
9: 145981 10: 145982 11: 145990 12: 148273 13: 148285 14: 148321 15: 148451 16: 148469
17: 149020 18: 149021 19: 149114 20: 149145 21: 149203 22: 149341 23: 149415 24: 149441
25: 149709 26: 150106 27: 151445 28: 151491 29: 151807 30: 153771 31: 153901 32: 154122
33: 154136 34: 154209 35: 155241 36: 155351 37: 155414 38: 155701 39: 156106 40: 156109
41: 156200 42: 156234 43: 156521 44: 156760 45: 159304 46: 159346 47: 159471 48: 159564
49: 159573 50: 159580 51: 160224 52: 160227 53: 160306 54: 160412 55: 160423 56: 164127
57: 164130 58: 165291 59: 165296 60: 165304 61: 165902 62: 165936 63: 165939 64: 165967
65: 170412 66: 170567 67: 170581 68: 171040 69: 172231 70: 172265 71: 172351 72: 172396
73: 172457 74: 172471 75: 173100 76: 173204 77: 173217 78: 173244 79: 173501 80: 173785
Folie-16
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen und Algorithmen (Fortsetzung)
2. Beispiel für eine Datenstruktur: geordnete Tabelle von Matrikelnummern
Aufgabe: Stelle fest, ob eine vorgegebene Nummer enthalten ist? (z.B. 170567)
anderer Algorithmus: Suche weiter in der passenden Hälfte des zuletzt betrachteten Bereichs.
1: 138749 2: 141013 3: 141082 4: 141092 5: 141322 6: 145461 7: 145532 8: 145671
9: 145981 10: 145982 11: 145990 12: 148273 13: 148285 14: 148321 15: 148451 16: 148469
17: 149020 18: 149021 19: 149114 20: 149145 21: 149203 22: 149341 23: 149415 24: 149441
25: 149709 26: 150106 27: 151445 28: 151491 29: 151807 30: 153771 31: 153901 32: 154122
33: 154136 34: 154209 35: 155241 36: 155351 37: 155414 38: 155701 39: 156106 40: 156109
41: 156200 42: 156234 43: 156521 44: 156760 45: 159304 46: 159346 47: 159471 48: 159564
49: 159573 50: 159580 51: 160224 52: 160227 53: 160306 54: 160412 55: 160423 56: 164127
57: 164130 58: 165291 59: 165296 60: 165304 61: 165902 62: 165936 63: 165939 64: 165967
65: 170412 66: 170567 67: 170581 68: 171040 69: 172231 70: 172265 71: 172351 72: 172396
73: 172457 74: 172471 75: 173100 76: 173204 77: 173217 78: 173244 79: 173501 80: 173785
Folie-17
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen und Algorithmen (Fortsetzung)
2. Beispiel für eine Datenstruktur: geordnete Tabelle von Matrikelnummern
Aufgabe: Stelle fest, ob eine vorgegebene Nummer enthalten ist? (z.B. 170567)
anderer Algorithmus: Suche weiter in der passenden Hälfte des zuletzt betrachteten Bereichs.
1: 138749 2: 141013 3: 141082 4: 141092 5: 141322 6: 145461 7: 145532 8: 145671
9: 145981 10: 145982 11: 145990 12: 148273 13: 148285 14: 148321 15: 148451 16: 148469
17: 149020 18: 149021 19: 149114 20: 149145 21: 149203 22: 149341 23: 149415 24: 149441
25: 149709 26: 150106 27: 151445 28: 151491 29: 151807 30: 153771 31: 153901 32: 154122
33: 154136 34: 154209 35: 155241 36: 155351 37: 155414 38: 155701 39: 156106 40: 156109
41: 156200 42: 156234 43: 156521 44: 156760 45: 159304 46: 159346 47: 159471 48: 159564
49: 159573 50: 159580 51: 160224 52: 160227 53: 160306 54: 160412 55: 160423 56: 164127
57: 164130 58: 165291 59: 165296 60: 165304 61: 165902 62: 165936 63: 165939 64: 165967
65: 170412 66: 170567 67: 170581 68: 171040 69: 172231 70: 172265 71: 172351 72: 172396
73: 172457 74: 172471 75: 173100 76: 173204 77: 173217 78: 173244 79: 173501 80: 173785
Folie-18
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen und Algorithmen (Fortsetzung)
2. Beispiel für eine Datenstruktur: geordnete Tabelle von Matrikelnummern
Aufgabe: Stelle fest, ob eine vorgegebene Nummer enthalten ist? (z.B. 170567)
anderer Algorithmus: Suche weiter in der passenden Hälfte des zuletzt betrachteten Bereichs.
1: 138749 2: 141013 3: 141082 4: 141092 5: 141322 6: 145461 7: 145532 8: 145671
9: 145981 10: 145982 11: 145990 12: 148273 13: 148285 14: 148321 15: 148451 16: 148469
17: 149020 18: 149021 19: 149114 20: 149145 21: 149203 22: 149341 23: 149415 24: 149441
25: 149709 26: 150106 27: 151445 28: 151491 29: 151807 30: 153771 31: 153901 32: 154122
33: 154136 34: 154209 35: 155241 36: 155351 37: 155414 38: 155701 39: 156106 40: 156109
41: 156200 42: 156234 43: 156521 44: 156760 45: 159304 46: 159346 47: 159471 48: 159564
49: 159573 50: 159580 51: 160224 52: 160227 53: 160306 54: 160412 55: 160423 56: 164127
57: 164130 58: 165291 59: 165296 60: 165304 61: 165902 62: 165936 63: 165939 64: 165967
65: 170412 66: 170567 67: 170581 68: 171040 69: 172231 70: 172265 71: 172351 72: 172396
73: 172457 74: 172471 75: 173100 76: 173204 77: 173217 78: 173244 79: 173501 80: 173785
Folie-19
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen und Algorithmen (Fortsetzung)
2. Beispiel für eine Datenstruktur: geordnete Tabelle von Matrikelnummern
Aufgabe: Stelle fest, ob eine vorgegebene Nummer enthalten ist? (z.B. 170567)
anderer Algorithmus: Suche weiter in der passenden Hälfte des zuletzt betrachteten Bereichs.
1: 138749 2: 141013 3: 141082 4: 141092 5: 141322 6: 145461 7: 145532 8: 145671
9: 145981 10: 145982 11: 145990 12: 148273 13: 148285 14: 148321 15: 148451 16: 148469
17: 149020 18: 149021 19: 149114 20: 149145 21: 149203 22: 149341 23: 149415 24: 149441
25: 149709 26: 150106 27: 151445 28: 151491 29: 151807 30: 153771 31: 153901 32: 154122
33: 154136 34: 154209 35: 155241 36: 155351 37: 155414 38: 155701 39: 156106 40: 156109
41: 156200 42: 156234 43: 156521 44: 156760 45: 159304 46: 159346 47: 159471 48: 159564
49: 159573 50: 159580 51: 160224 52: 160227 53: 160306 54: 160412 55: 160423 56: 164127
57: 164130 58: 165291 59: 165296 60: 165304 61: 165902 62: 165936 63: 165939 64: 165967
65: 170412 66: 170567 67: 170581 68: 171040 69: 172231 70: 172265 71: 172351 72: 172396
73: 172457 74: 172471 75: 173100 76: 173204 77: 173217 78: 173244 79: 173501 80: 173785
Folie-20
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen und Algorithmen (Fortsetzung)
2. Beispiel für eine Datenstruktur: geordnete Tabelle von Matrikelnummern
Aufgabe: Stelle fest, ob eine vorgegebene Nummer enthalten ist? (z.B. 170567)
anderer Algorithmus: Suche weiter in der passenden Hälfte des zuletzt betrachteten Bereichs.
1: 138749 2: 141013 3: 141082 4: 141092 5: 141322 6: 145461 7: 145532 8: 145671
9: 145981 10: 145982 11: 145990 12: 148273 13: 148285 14: 148321 15: 148451 16: 148469
17: 149020 18: 149021 19: 149114 20: 149145 21: 149203 22: 149341 23: 149415 24: 149441
25: 149709 26: 150106 27: 151445 28: 151491 29: 151807 30: 153771 31: 153901 32: 154122
33: 154136 34: 154209 35: 155241 36: 155351 37: 155414 38: 155701 39: 156106 40: 156109
41: 156200 42: 156234 43: 156521 44: 156760 45: 159304 46: 159346 47: 159471 48: 159564
49: 159573 50: 159580 51: 160224 52: 160227 53: 160306 54: 160412 55: 160423 56: 164127
57: 164130 58: 165291 59: 165296 60: 165304 61: 165902 62: 165936 63: 165939 64: 165967
65: 170412 66: 170567 67: 170581 68: 171040 69: 172231 70: 172265 71: 172351 72: 172396
73: 172457 74: 172471 75: 173100 76: 173204 77: 173217 78: 173244 79: 173501 80: 173785
Folie-21
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen und Algorithmen (Fortsetzung)
2. Beispiel für eine Datenstruktur: geordnete Tabelle von Matrikelnummern
Aufgabe: Stelle fest, ob eine vorgegebene Nummer enthalten ist? (z.B. 170567)
anderer Algorithmus: Suche weiter in der passenden Hälfte des zuletzt betrachteten Bereichs.
1: 138749 2: 141013 3: 141082 4: 141092 5: 141322 6: 145461 7: 145532 8: 145671
9: 145981 10: 145982 11: 145990 12: 148273 13: 148285 14: 148321 15: 148451 16: 148469
17: 149020 18: 149021 19: 149114 20: 149145 21: 149203 22: 149341 23: 149415 24: 149441
25: 149709 26: 150106 27: 151445 28: 151491 29: 151807 30: 153771 31: 153901 32: 154122
33: 154136 34: 154209 35: 155241 36: 155351 37: 155414 38: 155701 39: 156106 40: 156109
41: 156200 42: 156234 43: 156521 44: 156760 45: 159304 46: 159346 47: 159471 48: 159564
49: 159573 50: 159580 51: 160224 52: 160227 53: 160306 54: 160412 55: 160423 56: 164127
57: 164130 58: 165291 59: 165296 60: 165304 61: 165902 62: 165936 63: 165939 64: 165967
65: 170412 66: 170567 67: 170581 68: 171040 69: 172231 70: 172265 71: 172351 72: 172396
73: 172457 74: 172471 75: 173100 76: 173204 77: 173217 78: 173244 79: 173501 80: 173785
Folie-22
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen und Algorithmen (Fortsetzung)
2. Beispiel für eine Datenstruktur: geordnete Tabelle von Matrikelnummern
Aufgabe: Stelle fest, ob eine vorgegebene Nummer enthalten ist? (z.B. 170567)
anderer Algorithmus: Suche weiter in der passenden Hälfte des zuletzt betrachteten Bereichs.
1: 138749 2: 141013 3: 141082 4: 141092 5: 141322 6: 145461 7: 145532 8: 145671
9: 145981 10: 145982 11: 145990 12: 148273 13: 148285 14: 148321 15: 148451 16: 148469
17: 149020 18: 149021 19: 149114 20: 149145 21: 149203 22: 149341 23: 149415 24: 149441
25: 149709 26: 150106 27: 151445 28: 151491 29: 151807 30: 153771 31: 153901 32: 154122
33: 154136 34: 154209 35: 155241 36: 155351 37: 155414 38: 155701 39: 156106 40: 156109
41: 156200 42: 156234 43: 156521 44: 156760 45: 159304 46: 159346 47: 159471 48: 159564
49: 159573 50: 159580 51: 160224 52: 160227 53: 160306 54: 160412 55: 160423 56: 164127
57: 164130 58: 165291 59: 165296 60: 165304 61: 165902 62: 165936 63: 165939 64: 165967
65: 170412 66: 170567 67: 170581 68: 171040 69: 172231 70: 172265 71: 172351 72: 172396
73: 172457 74: 172471 75: 173100 76: 173204 77: 173217 78: 173244 79: 173501 80: 173785
Folie-23
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen und Algorithmen (Fortsetzung)
erste Erkenntnisse:
Die Gestaltung von Datenstrukturen und Algorithmen hängt zusammen.
Die Gestaltung von Datenstrukturen und Algorithmen hat nichts mit Programmieren zu tun.
Der zweite Algorithmus heißt binäre Suche, da der zu durchsuchende Bereich in jedem Schritt
halbiert wird, also in zwei Teile zerlegt wird.
Hat eine Datenstruktur bestimmte Eigenschaften, können Algorithmen diese nutzen.
Im Beispiel:
Die binäre Suche nutzt die vorhandene Sortierung,
um schneller zu einem Ergebnis zu kommen:
– Es werden nur 4 Vergleiche bis zum Finden benötigt.
– Die sequentielle Suche erfordert demgegenüber 66 Vergleiche.
Allerdings hat die Sortierung Aufwand beim Erstellen der Datenstruktur verursacht.
Bei der Konzeption von Datenstrukturen und darauf arbeitenden Algorithmen muss daher der
Gesamtaufwand betrachtet werden.
Die binäre Suche setzt zudem voraus:
– eine Möglichkeit zum Berechnen der gewünschten Position und
– den unmittelbaren Zugriff auf den Wert an einer Position.
Folie-24
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen und Algorithmen (Fortsetzung)
Algorithmus: Binäre Suche
gegeben sind
– eine sortierte Liste von Einträgen
– der zu suchende Wert wsuche
bestimme den Wert wmitte des Eintrags an der mittleren Position
vergleiche wsuche mit wmitte
– falls wsuche = wmitte: wsuche kommt in der Liste vor
– falls wsuche > wmitte: wende das Vorgehen auf die Hälfte mit den größeren Werten an
– falls wsuche < wmitte: wende das Vorgehen auf die Hälfte mit den kleineren Werten an
wende das Vorgehen so oft an, bis
– wsuche gefunden worden ist oder
– die zu betrachtende Hälfte keine Einträge enthält: wsuche kommt nicht in der Liste vor
Folie-25
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen und Algorithmen (Fortsetzung)
Algorithmus: Binäre Suche – Analyse
Wie viele Vergleiche sind höchstens notwendig?
entspricht: Wie häufig können Hälften wieder halbiert werden?
Annahme: Es liegen n Werte vor.
Fragestellung: Wie häufig kann n durch 2 dividiert werden, bis das Ergebnis 1 ist.
entspricht: Wie oft muss 2 mit sich selbst multipliziert werden,
bis n erreicht ist.
entspricht: 2x = n, also x = log2(n)
Beispiel: Es liegen 1.000.000 Werte vor,
dann ist log2(1.000.000) 20.
Es werden maximal 21 Vergleiche benötigt, um festzustellen,
ob ein gesuchter Wert vorkommt.
Zum Vergleich: Bei der sequentiellen Suche mit dem Ansehen aller Werte
werden maximal n = 1.000.000 Vergleiche benötigt.
Folie-26
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen und Algorithmen (Fortsetzung)
Die Betrachtung von Datenstrukturen und Algorithmen
ist ein zentraler Bestandteil der Informatik.
aber:
Der Ablauf der binären Suche ist verbal etwas kompliziert zu beschreiben
(und auf den vorangehenden Folien auch immer noch ungenau beschrieben).
Hier wird eine geeignete Notation zur Beschreibung von Algorithmen benötigt:
Programmiersprache
Folie-27
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Aufgaben von Programmiersprachen
Hilfsmittel für die Kommunikation zwischen Mensch und Rechner
für Menschen
mit vernünftigem Aufwand erlernbar
nach Lernphase leicht lesbar und schreibbar
erlaubt es, vollständige und präzise Handlungsanweisungen zu formulieren
für Rechner
ausführbar mit einer definierten Bedeutung
ausführbar mit ökonomisch vertretbarem Aufwand
Folie-28
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Einsatz von Programmiersprachen
Compiler
ist selbst ein Programm, das auf einem Rechner ausgeführt wird,
einen Text in einer Programmiersprache als Eingabe nimmt und
einen Text in Maschinensprache als Ausgabe erzeugt,
der auf Rechnern ausgeführt werden kann.
Problem: Für eine Programmiersprache wird
für jede Maschinensprache
ein eigener Compiler benötigt.
Compiler
Programmiersprache Maschinensprache
(Übersetzer)
Folie-29
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Einsatz der Programmiersprache Java
Java-Compiler: javac, ist Teil des Java Development Kit (JDK)
erzeugt Datei mit Bytecode-Programm,
das von der Virtuellen Maschine (java) ausgeführt wird,
die Teil der Java Runtime Environment (JRE) ist.
Vorteil: Bytecode-Programm ist auf jedem Rechner ausführbar,
für den es eine Virtuelle Maschine gibt.
Voraussetzung: Virtuelle Maschine darf nur wenige Anforderungen stellen,
um auf vielen Rechnern realisiert werden zu können.
javac
.java-Datei .class-Datei
java
Folie-30
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Einsatz der Programmiersprache Java (Fortsetzung)
Eine Programmierumgebung (Integrated Development Environment, IDE)
ermöglicht das
Eingeben, Übersetzen und Ausführen von Java-Programmen.
professionelle Programmierumgebungen:
Netbeans, Eclipse
einfache Programmierumgebungen für Java:
BlueJ, DrJava
Programmierumgebung
javac
.java-Datei
java
.class-Datei
Folie-31
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Einsatz der Programmiersprache Java (Fortsetzung)
DAP 1 ist eine Lehrveranstaltung:
Es interessiert nur die Entwicklung,
nicht die Nutzung oder Verteilung
der entwickelten Programme.
BlueJ
Folie-32
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Grammatik
Grammatik (im allgemeinen Sprachgebrauch)
ist die systematische Beschreibung der Syntax einer Sprache,
also der Konstruktionsvorschriften für die zur Sprache gehörenden Zeichenfolgen.
Grammatik (Formalismus in der Informatik):
G = (, N, P, s)
mit
einem Alphabet (Menge der Terminalsymbole),
einer Menge N von Nichtterminalsymbolen,
einer Menge P von Produktionsregeln,
einem Startsymbol s N.
Folie-33
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Grammatik (Fortsetzung)
G = (, N, P, s)
Eine Produktionsregel p P ersetzt genau ein Nichtterminalsymbol n N
durch eine Folge von Zeichen aus N. *)
Ein von G erzeugtes Wort w ist eine Folge von Terminalsymbolen, die
ausgehend vom Startsymbol s durch
das wiederholte Anwenden von Produktionsregeln abgeleitet werden kann.
Die von G erzeugte Sprache L(G) ist die Menge aller Wörter,
die von G erzeugt werden können.
G dient dazu, die große – meist unendliche – Menge der Wörter einer Sprache L(G)
durch die deutlich kleineren Mengen , N und P zu beschreiben.
*) Anmerkung: Durch diese Definition wird G zu einer kontextfreien Grammatik.
Folie-34
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Grammatik (Fortsetzung)
G = (, N, P, s)
Notation, um Produktionsregeln anzugeben: Syntaxdiagramm
Subjekt Nichtterminalsymbol
Terminalsymbol!
erlaubte Folge von Symbolen
Folie-35
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Grammatik (Fortsetzung)
Beispiel 1:
G1 = (1, N1, P1, s1)
mit 1 = { Anna, Bob, Chelsea, kauft, trifft, ! }
N1 = { Aussage, Name, Aktion }
s1 = Aussage
P1 siehe Diagramme auf den folgenden Folien
Folie-36
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Grammatik (Fortsetzung)
Beispiel 1: Produktionsregeln
Bob
Name
Anna
Chelsea
Folie-37
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Grammatik (Fortsetzung)
Beispiel 1: Produktionsregeln
Bob
Name
Anna
Chelsea
trifft
Aktion
kauft
Folie-38
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Grammatik (Fortsetzung)
Beispiel 1: Produktionsregeln
Name !
Aussage
Aktion Name
Bob
Name
Anna
Chelsea
trifft
Aktion
kauft
Folie-39
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Grammatik (Fortsetzung)
Beispiel 1: Produktionsregeln
einige Wörter der von dieser Grammatik erzeugten Sprache sind:
Anna kauft Bob! Bob kauft Chelsea! Bob trifft Bob! Chelsea kauft Chelsea!
Anna kauft Anna! Bob trifft Chelsea! Bob kauft Anna! Anna kauft Chelsea!
Name !
Aussage
Aktion Name
trifft
Aktion
kauft
Bob
Name
Anna
Chelsea
Folie-40
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Grammatik (Fortsetzung)
Eine Grammatik macht Aussagen zum Aufbau der Wörter der von ihr
erzeugten Sprache: Syntax der Sprache
Eine Grammatik macht keine Aussagen zur Bedeutung der erzeugten Wörter:
Semantik der Sprache
Ein syntaktisch korrektes Wort hat nicht immer eine Bedeutung.
Die Semantik eines Wortes erschließt sich häufig erst durch den Kontext:
– Bob kauft Bob!
hat dann eine sinnvolle Semantik, falls Bob ein Mensch und Bob ein Sportgerät ist.
– Bob kauft Anna!
hat dann eine sinnvolle Semantik, falls Bob ein Mensch und Anna ein Wellensittich ist.
– Bob kauft Chelsea!
hat keine sinnvolle Semantik, falls Bob ein Sportgerät ist.
Wird ein syntaktisch korrektes Wort in einem semantisch falschen Kontext verwendet, so kann
ihm keine Bedeutung zugeordnet werden.
Ein Wort ist syntaktisch falsch, wenn es nicht durch die Grammatik erzeugt werden kann:
Bob Anna trifft trifft
Ein syntaktisch falsches Wort hat keine Semantik.
Folie-41
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Grammatik (Fortsetzung)
Beispiel 2:
G2 = (2, N2, P2, s2)
mit 2 = { vor!, langsam, stopp, - }
N2 = { Einparken, Antreiben, Abbremsen }
s2 = Einparken
P2 siehe Diagramme auf den folgenden Folien
Folie-42
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Grammatik (Fortsetzung)
Beispiel 2: Produktionsregeln
Antreiben
Einparken
Abbremsen
vor!
Antreiben
-
Abbremsen
stopp
langsam
Folie-43
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Grammatik (Fortsetzung)
Beispiel 2: Produktionsregeln
mögliche Wörter der von dieser Grammatik erzeugten Sprache sind:
vor! - stopp vor! vor! vor! - stopp
vor! - langsam stopp vor! vor! - langsam langsam stopp
vor! - langsam langsam langsam stopp
Antreiben Abbremsen-
Einparken
vor!
Antreiben
Abbremsen
stopp
langsam
Folie-44
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Grammatik (Fortsetzung)
Beispiel 3:
Gesucht wird eine Grammatik G3 = (3, N3, P3, s3)
für folgende informelle Beschreibung der gültigen Wörter:
– Ein Ausdruck darf die folgenden Zeichen enthalten: x y +
– In einem Ausdruck dürfen die Zeichen beliebig häufig auftreten.
– Das Zeichen + darf nicht am Anfang eines Ausdrucks stehen.
– Auf das Zeichen + muss immer unmittelbar das Zeichen x folgen.
Folie-45
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Grammatik (Fortsetzung)
Beispiel 3:
Gesucht wird eine Grammatik G3 = (3, N3, P3, s3)
für folgende informelle Beschreibung der gültigen Wörter:
– Ein Ausdruck darf die folgenden Zeichen enthalten: x y +
– In einem Ausdruck dürfen die Zeichen beliebig häufig auftreten.
– Das Zeichen + darf nicht am Anfang eines Ausdrucks stehen.
– Auf das Zeichen + muss immer unmittelbar das Zeichen x folgen.
3 = { x, y, + }
Folie-46
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Grammatik (Fortsetzung)
Beispiel 3:
Gesucht wird eine Grammatik G3 = (3, N3, P3, s3)
für folgende informelle Beschreibung der gültigen Wörter:
– Ein Ausdruck darf die folgenden Zeichen enthalten: x y +
– In einem Ausdruck dürfen die Zeichen beliebig häufig auftreten.
– Das Zeichen + darf nicht am Anfang eines Ausdrucks stehen.
– Auf das Zeichen + muss immer unmittelbar das Zeichen x folgen.
3 = { x, y, + }
P3 x
yAusdruck
Folie-47
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Grammatik (Fortsetzung)
Beispiel 3:
Gesucht wird eine Grammatik G3 = (3, N3, P3, s3)
für folgende informelle Beschreibung der gültigen Wörter:
– Ein Ausdruck darf die folgenden Zeichen enthalten: x y +
– In einem Ausdruck dürfen die Zeichen beliebig häufig auftreten.
– Das Zeichen + darf nicht am Anfang eines Ausdrucks stehen.
– Auf das Zeichen + muss immer unmittelbar das Zeichen x folgen.
3 = { x, y, + }
P3 x
yAusdruck
Folie-48
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Grammatik (Fortsetzung)
Beispiel 3:
Gesucht wird eine Grammatik G3 = (3, N3, P3, s3)
für folgende informelle Beschreibung der gültigen Wörter:
– Ein Ausdruck darf die folgenden Zeichen enthalten: x y +
– In einem Ausdruck dürfen die Zeichen beliebig häufig auftreten.
– Das Zeichen + darf nicht am Anfang eines Ausdrucks stehen.
– Auf das Zeichen + muss immer unmittelbar das Zeichen x folgen.
3 = { x, y, + }
P3 +x
yAusdruck
Folie-49
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Grammatik (Fortsetzung)
Beispiel 3:
Gesucht wird eine Grammatik G3 = (3, N3, P3, s3)
für folgende informelle Beschreibung der gültigen Wörter:
– Ein Ausdruck darf die folgenden Zeichen enthalten: x y +
– In einem Ausdruck dürfen die Zeichen beliebig häufig auftreten.
– Das Zeichen + darf nicht am Anfang eines Ausdrucks stehen.
– Auf das Zeichen + muss immer unmittelbar das Zeichen x folgen.
3 = { x, y, + }
N3 = { Ausdruck }
s3 = Ausdruck
P3 +x
yAusdruck
Folie-50
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Grammatik (Fortsetzung)
Syntaxdiagramme werden in dieser Vorlesung dazu benutzt,
um den Aufbau der Konstrukte von Java zu verdeutlichen.
Die Syntax eines Programms wird immer vom Compiler überprüft,
wenn das Programm übersetzt wird.
Die Semantik der Konstrukte von Java wird in dieser Vorlesung informell anhand von
Beispielprogrammen beschrieben.
Die Semantik von Programmen kann der Compiler nur sehr eingeschränkt prüfen:
– Falls der Compiler Bob und Anna als Menschen kennt,
dann kann er für Bob kauft Anna! einen semantischen Fehler melden.
– Falls der Compiler kein Wissen zu Bob und Anna hat, wird er
Bob kauft Anna! auch dann akzeptieren,
wenn es sich um einen Fehler des Entwicklers handelt.
Folie-51
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein erstes Beispiel
public class FirstProgram
{
public static void main( String[] args )
{
System.out.println( "hello world" );
}
}
Dieses Programm tut sehr wenig:
Wird es ausgeführt, zeigt es den Text hello world auf dem Bildschirm an:
hello world
Um das zu erreichen, werden allerdings schon ziemlich viele Konzepte von Java benötigt.
Folie-52
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein erstes Beispiel (Fortsetzung)
public class FirstProgram
{
public static void main( String[] args )
{
System.out.println( "hello world" );
}
}
"hello world" ist ein Text-Literal:
eine explizit angegebene Folge von Zeichen.
Zwischen "..." können fast beliebige Zeichen stehen, die zusammen den Text bilden.
aber: "..." muss in einer Zeile stehen.
Text-Literal
Folie-53
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein erstes Beispiel (Fortsetzung)
public class FirstProgram
{
public static void main( String[] args )
{
System.out.println( "hello world" );
}
}
System.out.println ist eine Operation, die den Text auf dem Bildschirm anzeigt.
In Java wird eine solche Operation als Methode bezeichnet.
In ( ... ) eingeschlossen ist ein Argument, mit dem die Methode arbeitet.
In diesem Beispiel ist das Argument der Text hello World,
der als Text-Literal angegeben wird.
System.out.println ist eine Methode, die Java bereits kennt.
Folie-54
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein erstes Beispiel (Fortsetzung)
public class FirstProgram
{
public static void main( String[] args )
{
System.out.println( "hello world" );
}
}
Terminologie:
– "Das Argument wird übergeben." Voraussetzung für Ausführung
– "Die Methode wird ausgeführt." Vorgang des Abarbeitens der Methode
– "Die Methode wird aufgerufen." Der Programmtext sieht das Ausführen der
Methode vor.
Aufruf einer Methode
Folie-55
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein erstes Beispiel (Fortsetzung)
public class FirstProgram
{
public static void main( String[] args )
{
System.out.println( "hello world" );
}
}
Eine Anweisung ist ein einzeln ausführbarer Arbeitsschritt.
Eine Anweisung endet (meist) mit dem Zeichen ;
Eine Anweisung steht immer in einer Methode, die Arbeitsschritte zusammenfasst.
Hier besteht die Anweisung aus genau dem Aufruf einer Methode.
Anweisung
Folie-56
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein erstes Beispiel (Fortsetzung)
public class FirstProgram
{
public static void main( String[] args )
{
System.out.println( "hello world" );
}
}
main ist eine Methode mit Parameter args, die an dieser Stelle deklariert wird.
Der Name main besitzt in Java eine besondere Bedeutung:
Mit dieser Methode startet die Ausführung eines Programms.
Die Deklaration einer Methode besteht aus der Angabe eines Methodenkopfs und
eines Methodenrumpfs in {...}
Die Wörter public static void werden von Java vorgegeben (Terminalsymbole).
Ihre Bedeutung kann hier noch nicht erklärt werden.
bilden zusammen:
Methodenkopf
Methodenrumpf
Deklaration einer Methode
Folie-57
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein erstes Beispiel (Fortsetzung)
public class FirstProgram
{
public static void main( String[] args )
{
System.out.println( "hello world" );
}
}
FirstProgram ist eine Klasse.
Die Deklaration einer Klasse besteht besteht aus der Angabe eines Klassenkopfs und
eines Klassenrumpfs in {...}.
Öffentliche Klassen (public) sind eigenständige Programmeinheiten, die in einer Datei mit
gleichem Namen gespeichert werden müssen: FirstProgram.java
Klassen enthalten Deklarationen von Methoden,
sind also eine Sammlung von Deklarationen ausführbarer Einheiten.
bilden zusammen:
Klassenkopf
Klassenrumpf
Deklaration einer Klasse
Folie-58
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein erstes Beispiel (Fortsetzung)
/*
* author Stefan Dissmann
* version 1.0
*/
public class FirstProgram
{
public static void main( String[] args )
{
// show one line
System.out.println( "hello world" );
}
}
Kommentare verbessern die Verständlichkeit des Programms für die Entwickler oder
enthalten zusätzliche Informationen für die Entwickler.
Anmerkung: Auch das strukturierte Einrücken der verschiedenen Bestandteile des
Programms dient der Verbesserung der Lesbarkeit.
Folie-59
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein erstes Beispiel (Fortsetzung)
/*
* author Stefan Dissmann
* version 1.0
*/
public class FirstProgram
{
public static void main( String[] args )
{
// show one line
System.out.println( "hello world" );
}
}
Ein Kommentar hat keine Bedeutung für die Übersetzung und Ausführung des Programms.
/*...*/ -Kommentar kann sich über mehrere Zeilen erstrecken.
// -Kommentar endet immer am Zeilenende.
Kommentare
Folie-60
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein erstes Beispiel (Fortsetzung)
public class FirstProgram{public static void main(String[]args){
System.out.println("hello world");}}
Anmerkungen:
Leerzeichen, Zeilenumbrüche und Kommentare dienen – mit wenigen Ausnahmen –
nur zur Verbesserung der Lesbarkeit für die Entwickler.
Leerzeichen sind aber notwendig, um Wörter zu trennen:
public class ist nicht publicclass
Einzelne Zeichen mit besonderer Bedeutung müssen nicht durch Leerzeichen abgeteilt
werden:
);}} oder FirstProgram{public sind syntaktisch korrekt.
Statt eines Leerzeichens können fast überall auch mehrere Leerzeichen eingesetzt werden,
um beispielsweise sichtbare Einrückungen zu erzeugen
Die Lesbarkeit ist wichtig für die menschlichen Entwickler, nicht für den Compiler.
Die Ausgabe bleibt unverändert.
Folie-61
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein erstes Beispiel (Fortsetzung)
public class FirstProgram
{
public static void main( String[] args )
{
System.out.println( "hello world" );
}
}
Ausführen des Programms durch einen Rechner bedeutet, dass die Methode main ausgeführt wird.
Dabei passiert Folgendes:
System.out.println
main
Ausgabe auf dem Bildschirm
Folie-62
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein zweites Beispiel
public class SecondProgram
{
public static int average( int value1, int value2 )
{
return (value1 + value2) / 2;
}
}
Folie-63
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein zweites Beispiel (Fortsetzung)
public class SecondProgram
{
public static int average( int value1, int value2 )
{
return (value1 + value2) / 2;
}
}
average ist eine Methode, die in der Klasse SecondProgram deklariert wird.
average ist ein vom Entwickler gewählter Name.
average hat zwei Parameter value1 und value2 mit selbst gewählten Namen.
Ein Parameter dient beim Aufruf der Methode dazu, ein Argument zu übernehmen.
Der Wert des Arguments wird dann innerhalb der Methode über den Parameter bereitgestellt.
average berechnet einen Wert und stellt diesen im Programm bereit.
Methode
Folie-64
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein zweites Beispiel (Fortsetzung)
public class SecondProgram
{
public static int average( int value1, int value2 )
{
return (value1 + value2) / 2;
}
}
int (für integer) bezeichnet einen Teilbereich der ganzen Zahlen:
–2 147 483 648 ... 2 147 483 647
int ist die Angabe eines Wertebereichs und wird als Typ bezeichnet
int schränkt die möglichen Werte ein, die bei der Bearbeitung von average auftreten:
– die Werte der beim Aufruf an die Parameter übergebenen Argumente
– den Wert, der nach der Ausführung der Methode zurückgegeben wird
Typ des zurückgegebenen Wertes
Typen der Parameter
Folie-65
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein zweites Beispiel (Fortsetzung)
public class SecondProgram
{
public static int average( int value1, int value2 )
{
return (value1 + value2) / 2;
}
}
Die return-Anweisung bestimmt, welcher Wert beim Aufruf der Methode average
zurückgegeben werden soll.
Zurückgeben eines Wertes
Anweisung:
Typ des zurückgegebenen Wertes
Folie-66
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein zweites Beispiel (Fortsetzung)
public class SecondProgram
{
public static int average( int value1, int value2 )
{
return (value1 + value2) / 2;
}
}
(value1 + value2) / 2 ist ein mathematischer Ausdruck der eine int-Zahl berechnet:
+ ist die ganzzahlige Addition, / ist die ganzzahlige Division.
Die Klammern ( ... ) bestimmen die Auswertungsreihenfolge,
ohne Klammerung gilt Punkt- vor Strichrechnung.
2 ist ein Literal des Typs int mit dem Wert 2 (trivial).
Zurückgeben eines Wertes
int-Literal
Ausdruck
Folie-67
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein zweites Beispiel (Fortsetzung)
public class SecondProgram
{
public static void main( String[] args )
{
System.out.println( "average of 15 and 20: " + average( 15, 20 ) );
}
public static int average( int value1, int value2 )
{
return (value1 + value2) / 2;
}
}
main ist die Methode in der Klasse SecondProgram, mit der die Ausführung des zweiten
Programms beginnt.
String[] args ist der Parameter der Methode main.
Die Bedeutung kann hier noch nicht erklärt werden.
Folie-68
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein zweites Beispiel (Fortsetzung)
public class SecondProgram
{
public static void main( String[] args )
{
System.out.println( "average of 15 and 20: " + average( 15, 20 ) );
}
public static int average( int value1, int value2 )
{
return (value1 + value2) / 2;
}
}
void (deutsch "leer") kennzeichnet eine Methode, die keinen Wert zurückgibt.
Die nicht benötigte Typangabe wird durch void ersetzt.
Eine durch void gekennzeichnete Methode muss keine return-Anweisung
enthalten.
Eine Methode, die wie die Methode average einen Wert zurückgibt,
muss immer (mindestens) eine return-Anweisung enthalten.
Typ des zurückgegebenen Wertes
Folie-69
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein zweites Beispiel (Fortsetzung)
public class SecondProgram
{
public static void main( String[] args )
{
System.out.println( "average of 15 and 20: " + average( 15, 20 ) );
}
public static int average( int value1, int value2 )
{
return (value1 + value2) / 2;
}
}
"average of 15 and 20: " + average( 15, 20 ) ist ein Ausdruck,
der einen Text festlegt.
Ausdruck
Folie-70
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein zweites Beispiel (Fortsetzung)
public class SecondProgram
{
public static void main( String[] args )
{
System.out.println( "average of 15 and 20: " + average( 15, 20 ) );
}
public static int average( int value1, int value2 )
{
return (value1 + value2) / 2;
}
}
average( 15, 20 ) ist ein Aufruf der Methode average,
bei dem die Werte 15 und 20 als Argumente übergeben werden.
Da / die ganzzahlige Division ist, liefert average( 15, 20 ) als Ergebnis 17.
+ ist an dieser Stelle die Konkatenation (Verkettung) von zwei Texten,
das Ergebnis des Aufrufs von average wird implizit von int in Text umgewandelt.
System.out.println( "average of 15 and 20: " + average( 15, 20 ) )
ist also der Aufruf von System.out.println
mit dem Argument "average of 15 and 20: 17"
Aufruf Konkatenation
Folie-71
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein zweites Beispiel (Fortsetzung)
public class SecondProgram
{
public static void main( String[] args )
{
System.out.println( "average of 15 and 20: " + average( 15, 20 ) );
}
public static int average( int value1, int value2 )
{
return (value1 + value2) / 2;
}
}
Die Vorgabe in der Deklaration der Methode heißt: Parameter
Der übergebene Wert beim Aufruf der Methode heißt: Argument
Während der Ausführung nehmen die Parameter die Werte der Argumente an:
value1 erhält den Wert 15, value2 erhält den Wert 20.
Argumente können auch unmittelbar für die Übergabe berechnet werden:
average( 15, 20 ) für Aufruf von System.out.println.
Argumente
Parameter
Folie-72
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein zweites Beispiel (Fortsetzung)
public class SecondProgram
{
public static void main( String[] args )
{
System.out.println( "average of 15 and 20: " + average( 15, 20 ) );
}
public static int average( int value1, int value2 )
{
return (value1 + value2) / 2;
}
}
Ausführung:
System.out.println
main
Ausgabe auf dem Bildschirm
average
Berechnung
Folie-73
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein drittes Beispiel
public class ThirdProgram
{
public static void main( String[] args )
{
System.out.println( "average of 15 and 5: " + average( 15, five() ) );
}
public static int average( int value1, int value2 )
{
return (value1 + value2) / 2;
}
public static int five()
{
return 5;
}
}
Folie-74
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein drittes Beispiel (Fortsetzung)
public class ThirdProgram
{
public static void main( String[] args )
{
System.out.println( "average of 15 and 5: " + average( 15, five() ) );
}
public static int average( int value1, int value2 )
{
return (value1 + value2) / 2;
}
public static int five()
{
return 5;
}
}
five() ist eine Methode ohne Parameter, die immer nur den Wert 5 zurückgibt:
() sind bei der Deklaration und beim Aufruf der Methode five notwendig!
average( 15, five() )
Die Berechnung von Argumenten kann beliebig geschachtelt werden.
Aufruf ohne Argument
Deklaration ohne Parameter
Folie-75
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Programmiersprache Java – ein drittes Beispiel (Fortsetzung)
public class ThirdProgram
{
public static void main( String[] args )
{
System.out.println( "average of 15 and 5: " + average( 15, five() ) );
}
...
}
Ausführung:
System.out.println
main
Ausgabe auf dem Bildschirm
average
Berechnung
five
Rückgabe von 5
Folie-76
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zusammenfassung (Folie 51 bis Folie 74)
Eine Klasse bildet die äußere strukturelle Einheit eines Java-Programms.
Eine Methode ist eine Folge von Handlungsschritten (Anweisungen),
die unter einem Namen zusammengefasst werden.
Methoden werden innerhalb von Klassen deklariert.
Es gibt besondere Methoden, z.B.: main, System.out.println
Eine Methode kann Parameter besitzen, die im Methodenkopf deklariert werden.
Eine Methode kann einen Rückgabewert liefern, dessen Typ im Methodenkopf
deklariert wird.
Eine Methode kann aufgerufen und ausgeführt werden:
Dann werden Werte als Argumente an die Parameter übergeben
und der Rückgabewert wird berechnet.
Eine Anweisung ist ein Handlungsschritt in einer Methode:
– Methodenaufruf
– return-Anweisung
Ein Ausdruck ist eine Berechnung, die einen Wert eines bestimmten Typs liefert.
Ein Typ bezeichnet einen Wertebereich, der die Werte für Argumente und in Ausdrücken
beschränkt.
Folie-77
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Syntaxdiagramm zu Klasse *)
Das Nichtterminalsymbol Bezeichner wird in den Übungen näher betrachtet.
Diese Diagramme werden in späteren Versionen noch erweitert.
*) Ein Teil der Syntaxdiagramme wird im Laufe der Vorlesung weiter ergänzt, so dass jeweils nur die am weitesten hinten
stehende Version die vollständige Beschreibung der Syntax liefert.
Bezeichner {
Klasse
Klassenrumpf
classpublic
}
Methodendeklaration
Klassenrumpf
Folie-78
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Methodendeklaration
Syntaxdiagramm zu Methode
Typ
( Parameterliste
Methodenkopf
)
Methodenrumpf
Methodenkopf Modifiziererliste Bezeichner
void
Folie-79
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Syntaxdiagramm zu Methode (Fortsetzung)
Insbesondere kann eine Parameterliste leer sein, also keine Parameter enthalten.
Das Syntaxdiagramm Methodenkopf erzwingt aber immer die ().
Bisher ist als Typ-Angabe nur das Schlüsselwort int bekannt.
Parameter
Parameterliste
,
Typ Bezeichner
Parameter
Folie-80
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Syntaxdiagramm zu Methode (Fortsetzung)
Für Modifizierer gelten zusätzliche sematische Regeln:
public und private dürfen nicht gemeinsam vorkommen.
Modifizierer
Modifiziererliste
Block
public
static
Modifizierer
Methodenrumpf
Folie-81
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Syntaxdiagramm zu Block
Das Nichtterminal Block wird später auch noch an anderer Stelle der Java-Grammatik
verwendet.
{ Blocksequenz }
Block
Anweisung
Blocksequenz
Folie-82
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Syntaxdiagramm zu Anweisung und return-Anweisung
Eine Anweisung kann auch eine leere Anweisung sein:
Folgen von ;;;; sind erlaubt.
Anweisung
Methodenaufruf
return-Anweisung
return
return-Anweisung
Ausdruck
;
Folie-83
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Syntaxdiagramm zu Methodenaufruf
Da Methoden ohne Parameter deklariert werden können,
erlaubt Argumentliste auch den Aufruf von Methoden ohne Parameter.
Beim Aufruf einer Methode müssen die Anzahl und die Typen der Argumente
immer zu der Parameterliste passen.
Diese Übereinstimmung läßt sich aber nicht durch Produktionsregeln erzwingen.
( Argumentliste )
Methodenaufruf
Ausdruck
Argumentliste
Bezeichner
,
Folie-84
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Syntaxdiagramme
Hinweise:
Einige Nichtterminalsymbole werden hier nicht als Diagramme veranschaulicht,
weil sie
– noch nicht ausreichend anhand von Beispielen eingeführt worden sind,
– selbsterklärend sind oder
– in den Übungen vertieft werden.
Es gibt semantische Abhängigkeiten zwischen Nichtterminalsymbolen,
die sich nicht auf der Ebene der Syntax(-diagramme) darstellen lassen:
– Zu jeder aufgerufenen Methode muss es eine passende Deklaration geben.
– Ein als Argument übergebener Wert muss zum Typ der zugehörigen
Parameterdeklaration passen.
– Der Wert, den der Ausdruck in einer return-Anweisung liefert,
muss zur Typangabe im Kopf der umgebenden Methode passen.
Begriff:
Die Signatur einer Methode sind die zum Aufruf notwendigen Informationen:
der Name der Methode sowie die Anzahl und Folge der Typen der Parameter
Folie-85
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Symbole in Java
bisher kennengelernt:
Schlüsselwörter sind Terminalsymbole, die aus Buchstaben gebildet werden
Beispiele: public int return
Sonderzeichen sind Terminalsymbole, die aus Nicht-Buchstaben gebildet werden
Beispiele: ; { } / // /* */
Anmerkung:
Die korrekte (Klein-)Schreibung ist wichtig bei
Schlüsselwörtern und Sonderzeichen.
Insbesondere dürfen keine Leerzeichen eingeschoben werden.
Folie-86
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Symbole in Java (Fortsetzung)
bisher wurden vorgestellt:
Literale sind meist Nichtterminalsymbole, die als Folge aus einer vorgegebenen Menge von
Terminalsymbolen gebildet werden:
– Literale des Typs int bestehen aus einzelnen Ziffern: 2431
– Literale des Typs String bestehen aus fast beliebigen Zeichen: "Ergebnis"
Bezeichner sind Nichtterminalsymbole, die als Folge aus einer vorgegebene Menge von
Terminalsymbolen gebildet werden:
value1 average FirstProgram
In Java werden Bezeichner üblicherweise folgendermaßen aufgebaut:
– Parameter- und Methodennamen beginnen mit einem Kleinbuchstaben,
– Klassennamen beginnen mit einem Großbuchstaben,
– bei aus mehreren Wörtern zusammengesetzten Namen werden das zweite und
alle folgenden Wörter mit einem Großbuchstaben begonnen (CamelCase).
Anmerkungen:
– Die korrekte (Klein-)Schreibung ist bei Bezeichnern wichtig!
– Schlüsselwörter können nicht als Bezeichner verwendet werden.
Folie-87
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Compiler – Überprüfen von Programmeigenschaften
Überprüfungen
Der Compiler (javac) kennt die Grammatik von Java und überprüft,
ob das zu übersetzende Programm (.java) mit dieser Grammatik erzeugt werden kann.
Der Compiler kennt zusätzliche Eigenschaften, die für Java-Programme gelten müssen,
wie zum Beispiel:
– Aufgerufene Methoden müssen auch deklariert sein.
– Für Methodenaufrufe müssen die Anzahl der deklarierten Parameter
und der übergebenen Argumente übereinstimmen.
– Für Methodenaufrufe müssen die Typen der deklarierten Parameter
und der übergebenen Argumente übereinstimmen.
– Für Operatoren müssen die Typen der Operanden zulässig sein:
5 / 2 ist als Division von zwei int-Werten zulässig, "fuenf" / 2 ist unzulässig.
javac
.java-Datei .class-Datei
java
Folie-88
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Compiler – Überprüfen von Programmeigenschaften (Fortsetzung)
Überprüfungen
Falls der Compiler einen Fehler feststellt,
– wird dem Entwickler eine entsprechende Fehlermeldung angezeigt und
– es wird keine Bytecode-Datei (.class) erzeugt.
Falls der Compiler keinen Fehler feststellt,
wird eine Bytecode-Datei (.class) erzeugt, die ausgeführt werden kann.
javac
.java-Datei .class-Datei
java
Folie-89
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Compiler – Überprüfen von Programmeigenschaften (Fortsetzung)
Überprüfungen
Falls der Compiler einen Fehler feststellt,
– wird dem Entwickler eine entsprechende Fehlermeldung angezeigt und
– es wird keine Bytecode-Datei (.class) erzeugt.
Falls der Compiler keinen Fehler feststellt,
wird eine Bytecode-Datei (.class) erzeugt, die ausgeführt werden kann.
aber:
Der Compiler weiß nicht, welche Funktionalität der Entwickler umsetzen wollte
und welche Werte verarbeitet werden sollen.
javac
.java-Datei .class-Datei
java
Folie-90
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Compiler – Überprüfen von Programmeigenschaften (Fortsetzung)
Aufgabe:
Erstelle eine Methode, die den Wert ihres Parameters verdoppelt
und den berechneten Wert als Ergebnis zurückgibt.
Folie-91
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Compiler – Überprüfen von Programmeigenschaften (Fortsetzung)
Aufgabe:
Erstelle eine Methode, die den Wert ihres Parameters verdoppelt
und den berechneten Wert als Ergebnis zurückgibt.
programmierte Lösung:
public static int doubleValue( int value )
{
return 2 / value;
}
Folie-92
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Compiler – Überprüfen von Programmeigenschaften (Fortsetzung)
Aufgabe:
Erstelle eine Methode, die den Wert ihres Parameters verdoppelt
und den berechneten Wert als Ergebnis zurückgibt.
programmierte Lösung:
public static int doubleValue( int value )
{
return 2 / value;
}
Der Compiler findet keinen Fehler, da die Methode syntaktisch korrekt ist.
Trotzdem ist die Lösung fehlerhaft, da die gestellte Aufgabe nicht gelöst wird.
Folie-93
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Testen durch den Entwickler
javac
.java-Datei .class-Datei
java
Ein Test ist das Ausführen des Programms mit Werten,
um die richtige (oder falsche) Umsetzung der Aufgabe zu erkennen:
Durch einen Test erfolgt eine (partielle) Prüfung der Semantik des Programms.
Folie-94
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Testen durch den Entwickler
Anmerkung:
Auch die Zahl und die Auswahl der zum Testen benutzen Werte ist wichtig:
doubleValue( 1 ) würde das erwartete Ergebnis 2 liefern.
public static int doubleValue( int value )
{
return 2 / value;
}
javac
.java-Datei .class-Datei
java
Ein Test ist das Ausführen des Programms mit Werten,
um die richtige (oder falsche) Umsetzung der Aufgabe zu erkennen:
Durch einen Test erfolgt eine (partielle) Prüfung der Semantik des Programms.
Folie-95
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Testen durch den Entwickler (Fortsetzung)
Der Aufruf doubleValue( 0 ) erzeugt ein mathematisches Problem:
Die Division durch 0 besitzt kein gültiges Ergebnis in int.
public static int doubleValue( int value )
{
return 2 / value;
}
javac
.java-Datei .class-Datei
java
Ausführen der Methode mit dem Argument 0
Folie-96
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Testen durch den Entwickler (Fortsetzung)
Der Aufruf doubleValue( 0 ) führt zu:
java.lang.ArithmeticException: / by zero
at ClassName.doubleValue(ZeroDivision.java:5)
– Abbruch der Ausführung der Methode doubleValue
– Anzeige
dass eine Ausnahme(-situation) aufgetreten ist: ArithmeticException
welcher Art die Ausnahme ist: / by zero
wo die Ausnahme aufgetreten ist: at ClassName.doubleValue
javac
.java-Datei .class-Datei
java
Ausführen der Methode mit dem Argument 0
Folie-97
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele Einführung
(siehe Folie 5)
Nach Durcharbeiten der Einführung sollen
die teilnehmenden Studierenden
ein erstes Verständnis von dem Begriff Datenstruktur besitzen
ein erstes Verständnis von dem Begriff Algorithmus besitzen
ein Beispiel für die Beziehung zwischen Datenstrukturen und Algorithmen angeben können
den Verarbeitungsablauf bei der Erstellung von Java-Programmen kennen
die Begriffe Syntax und Semantik unterscheiden und zuordnen können
Syntaxdiagramme lesen und entscheiden können,
ob ein Wort zu einer gegebenen Sprache gehört
Syntaxdiagramme für einfache Konstrukte selbst formulieren können
einfache, nur aus einer Klasse bestehende Java-Programme mit ausschließlich statischen
Methoden implementieren, übersetzen und ausführen lassen können
Fehler den Phasen Compilierung oder Ausführung zuordnen können
Folie-98
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen, Algorithmen
und Programmierung 1 (DAP 1)
Fakultät für Informatik
Wintersemester 2019/20
Stefan Dissmann
Einfache Algorithmen
Folie-99
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Einfache Algorithmen
Nach Durcharbeiten des Kapitels Einfache Algorithmen sollen
die teilnehmenden Studierenden
die Typen boolean, int, long, float und double kennen
Operatoren und Ausdrücke kennen und deren Auswertungsreihenfolgen bestimmen können
Variablen deklarieren und initialisieren können
Werte an Variablen zuweisen können
Bedingungen formulieren und auswerten können
bedingte Anweisungen und ihre Verwendung kennen
for- und while-Schleifen und ihre Verwendung kennen
Feld-Variable deklarieren und nutzen können
den Ablauf des Algorithmus zur Primzahlenbestimmung nach Eratosthenes skizzieren und
nachvollziehen können
Folie-100
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate»
Aufgabe:
Berechne die Summe der Quadrate aller natürlichen Zahlen bis zu einer
vorgegebenen Obergrenze n.
oder mathematisch: 12 + 22 + 32 + 42 + ... + n2
Lösungsidee:
berechne das Quadrat einer Zahl
addiere das berechnete Quadrat zu der eventuell schon berechneten Summe von Quadraten
prüfe, ob noch Quadrate berechnet werden müssen: dann gehe zurück
die berechnete Summe ist das Ergebnis
Folie-101
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate» (Fortsetzung)
Aufgabe:
Berechne die Summe der Quadrate aller natürlichen Zahlen bis zu einer
vorgegebenen Obergrenze n.
oder mathematisch: 12 + 22 + 32 + 42 + ... + n2
Lösungsidee «mit etwas mehr Ordnung»:
beginne mit der Zahl 1
berechne das Quadrat der gewählten Zahl
addiere das berechnete Quadrat zu der eventuell schon berechneten Summe von Quadraten
erhöhe den Wert der gewählten Zahl um 1
prüfe, ob n noch nicht überschritten ist: dann gehe zurück
die berechnete Summe ist das Ergebnis
Folie-102
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate» (Fortsetzung)
Aufgabe:
Berechne die Summe der Quadrate aller natürlichen Zahlen bis zu einer
vorgegebenen Obergrenze n.
oder mathematisch: 12 + 22 + 32 + 42 + ... + n2
Lösungsidee mit «Namen» für Werte:
beginne mit der Zahl value = 1
berechne das Quadrat von value
addiere das berechnete Quadrat zu der eventuell schon berechneten
Summe (subtotal) von Quadraten
erhöhe den Wert von value um 1
prüfe, ob value <= n : dann gehe zurück
subtotal ist das Ergebnis
Folie-103
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate» (Fortsetzung)
Aufgabe:
Berechne die Summe der Quadrate aller natürlichen Zahlen bis zu einer
vorgegebenen Obergrenze n.
oder mathematisch: 12 + 22 + 32 + 42 + ... + n2
1. Lösungsansatz:
initialisiere einen Zähler für die natürliche Zahlen value = 1
initialisiere die zu berechnende Zwischensumme subtotal = 0
bestimme die neue Zwischensumme als subtotalneu =
subtotalalt + value*value
erhöhe den Wert von value um 1 valueneu = valuealt + 1
prüfe, ob value <= n : dann gehe zurück
gib subtotal als Ergebnis zurück
Folie-104
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate» (Fortsetzung)
1. Lösungsansatz:
initialisiere einen Zähler für die natürliche Zahlen value = 1
initialisiere die zu berechnende Zwischensumme subtotal = 0
bestimme die neue Zwischensumme als subtotalneu = subtotalalt + value*value
erhöhe den Wert von value um 1 valueneu = valuealt + 1
prüfe, ob value <= n : dann gehe zurück
gib subtotal als Ergebnis zurück
2. Lösungsansatz:
initialisiere einen Zähler für die natürliche Zahlen value = 1
initialisiere die zu berechnende Zwischensumme subtotal = 0
prüfe, ob value <= n: sonst gehe zum Ende
bestimme die neue Zwischensumme subtotalneu =
subtotalalt + value*value
erhöhe den Wert von v um 1 valueneu = valuealt + 1
gehe zurück
gib subtotal als Ergebnis zurück
Folie-105
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate» (Fortsetzung)
1. Implementierung
public static int sumOfSquares( int n )
{
int value = 1;
int subtotal = 0;
while ( value <= n )
{
subtotal = subtotal + value * value;
value = value + 1;
}
return subtotal;
}
Folie-106
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate» (Fortsetzung)
1. Implementierung
public static int sumOfSquares( int n )
{
int value = 1;
int subtotal = 0;
while ( value <= n )
{
subtotal = subtotal + value * value;
value = value + 1;
}
return subtotal;
}
Eine Variable speichert einen Wert des bei ihrer Deklaration vorgegeben Typs:
– int value deklariert die Variable value, die int-Werte speichern kann
– int subtotal deklariert die Variable subtotal, die ebenfalls int-Werte speichern kann
Deklaration
Folie-107
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate» (Fortsetzung)
1. Implementierung
public static int sumOfSquares( int n )
{
int value = 1;
int subtotal = 0;
while ( value <= n )
{
subtotal = subtotal + value * value;
value = value + 1;
}
return subtotal;
}
Eine Variable kann bei ihrer Deklaration mit einem Wert initialisiert werden:
– int value = 1 initialisiert die Variable value mit dem (zulässigen) Wert 1
– int subtotal = 0 initialisiert die Variable subtotal mit dem (zulässigen) Wert 0
Initialisierung
Folie-108
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate» (Fortsetzung)
1. Implementierung
public static int sumOfSquares( int n )
{
int value = 1;
int subtotal = 0;
while ( value <= n )
{
subtotal = subtotal + value * value;
value = value + 1;
}
return subtotal;
}
Auf eine Variable kann über ihren Namen zugegriffen werden:
So kann ihr sowohl ein Wert zugewiesen werden als auch ihr Wert abgerufen werden.
Einer Variablen kann während der Ausführung ein neuer Wert zugewiesen werden,
eine Zuweisung = erfolgt immer von rechts nach links:
Daher erhöht value = value + 1 den Wert von value um 1.
Zugriff
Zuweisung
Folie-109
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate» (Fortsetzung)
1. Implementierung
public static int sumOfSquares( int n )
{
int value = 1;
int subtotal = 0;
while ( value <= n )
{
subtotal = subtotal + value * value;
value = value + 1;
}
return subtotal;
}
Ein Block wird immer durch {...} eingeschlossen.
Ein Block begrenzt den Bereich, in dem deklarierte Variablen bekannt sind.
Ein Block fasst Anweisungen zusammen, die gemeinsam behandelt werden.
Blöcke können geschachtelt werden.
Block} Block
Folie-110
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate» (Fortsetzung)
1. Implementierung
Anmerkungen zu Variablen:
Eine Variable muss vor ihrer Nutzung (Zugriff) deklariert werden.
Eine Variable ist nur innerhalb des Blocks bekannt, in dem sie deklariert ist.
Eine Variable ist auch in tiefer geschachtelten Blöcken bekannt.
In einem Block darf es keine zwei Variablen mit gleichem Namen geben.
Insbesondere darf zwischen umgebenden und inneren Blöcken kein Konflikt auftreten.
Deklarationen von Variablen des gleichen Typs können zusammengefasst werden.
Beispiele:
int v1, v2, v3;
int v4, v5 = 2, v6;
int value = 0, subtotal = 0;
Anmerkung:
Ein Parameter kann als eine Variable betrachtet werden, die
– im Block der Methode bekannt ist und
– beim Aufruf der Methode den Wert des Arguments zugewiesen bekommt.
Folie-111
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung "Summe der Quadrate" (Fortsetzung)
1. Implementierung
Anmerkungen zu Initialisierung und Zuweisung:
Initialisierung und Zuweisung sind unterschiedliche Konzepte. *)
Eine Variable ohne Initialisierung besitzt zunächst keinen Wert.
Auf eine Variable ohne Wert darf nicht zugegriffen werden.
Ihr kann aber ein Wert zugewiesen werden.
Eine Zuweisung ist eine Anweisung, bei der zunächst der Ausdruck rechts von =
ausgewertet wird und dann der ermittelte Wert in der Variablen gespeichert wird.
*) Der Unterschied kann hier aber noch nicht demonstriert werden.
Folie-112
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate» (Fortsetzung)
1. Implementierung
public static int sumOfSquares( int n )
{
int value = 1;
int subtotal = 0;
while ( value <= n )
{
subtotal = subtotal + value * value;
value = value + 1;
}
return subtotal;
}
Eine Schleife ermöglicht die wiederholte Ausführung der Anweisungen innerhalb
des nachfolgenden Blocks zwischen {...}.
Eine Schleife beginnt mit dem Schlüsselwort while.
Es folgen eine Bedingung und ein Block.
Eine Schleife ist eine Anweisung.
Schleife
Block}
Folie-113
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate» (Fortsetzung)
1. Implementierung
public static int sumOfSquares( int n )
{
int value = 1;
int subtotal = 0;
while ( value <= n )
{
subtotal = subtotal + value * value;
value = value + 1;
}
return subtotal;
}
Die Bedingung kontrolliert die Ausführung der Anweisungen in dem nachfolgenden Block.
Eine Bedingung ist ein logischer Ausdruck,
der einen der beiden Werte true (wahr) oder false (falsch) liefert.
Ergibt die Auswertung der Bedingung den Wert true, so wird der Block ausgeführt.
Nach Ausführung aller Anweisungen des Blocks wird erneut die Bedingung ausgewertet.
Ergibt die Auswertung der Bedingung den Wert false, so wird hinter dem Block fortgefahren.
Dadurch werden die Anweisungen des Blocks solange wiederholt,
bis die Auswertung der Bedingung erstmals false ergibt.
Bedingung
Schleife
Block}
Folie-114
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Exkurs: einfaches Modell der Speicherhierarchie
Hardware:
Register
Cache
Arbeits-/Hauptspeicher
Massen-/Peripheriespeicher
Prozessor
Folie-115
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Exkurs: einfaches Modell der Speicherhierarchie (Fortsetzung)
Hardware: Software:
Register
Cache Variable, Parameter
existiert nur während der Programmausführung
Arbeits-/Hauptspeicher
Massen-/Peripheriespeicher Datei
existiert dauerhaft, evt. auch nur auf einem Medium
Prozessor
Folie-116
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Exkurs: einfaches Modell der Speicherhierarchie (Fortsetzung)
Hardware: Software:
«Speicher»
Eine Variable ist ein Name für
einen Bereich im Speicher,
der genau die Größe besitzt, die benötigt wird,
um einen Wert des Typs der Variablen abzulegen.
int v
int subtotal
Prozessor
Folie-117
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Exkurs: einfaches Modell der Speicherhierarchie (Fortsetzung)
Hardware: Software:
«Speicher»
Der Typ der Variablen wird im Programm
angegeben. Daher kann der Compiler bereits
vor der Ausführung des Programms den
entsprechenden Speicherbereich festlegen.
int v
int subtotal
Prozessor
Folie-118
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate» (Fortsetzung)
1. Implementierung
Die Bedingung value <= n führt einen Vergleich von zwei Werten durch.
Vergleichsoperatoren:
Ein Vergleichsoperator vergleicht zwei Werte eines Zahlentyps wie int
und liefert immer ein Ergebnis des Typs boolean.
Der Typ boolean besitzt nur zwei Werte: true und false.
Vergleichsoperatoren:
< kleiner
<= kleiner gleich
> größer
>= größer gleich
== gleich Hinweis: = ist eine Zuweisung (Folie 106)
!= ungleich
Folie-119
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate» (Fortsetzung)
1. Implementierung
Anmerkungen:
Vergleichsoperatoren können auch auf den Typ boolean angewendet werden:
boolean b1, b2;
…
while ( b1 == b2 ) …
aber statt while ( b1 == true ) …
reicht while ( b1 ) …
da b1 == true genau dann den Wert true liefert,
wenn b1 den Wert true besitzt.
Folie-120
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate» (Fortsetzung)
1. Implementierung
Zuweisung
Zuweisungsoperator (bereits bekannt)
dient auch zur Veränderung der Werte von Variablen auf der Basis ihres alten Wertes:
v = v + 4;
v = v * 5;
Verbundoperatoren
verkürzen (nur) die Schreibweise für diesen Fall:
int v = 3, w = 5;
v += 4; entspricht v = v + 4;
v *= w + 3; entspricht v = v * (w + 3);
Folie-121
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate» (Fortsetzung)
1. Implementierung
Inkrement-/Dekrement-Operatoren
verkürzen die Schreibweise für den Fall einer Erhöhung/Verminderung um 1.
Inkrement-/Dekrement-Operatoren
– Präfixoperatoren
++v; entspricht v = v + 1;
–v; entspricht v = v – 1;
Der Ausdruck ++v liefert den Wert von v nach der Zuweisung.
– Postfixoperatoren
v++; entspricht v = v + 1;
v–; entspricht v = v – 1;
Aber der Ausdruck v++ liefert den (alten) Wert von v vor der Veränderung.
int v = 0, w = 3;
v = w++; führt zu: w wird erhöht auf 4, v erhält aber den Wert
von w vor der Erhöhung, also 3, zugewiesen.
v = ++w; führt zu: w wird jetzt erhöht auf 5, v erhält den neuen Wert 5
zugewiesen.
almuthanna
Pencil
Folie-122
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate» (Fortsetzung)
1. Implementierung
public static int sumOfSquares( int n )
{
int value = 1;
int subtotal = 0;
while ( value <= n )
{
subtotal += value * value;
value++;
}
return subtotal;
}
Verbundoperator
Postfixoperator
Folie-123
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate» (Fortsetzung)
2. Implementierung
Das Ergebnis läßt sich auch direkt mit einer Formel berechnen:
public static int sumOfSquares( int n )
{
return n * (n + 1) * (2 * n + 1) / 6;
}
s n n 1+ 2 n 1+
6
------------------------------------------------------=
Folie-124
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate» (Fortsetzung)
2. Implementierung
Das Ergebnis lässt sich auch direkt mit einer Formel berechnen:
public static int sumOfSquares( int n )
{
return n * (n + 1) * (2 * n + 1) / 6;
}
Das ändert aber nicht den Aufruf der Methode sumOfSquares:
public class Summation
{
public static int sumOfSquares( int n )
{
// unknown implementation ...
}
public static void main( String[] args )
{
System.out.println( "Ergebnis für n=34: " + sumOfSquares( 34 ) );
}
}
Das Verbergen von Abläufen in Methoden verbessert offensichtlich
die Änderungsfreundlichkeit des Programms.
Folie-125
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate» (Fortsetzung)
Vergleich der beiden Implementierungen
Ziel: Überprüfen der Korrektheit
public static void main(String[] args)
{
int sum1 = 0, sum2 = 0; int value = 1;
while ( value <=100000 & sum1 == sum2 )
{
sum1 = SummationWithLoop.sumOfSquares( value );
sum2 = SummationWithFormula.sumOfSquares( value );
value++;
}
System.out.println( "value is: " + value );
System.out.println( "sum (computed by loop) is: " + sum1 );
System.out.println( "sum (computed by formula) is: " + sum2 );
}
Bis maximal zum Wert 100000 werden die Summen der Quadrate jeweils mit beiden
Methoden (Algorithmen) berechnet und die Ergebnisse verglichen.
Die zuletzt berechneten Werte werden ausgegeben.
Folie-126
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate» (Fortsetzung)
Vergleich der beiden Implementierungen
Ziel: Überprüfen der Korrektheit
public static void main(String[] args)
{
int sum1 = 0, sum2 = 0; int value = 1;
while ( value <=100000 & sum1 == sum2 )
{
sum1 = SummationWithLoop.sumOfSquares( value );
sum2 = SummationWithFormula.sumOfSquares( value );
value++;
}
System.out.println( "value is: " + value );
System.out.println( "sum (computed by loop) is: " + sum1 );
System.out.println( "sum (computed by formula) is: " + sum2 );
}
Operator & liefert eine logische UND-Verknüpfung (mathematisch: )
SummationWithLoop.sumOfSquares( value ) bezeichnet den Aufruf
der Methode sumOfSquares aus der Klasse SummationWithLoop.
logischer Operator
Zugriff auf andere Klasse
Folie-127
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate» (Fortsetzung)
Vergleich der beiden Implementierungen
Ausgabe:
value is: 1025
sum (computed by loop) is: 358438400
sum (computed by formula) is: -357389482
Ist die Formel falsch?
Ist die Implementierung der Formel falsch?
Wird die Summe falsch berechnet?
negativer Wert
nicht möglich!
Folie-128
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Summe der Quadrate» (Fortsetzung)
Vergleich der beiden Implementierungen
Ausgabe:
value is: 1025
sum (computed by loop) is: 358438400
sum (computed by formula) is: -357389482
Ist die Formel falsch?
Ist die Implementierung der Formel falsch?
Wird die Summe falsch berechnet?
Problem liegt im Wertebereich des Typs int: –2 147 483 648 ... 2 147 483 647
In der Formel wird n*(n+1)*(2*n+1) berechnet und dann durch 6 geteilt.
Für n = 1025 wird daher zunächst 2 150 630 400 berechnet und
bereits vor der Division der Wertebereich des Typs int verlassen.
Es gibt keine Fehlermeldung, aber das Ergebnis ist fehlerhaft.
Ein Entwickler muss ein solches mögliche Überschreiten des Wertebereichs beachten
und eventuell geeignete Maßnahmen ergreifen.
Folie-129
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Exkurs: Binärzahlenformat
interne Darstellung von positiven und negativen Zahlen als Binärzahl
Zweierkomplement
Vorteil: verzichtet auf die Unterscheidung von Vorzeichen und Zahl
Wertebereich:
– positive Zahlen beginnen mit einer 0
– negative Zahlen beginnen mit einer 1
Beispiel:
(übliches) Dezimalsystem: (37)10 = 7 x 10
1-1 + 3 x 102-1
= 7 x 1 + 3 x 10
Binärsystem: (100101)2 = ( 1 x 2
1-1 + 0 x 22-1 + 1 x 23-1 +
0 x 24-1 + 0 x 25-1 + 1 x 26-1 )10
= (1 x 1 + 1 x 4 + 1 x 32 )10
= (37)10
Folie-130
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Exkurs: Binärzahlenformat (Fortsetzung)
interne Darstellung von positiven und negativen Zahlen als Binärzahl
Zweierkomplement
Vorteil: verzichtet bei Berechnungen auf die Unterscheidung
von Vorzeichen und Zahl
Wertebereich:
– positive Zahlen beginnen mit einer 0: 00001001 entspricht (9)10
– Null ist 00000000
– negative Zahlen beginnen mit einer 1: 11110111 entspricht (–9)10
Vorzeichenwechsel (Umwandlung positive in negative Zahl):
– invertiere jede einzelne Ziffern
– addiere 1 hinzu
– Beispiel:
00001001 wird zu 11110110 und weiter zu 11110111
mit 00001001
+ 11110111
= 100000000
Folie-131
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Exkurs: Binärzahlenformat (Fortsetzung)
Zweierkomplement – Problem des Überlaufs
Beispiel:
01101001 entspricht (105)10
+ 01110001 entspricht (113)10
= 11011010 entspricht (-38)10 – Überlauf in negative Zahlen
Folie-132
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Einfache Typen
Zahlentypen
mit anderen Wertebereichen sind:
Typ long
ganze Zahlen
im Wertebereich –9 223 372 036 854 775 808 ... 9 223 372 036 854 775 807
Rechnungen mit den ganzzahligen Typen int und long sind immer genau.
Typ float
Fließkommazahlen im Wertebereich –3.4*1038 ... +3.4*1038
Typ double
Fließkommazahlen im Wertebereich –1.8*10308 ... +1.8*10308
Fließkommazahlen-Typen decken nicht alle möglichen Werte ihres Wertebereichs ab.
Bei Rechnungen treten daher Rundungsfehler auf. *)
Beim Verlassen eines Wertebereichs treten bei allen Typen Rechenfehler auf.
*) Erklärung erfolgt in der Vorlesung Rechnerstrukturen.
Folie-133
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Einfache Typen (Fortsetzung)
Literale
Typ int
Folgen von Ziffern: 2 19 374 2147483647
kein zulässiges Literal: 59474836474 (nicht im Wertebereich von int)
Typ long
Folgen von Ziffern, endet mit L: 2L 19L 59474836474L
Typ float
Folgen von Ziffern, endet mit F, auch mit Dezimalpunkt und Exponent:
19F 37.4F 21E7F
kein zulässiges Literal: 6.9E44F (nicht im Wertebereich von float)
Typ double
Folgen von Ziffern mit Dezimalpunkt, auch mit Exponent:
2. 19.0 37.4 5.9474836474E45
Folie-134
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Einfache Typen (Fortsetzung)
Kompatibilität
Werte von Typen mit einem kleineren Wertebereich sind kompatibel mit
Typen mit einem größeren Wertebereich.
2, 17 und 2891 sind Literale für den Typ int.
Die folgenden Initialisierungen sind also erlaubt:
long v = 2891;
float w = 17;
double x = v;
2.5, 16.0 und 4E22 sind Literale für den Typ double.
Die folgenden Initialisierungen sind also erlaubt:
double y = 4E22;
double z = 16.0;
Nicht erlaubt sind hingegen:
v = z;
v = 2.0;
w = 2.5;
Folie-135
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Einfache Typen (Fortsetzung)
Typ boolean
Literale sind true
und false
logische Operatoren
– Konjunktion (und, mathematisches Zeichen: ) als Java-Operator &
– Disjunktion (oder, mathematisches Zeichen: ) als Java-Operator |
– Negation (mathematisches Zeichen: ) als Java-Operator !
Folie-136
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Einfache Typen (Fortsetzung)
Anmerkungen zu Operatoren
Mit Ausnahme der Zuweisung werden
alle Operatoren von links nach rechts ausgewertet.
Operatoren mit höherer Priorität oder Klammern
ändern die Auswertungsreihenfolge.
Operatoren liefern immer einen Wert eines bestimmten Typs.
Der Typ des Ergebnisses eines Operators ergibt sich implizit aus den Typen der Operanden.
Dabei wird bei numerischen Berechnungen zwangsläufig der Typ des Operanden mit dem
größeren Wertebereich zum Typ des Ergebnisses.
Beispiele:
double x = 2.51;
4 + 5 ergibt den int-Wert 9
5 / 2 * 2 ergibt den int-Wert 4
2 * 5 / 2 ergibt den int-Wert 5
4.4 + 5 ergibt den double-Wert 9.4
5 / 2.0 ergibt den double-Wert 2.5
10 * x ergibt den double-Wert 25.1
Folie-137
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Einfache Typen (Fortsetzung)
Anmerkungen zu Operatoren
Der Typ, den ein Operator liefert, ergibt sich implizit aus den Typen der Operanden.
Das Ergebnis erhält zwangsläufig den Typ des Operanden mit dem größeren Wertebereich.
Sonderfall Operator +:
– Addition
– Konkatenation von Texten (siehe Folie 70)
"hello" + " " + "world" ergibt
über "hello " + "world" den String "hello world"
"hello" + 2 + 3 ergibt
über "hello2" + 3 den String "hello23"
2 + 3 + "hello" ergibt
über 5 + "hello" den String "5hello"
almuthanna
Pencil
Folie-138
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Operatorprioritäten
Die Priorität eines Operators bestimmt den Zeitpunkt seiner Auswertung in einem Ausdruck.
Priorität Operatoren
hoch 1 ++, --, ! alle einstelligen (unären) Operatoren
2 *, / Punktrechnung
3 +, - Strichrechnung
4
5 >, >=, < , <= Vergleiche
6 ==, != (Un-)Gleichheit
7 & Konjuktion
8
9 | Disjunktion
...
13 = Zuweisung
niedrig 14 +=, *= Verbundzuweisungen
Folie-139
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Syntaxdiagramm zu Blocksequenz (siehe Folie 81)
Block
Anweisung
Blocksequenz
Folie-140
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Syntaxdiagramm zu Anweisung
Deklaration
Zuweisung
Schleife
Anweisung
Methodenaufruf
return-Anweisung
;
Folie-141
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Syntaxdiagramm zu Deklarationen und Zuweisung
Deklaration
Deklarationen
,
Typ
Deklaration =Bezeichner Ausdruck
Zuweisung
Bezeichner AusdruckZuweisungsoperator
Folie-142
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Syntaxdiagramm zu Schleife
Der Ausdruck eines Schleifenkopfs muss immer ein Ergebnis des Typs boolean liefern.
Die while-Schleife sollte aus Gründen der Übersichtlichkeit und zur Fehlervermeidung
immer nur mit einem nachfolgenden Block verwendet werden.
Schleife
while-Kopf
( Ausdruck )
while-Kopf
while
Block
Anweisung
Folie-143
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Bestimmung ganzzahlig teilbarer Summen von Quadraten»
Aufgabe:
Bestimme die Anzahl der Summen von Quadraten aller natürlichen Zahlen kleiner 1000,
die ganzzahlig durch eine vorgegebene Zahl divisor teilbar sind.
oder mathematischer: Wie viele i mit i<1000 gibt es, so dass
12 + 22 + 32 + 42 + ... + i2 ganzzahlig durch divisor teilbar ist.
Lösungsansatz:
Bestimme für jedes i die Summe der Quadratzahlen auf die bekannte Weise.
Prüfe bei jeder Summe, ob sie ganzzahlig durch divisor teilbar ist.
Falls das der Fall ist, merke, dass ein Treffer (mehr) erfolgt ist.
Gib am Ende die Anzahl der Treffer zurück.
Folie-144
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Bestimmung ganzzahlig teilbarer Summen von Quadraten»
1. Implementierung
public static int sumsDivisibleBy( int divisor )
{
int value = 1;
int sum = 0;
int count = 0;
while ( value < 1000 )
{
sum += value * value;
if ( sum % divisor == 0 )
{
count++;
}
value++;
}
return count;
}
Folie-145
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Bestimmung ganzzahlig teilbarer Summen von Quadraten»
1. Implementierung
public static int sumsDivisibleBy( int divisor )
{
int value = 1;
int sum = 0;
int count = 0;
while ( value < 1000 )
{
sum += value * value;
if ( sum % divisor == 0 )
{
count++;
}
value++;
}
return count;
}
Eine bedingte Anweisung beginnt mit dem Schlüsselwort if,
auf das eine Bedingung und ein Block folgen.
Eine bedingte Anweisung kontrolliert über die Bedingung die Ausführung des folgenden
Blocks. Nur wenn die Bedingung den Wert true ergibt, wird der Block einmal ausgeführt.
bedingte Anweisung
Bedingung
Folie-146
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Bestimmung ganzzahlig teilbarer Summen von Quadraten»
1. Implementierung
public static int sumsDivisibleBy( int divisor )
{
int value = 1;
int sum = 0;
int count = 0;
while ( value < 1000 )
{
sum += value * value;
if ( sum % divisor == 0 )
{
count++;
}
value++;
}
return count;
}
Der Modulo-Operator % liefert den Rest der ganzzahligen Division sum / divisor,
also gilt: sum % divisor == sum - (sum / divisor) * divisor
Hinweis Für negative Dividenden kann ein negativer Rest entstehen:
-11 % 2 ergibt -1, da gilt: -11 - (-11 / 2) * 2 == -1
Modulo-Operator
Folie-147
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Syntaxdiagramm zu bedingte Anweisung
Die bedingte Anweisung sollte aus Gründen der Übersichtlichkeit und Fehlervermeidung
immer nur mit einem nachfolgenden Block verwendet werden.
( Ausdruck )
bedingte Anweisung
if
Block
Anweisung
Folie-148
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Bestimmung ganzzahlig teilbarer Summen von Quadraten»
2. Implementierung
Übersichtlichere Darstellung mit einer for-Schleife,
die die wesentlichen Teile der Schleifenkonstruktion in ihrem Kopf zusammenfasst:
– Deklaration und Initialisierung von (Zähl-)Variablen
– Veränderung von (Zähl-)Variablen
public static int sumsDivisibleBy( int divisor )
{
int sum = 0;
int count = 0;
for ( int value = 1; value < 1000; value++ )
{
sum += value * value;
if ( sum % divisor == 0 )
{
count++;
}
}
return count;
}
for-Schleife
Deklaration und Initialisierung Veränderung
Bedingung
Folie-149
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Bestimmung ganzzahlig teilbarer Summen von Quadraten»
2. Implementierung
Hinweise zur for-Schleife:
Der Abschnitt mit Deklaration und Initialisierung wird vor den anderen Bestandteilen der
Schleife genau einmal ausgeführt.
Anschließend wird die Bedingung ausgewertet.
Liefert die Bedingung das Ergebnis true, so werden die Anweisungen im Rumpf der Schleife
ausgeführt.
Liefert die Bedingung das Ergebnis false, so wird die Ausführung der Schleife beendet.
Der Veränderungsabschnitt wird nach den Anweisungen im Rumpf der Schleife ausgeführt.
Anschließend wird die Bedingung ausgewertet.
Initialisierungs- und Veränderungsabschnitt können auch leer bleiben.
Dann entspricht die for-Schleife einer while-Schleife:
for (; value < 1000;)
Folie-150
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Syntaxdiagramm zu Schleife
Die for-Schleife sollte aus Gründen der Übersichtlichkeit immer nur mit einem nachfolgenden
Block verwendet werden.
Schleife
while-Kopf
( Deklarationen
)
for-Kopf
for
Block
Anweisungfor-Kopf
; Ausdruck
; Zuweisungen
almuthanna
Pencil
almuthanna
Pencil
almuthanna
Pencil
Folie-151
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Bestimmung von Primzahlen»
Aufgabe:
Bestimme alle Primzahlen bis zu einer vorgegebenen Zahl n.
Erinnerung:
Primzahlen sind natürliche Zahlen, die nur durch 1 und sich selbst ganzzahlig teilbar sind.
Beispiele:
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, ...
Lösungsansatz (Sieb des Eratosthenes, griechischer Mathematiker, geb. ca. 275 v. Chr.):
Schreibe alle natürlichen Zahlen (>1 und <=n) als Liste auf.
Beginne vorne in der Liste.
Wähle die nächste Zahl aus und streiche alle ihre Vielfachen aus der Liste.
Falls das Ende der Liste noch nicht erreicht ist, fahre fort.
Falls das Ende der Liste erreicht ist, stehen in der Liste nur noch Primzahlen.
Folie-152
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Bestimmung von Primzahlen» (Fortsetzung)
Lösungsansatz:
Schreibe alle natürlichen Zahlen (>1 und <=n) als Liste auf.
Beginne vorne in der Liste.
Wähle die nächste Zahl aus und streiche alle ihre Vielfachen aus der Liste.
Falls das Ende der Liste noch nicht erreicht ist, fahre fort.
Falls das Ende der Liste erreicht ist, stehen in der Liste nur noch Primzahlen.
Beispiel:
Schreibe die natürlichen Zahlen bis 30 auf:
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Folie-153
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Bestimmung von Primzahlen» (Fortsetzung)
Lösungsansatz:
Schreibe alle natürlichen Zahlen (>1 und <=n) als Liste auf.
Beginne vorne in der Liste.
Wähle die nächste Zahl aus und streiche alle ihre Vielfachen aus der Liste.
Falls das Ende der Liste noch nicht erreicht ist, fahre fort.
Falls das Ende der Liste erreicht ist, stehen in der Liste nur noch Primzahlen.
Beispiel:
Schreibe die natürlichen Zahlen bis 30 auf:
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Wähle 2 aus und streiche die Vielfachen von 2 aus der Liste:
2 3 5 7 9 11 13 15 17 19 21 23 25 27 29
Folie-154
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Bestimmung von Primzahlen» (Fortsetzung)
Lösungsansatz:
Schreibe alle natürlichen Zahlen (>1 und <=n) als Liste auf.
Beginne vorne in der Liste.
Wähle die nächste Zahl aus und streiche alle ihre Vielfachen aus der Liste.
Falls das Ende der Liste noch nicht erreicht ist, fahre fort.
Falls das Ende der Liste erreicht ist, stehen in der Liste nur noch Primzahlen.
Beispiel:
Schreibe die natürlichen Zahlen bis 30 auf:
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Wähle 2 aus und streiche die Vielfachen von 2 aus der Liste:
2 3 5 7 9 11 13 15 17 19 21 23 25 27 29
Wähle 3 aus und streiche die Vielfachen von 3 aus der Liste:
2 3 5 7 11 13 17 19 23 25 29
Folie-155
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Bestimmung von Primzahlen» (Fortsetzung)
Lösungsansatz:
Schreibe alle natürlichen Zahlen (>1 und <=n) als Liste auf.
Beginne vorne in der Liste.
Wähle die nächste Zahl aus und streiche alle ihre Vielfachen aus der Liste.
Falls das Ende der Liste noch nicht erreicht ist, fahre fort.
Falls das Ende der Liste erreicht ist, stehen in der Liste nur noch Primzahlen.
Beispiel:
Schreibe die natürlichen Zahlen bis 30 auf:
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Wähle 2 aus und streiche die Vielfachen von 2 aus der Liste:
2 3 5 7 9 11 13 15 17 19 21 23 25 27 29
Wähle 3 aus und streiche die Vielfachen von 3 aus der Liste:
2 3 5 7 11 13 17 19 23 25 29
Wähle 5 aus und streiche die Vielfachen von 5 aus der Liste:
2 3 5 7 11 13 17 19 23 29
Folie-156
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Bestimmung von Primzahlen» (Fortsetzung)
Lösungsansatz:
Schreibe alle natürlichen Zahlen (>1 und <=n) als Liste auf.
Beginne vorne in der Liste.
Wähle die nächste Zahl aus und streiche alle ihre Vielfachen aus der Liste.
Falls das Ende der Liste noch nicht erreicht ist, fahre fort.
Falls das Ende der Liste erreicht ist, stehen in der Liste nur noch Primzahlen.
Bestandsaufnahme:
natürliche Zahlen auflisten: Implementierung mit Schleife
Vielfache ermitteln: über Modulo-Operator möglich
wiederholtes Ermitteln der Vielfachen: Implementierung mit einer Schleife
verbleibende Zahlen ausgeben: Implementierung mit einer Schleife,
System.out.println
aber:
Das Anlegen einer Liste von Zahlen ist mit den bekannten Hilfsmitteln unmöglich.
Es können bisher nur einzelne Werte in Variablen abgelegt werden.
Benötigt wird also eine Möglichkeit, um viele Werte (des gleichen Typs) zu speichern.
Folie-157
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Felder
Ein Feld (englisch Array) ist eine Folge
einer festen Anzahl von Werten des gleichen Typs.
Der Zugriff auf ein Feld erfolgt über eine Feldvariable.
Der Umgang mit Feldvariablen und Felder wird auf den folgenden Folien eingeführt:
Deklaration von Feldvariablen
Erzeugen von Feldern
Initialisieren von Feldern
Zuweisen
– von einzelnen Werten
– von ganzen Feldern
Zugriff auf einzelne Werte eines Feldes
Folie-158
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Felder (Fortsetzung)
Erinnerung
int value; deklariert eine Variable value,
die genau einen int-Wert aufbewahren kann.
Deklaration einer Feldvariablen
int[] ist der Typ aller Felder mit int-Werten,
int ist der Grundtyp dieser Felder.
int[] values; deklariert eine Feldvariable values,
die ein Feld mit dem Grundtyp int erreichbar macht.
Die Anzahl der Werte des Feldes ist kein Bestandteil
der Deklaration der Feldvariablen.
Sonderzeichen für Feld: []
Folie-159
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Felder (Fortsetzung)
Das Erzeugen eines Feldes erfordert
das Festlegen der Anzahl der speicherbaren Werte.
int count = 25;
int[] values; Nach der Deklaration besitzt die Variable keinen Wert!
values = new int[5]; Nach der Zuweisung ist der «Wert» der Variablen
das neu erzeugte Feld.
values = new int[231];
values = new int[count];
values = new int[2 * count];
Schlüsselwort new erzeugt ein neues Feld mit nachfolgend genannten Grundtyp.
Die Angabe zwischen [...] legt die Anzahl der Elemente des Feldes fest.
In jedem Element kann ein Wert des Grundtyps abgelegt werden.
Auch möglich ist: values = new int[0];
Es wird ein Feld ohne Elemente erzeugt.
Die Anzahl der Elemente wird auch als Länge oder Größe des Feldes bezeichnet.
Folie-160
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
einfaches Modell der Speicherung von Feldern
(vergleiche Folie 115)
Hardware: Software:
«Speicher»
Die Anzahl der Elemente eines Feldes
wird erst während der Ausführung festgelegt.
Der Compiler kann daher vor der Ausführung
nur einen Speicherbereich bestimmen, von dem aus
auf das Feld mit seinen Elementen verwiesen wird.
int[] values
Folie-161
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
einfaches Modell der Speicherung von Feldern (Fortsetzung)
Hardware: Software:
«Speicher»
Für Felder und ihre Elemente wird ein Teil des
«Freispeicher» Speichers (Freispeicher) reserviert, der während
der Ausführung dynamisch den Feldvariablen
zugeordnet wird.
int[] values
Folie-162
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
einfaches Modell der Speicherung von Feldern (Fortsetzung)
Hardware: Software:
«Speicher»
Für Felder und ihre Elemente wird ein Teil des
«Freispeicher» Speichers (Freispeicher) reserviert, der während
der Ausführung dynamisch den Feldvariablen
zugeordnet wird.
int[] values = new int[5]
Folie-163
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Felder (Fortsetzung)
Feldvariablen können auch in der bekannten Weise initialisiert werden:
int[] values = new int[5];
Die Feldvariable values wird mit dem neu erzeugten Feld initialisiert.
Alle Elemente des Feldes des Grundtyps int werden mit 0 initialisiert.
Visualisierung:
Nur das Initialisieren kann auch über die direkte Angabe der Werte des Feldes erfolgen:
int[] values = { 17, 2, 23, -5, 0, 7 };
Die Feldvariable values wird mit einem neu erzeugten Feld der Länge 6 initialisiert,
dessen Elemente die Werte { 17, 2, 23, -5, 0, 7 } besitzen.
Visualisierung:
0 0000
17 0-5232 7values
values
Folie-164
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Felder (Fortsetzung)
Die Elemente des Feldes sind durchnummeriert.
Die Nummerierung beginnt mit 0.
Die Nummer eines Elements wird als Index bezeichnet.
int[] values = { 17, 2, 23, -5, 0, 7 }
Visualisierung:
Der Zugriff auf ein Element des Feldes erfolgt über die Angabe des Index in [...]:
values[2] = 9; Dem 3. Element wird der Wert 9 zugewiesen.
values[0] = 1; Dem 1. Element wird der Wert 1 zugewiesen.
Visualisierung:
17 0-5232 7values
0 1 2 3 4 5 Index
Wert
1 0-592 7values
0 1 2 3 4 5
Folie-165
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Felder (Fortsetzung)
Der Index kann auch berechnet werden:
int position = 4;
int[] values = { 1, 2, 9, -5, 0, 7 };
values[position + 1] = 3; Dem 6. Element wird der Wert 3 zugewiesen.
values[position - 1] = 1; Dem 4. Element wird der Wert 1 zugewiesen.
Visualisierung:
Die Länge des Feldes kann ermittelt werden durch: values.length
values.length liefert als Ergebnis: 6
Zulässige Werte für den indexbasierten Zugriff zu den Elementen eines Feldes x
liegen daher immer nur im Bereich 0, ..., x.length-1
1 0192 3values
0 1 2 3 4 5
Folie-166
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Felder (Fortsetzung)
Der Zugriff auf die Elemente eines Feldes erfolgt ebenfalls indexbasiert:
int[] values = { 1, 2, 9, -5, 0, 7 };
int v;
v = values[3]; Der Variablen v wird der Wert -5 zugewiesen.
Auch die Anwendung von Zuweisungsoperatoren ist
auf den Elementen eines Feldes möglich:
values[2] += 4; Der Wert des 3. Elements wird um 4 erhöht.
values[3]++; Der Wert des 4. Elements wird um 1 erhöht.
Visualisierung:
1 0-4132 7values
0 1 2 3 4 5
Folie-167
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Felder (Fortsetzung)
Zugriffe mit unzulässigem Indexwert:
int[] values = { 1, 2, 9, -5, 0, 7 };
int i = values[8]; Es wird versucht, den Wert eines nicht
vorhandenen Elements abzurufen.
values[-1] = 1; Es wird versucht, einem nicht vorhandenen
Element einen Wert zuzuweisen.
Immer dann, wenn ein Wert für den indexbasierten Zugriff zu einem Element
eines Feldes x angegeben wird, der nicht im Bereich 0, ..., x.length-1 liegt,
entsteht eine Ausnahme(-situation) (siehe Folie 96).
Fehlermeldungen bei der Programmausführung:
java.lang.ArrayIndexOutOfBoundsException: 8
bzw. java.lang.ArrayIndexOutOfBoundsException: -1
fehlerhafte Indexangabe
Ursache des Fehlers
Folie-168
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zuweisungen an Feldvariablen (Modell)
(vergleiche Folie 162)
Hardware: Software:
«Speicher»
int[] values1;
int[] values2;
«Freispeicher»
Der Compiler legt fest, an welcher Stelle des Speichers
die Feldvariablen eingerichtet werden.
Folie-169
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zuweisungen an Feldvariablen (Modell) (Fortsetzung)
Hardware: Software:
«Speicher»
int[] values1;
int[] values2;
values1 = new int[3];
«Freispeicher» values2 = new int[6];
Während der Ausführung werden Speicherbereiche in
der benötigten Größe für die Felder reserviert.
Die Positionen dieser Speicherbereiche werden in den
Feldvariablen abgelegt.
Folie-170
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zuweisungen an Feldvariablen (Modell) (Fortsetzung)
Hardware: Software:
«Speicher»
int[] values1;
int[] values2;
values1 = new int[3];
«Freispeicher» values2 = new int[6];
values1 = values2;
Der Feldvariablen values1 wird der Speicherbereich
zugewiesen, den die Feldvariable values2 kennt.
Beide Feldvariablen verweisen jetzt auf den gleichen
Speicherbereich (mit Platz für sechs int-Werte).
Der Speicherbereich für drei int-Werte ist nicht mehr
erreichbar.
Folie-171
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zuweisungen an Feldvariablen (Fortsetzung)
Die Zuweisung von Feldvariablen führt also zu folgendem Verhalten:
int[] values1 = { 4, 7, 13 };
int[] values2 = { 1, 2, 9, 1, 0, 7 };
values1 = values2; Effekt: Die Feldvariable values1 bezeichnet
dasselbe Feld wie die Feldvariable values2.
Konsequenzen:
Es ensteht keine Kopie des Feldes values2.
Das Feld besitzt jetzt «zwei Namen».
Das Feld ist nicht mehr erreichbar.
Alle weiteren Änderungen an den Elementen des Feldes wirken
in gleicher Weise für den Zugriff über values1 oder values2.
4 137values1
1 0192 7values2
1 0192 7values1values2
4 137
1 0192 7
Folie-172
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kopieren von Feldinhalten
Das Kopieren von Feldinhalten muss also immer elementweise geschehen:
int[] values1;
int[] values2 = {1,2,3,4};
values1 = new int[values2.length];
for ( int i = 0; i < values2.length; i++ )
{
values1[i] = values2[i];
}
Jedes Feld muss explizit mit new angelegt werden.
Die Elemente eines neu angelegten Feldes sind immer mit einem (Null-)Wert initialisiert:
– für int[] ist das 0
– für double[] ist das 0.0
– für boolean[] ist das false
Bestimmen der Länge
Erzeugen des neuen Feldes
Zuweisen der einzelnen Werte
Folie-173
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kopieren von Feldinhalten (Fortsetzung)
Das Kopieren lässt sich auch als Methode implementieren:
public static int[] copy( int[] in )
{
int[] out = new int[in.length];
for ( int i = 0; i < in.length; i++ )
{
out[i] = in[i];
}
return out;
}
Typ der Rückgabe:
Feld mit Grundtyp int
Folie-174
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kopieren von Feldinhalten (Fortsetzung)
Auch das Übertragen der Inhalte eines Feldes in ein (passendes) zweites Feld muss elementweise
erfolgen:
public static void moveTo( int[] source, int[] into )
{
if ( source.length == into.length )
{
for ( int i = 0; i < source.length; i++ )
{
into[i] = source[i];
}
}
}
Für den Aufruf von moveTo muss ein passendes Feld bereitgestellt werden:
int[] values1 = new int[values2.length];
moveTo( values2, values1 );
Anschließend enthalten die Elemente des über values1 erreichbaren Feldes die Werte
der Elemente des Feldes, das durch values2 erreicht wird.
Folie-175
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kopieren von Feldinhalten (Fortsetzung)
Ausführung der Methode moveTo:
public static void moveTo( int[] source, int[] into )
{
if ( source.length == into.length )
{
for ( int i = 0; i < source.length; i++ )
{
into[i] = source[i];
}
}
}
Beim Aufruf der Methode moveTo wird der Wert des zweiten Arguments dem Parameter into
zugewiesen.
Da es sich um eine Feldvariable handelt, erreicht into jetzt das Feld, das auch über die als
zweites Argument übergebene Feldvariable erreichbar ist.
Die Zuweisung in der Methode moveTo ändert also die Elemente des über die als zweites
Argument übergebene Feldvariable auch außerhalb der Methode sichtbaren Feldes.
Auf diese Weise ist das geänderte Feld nach der Ausführung der Methode erreichbar.
Folie-176
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Bestimmung von Primzahlen» (Fortsetzung)
Lösungsansatz:
Schreibe alle natürlichen Zahlen (>1 und <=n) als Liste auf.
Beginne vorne in der Liste.
Wähle die nächste Zahl aus und streiche alle ihre Vielfachen aus der Liste.
Falls das Ende der Liste noch nicht erreicht ist, fahre fort.
Falls das Ende der Liste erreicht ist, stehen in der Liste nur noch Primzahlen.
Überlegungen zur Realisierung:
Die sich im Verlauf der Ausführung ändernde Liste von natürlichen Zahlen wird durch ein Feld
des Grundtyps boolean repräsentiert, bei dem der Wert true am Index i anzeigt,
dass i eine Zahl in der Liste ist.
Soll eine Zahl i aus der Liste gestrichen werden,
so wird das Element am Index i auf den Wert false gesetzt.
Nach Beenden des Algorithmus sind die Primzahlen dann durch alle Indizes gegeben,
deren zugehöriger Wert true ist.
Folie-177
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Bestimmung von Primzahlen» (Fortsetzung)
Implementierung:
public static void computePrimes( int n )
{
boolean[] numbers = initializeNumbers( n );
inspectNumbers( numbers );
show( numbers );
}
erzeugt ein
passendes Feld
markiert Primzahlen
zeigt die Primzahlen
auf dem Bildschirm an
Folie-178
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Bestimmung von Primzahlen» (Fortsetzung)
Implementierung:
public static void computePrimes( int n )
{
boolean[] numbers = initializeNumbers( n );
inspectNumbers( numbers );
show( numbers );
}
Ausführung:
computePrimes
inspectNumbers
initializeNumbers
show
Folie-179
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Bestimmung von Primzahlen» (Fortsetzung)
Schritt 1: Die Methode initializeNumbers erzeugt ein Feld des Typs boolean der Länge n+1,
bei dem in allen Elementen mit Index i>1 der Wert true steht.
public static boolean[] initializeNumbers( int n )
{
boolean[] numbers = new boolean[n+1];
for ( int i = 2; i < numbers.length; i++ )
{
numbers[i] = true;
}
return numbers;
}
Visualisierung:
Alle Werte des Feldes sind beim Erzeugen mit false initialisiert,
da false der Nullwert des Typs boolean ist.
Die Methode ändert die Werte für die Indizes 0 und 1 nicht.
Der größte für das Feld numbers zulässige Index ist n.
falsenumbers
0 1 2 3 4 5
...false truetrue truetrue
Folie-180
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Bestimmung von Primzahlen» (Fortsetzung)
Schritt 2: 1. Implementierung der Methode inspectNumbers, die alle Zahlen betrachtet.
public static void inspectNumbers( boolean[] numbers )
{
for ( int i = 2; i < numbers.length; i++ )
{
if ( numbers[i] )
{
discardMultiples( numbers, i );
}
}
}
Nach Ausführung von inspectNumbers besitzt numbers nur noch für solche Indizes
den Wert true, die Primzahlen sind.
if ( numbers[i] ) entspricht if ( numbers[i] == true )
streicht die Vielfachen
von i aus numbers
nur für nicht gestrichenen Zahlen
der Liste
Folie-181
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Bestimmung von Primzahlen» (Fortsetzung)
public static void inspectNumbers( boolean[] numbers )
{
for ( int i = 2; i < numbers.length; i++ )
{
if ( numbers[i] )
{
discardMultiples( numbers, i );
}
}
}
computePrimes
inspectNumbers
initializeNumbers
show
discardMultiples
Folie-182
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Bestimmung von Primzahlen» (Fortsetzung)
Schritt 2: 1. Implementierung der Methode discardMultiples, die das Aussieben durchführt.
public static void discardMultiples( boolean[] numbers, int i )
{
for ( int j = i+1; j < numbers.length; j++ )
{
if ( j % i == 0 )
{
numbers[j] = false;
}
}
}
In jedem Element des Feldes numbers, dessen Index j ein ganzzahliges Vielfaches von i ist,
wird der Wert false eingetragen.
j ist dann ein ganzzahliges Vielfaches von i , wenn die Division j/i zu keinem Rest führt.
Streichen wird als
«setze auf false» realisiert
Folie-183
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Bestimmung von Primzahlen» (Fortsetzung)
Schritt 2: 1. Implementierung der Methode discardMultiples, die das Aussieben durchführt.
public static void discardMultiples( boolean[] numbers, int i )
{
for ( int j = i+1; j < numbers.length; j++ )
{
if ( j % i == 0 )
{
numbers[j] = false;
}
}
}
Analyse
Es werden sehr viele überflüssige %-Berechnungen ausgeführt:
beispielsweise wird i+1 niemals ganzzahlig durch i teilbar sein für i>1.
Falls i die Primzahl ist, deren Vielfache gestrichen werden sollen, so sind ja bereits
alle Vielfachen p*i gestrichen worden, bei denen p eine Primzahl ist und p 0
// there exists no x>1 with numerator%x==0 and denominator%x==0
}
}
Ein Konstruktor erzeugt ein Objekt der Klasse und ähnelt im Aufbau einer Methode.
Ein Konstruktor besitzt keine Angabe für einen Rückgabewert.
Ein Konstruktor besitzt immer den gleichen Namen wie die Klasse.
Jedes Objekt der Klasse Fraction besitzt eigene Attribute numerator und denominator.
Der Konstruktor dient dazu, die Attribute des erzeugten Objekts so mit Werten zu belegen,
dass das Objekt sinnvoll benutzbar ist.
Konstruktor
Folie-211
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Visualisierung
Aufgabe des Konstruktors:
Aufruf des
Konstruktors
public class Fraction
{
private int numerator;
private int denominator;
public Fraction(int num,int denom)
{ … }
}
Deklaration
numerator
denominator
numerator
denominator
numerator
denominator
numerator
denominator
Objekte der Klasse Fraction
Folie-212
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Die Klasse für den Umgang mit rationalen Zahlen wird schrittweise erweitert:
public class Fraction
{
private int numerator; // Zaehler
private int denominator; // Nenner
public Fraction ( int num, int denom )
{
// ensure:
// denominator > 0
// there exists no x with numerator%x==0 and denominator%x==0
}
}
Für jedes Attribut und jeden Konstruktor wird ein Zugriffsrecht festgelegt.
Das Zugriffsrecht private (privat) beschränkt die Sichtbarkeit auf genau die Klasse,
in der die Deklaration erfolgt:
Das Attribut numerator ist nur innerhalb der Klasse Fraction bekannt.
Das Zugriffsrecht public (öffentlich) schränkt die Sichtbarkeit nicht ein:
Der Konstruktor Fraction( … ) kann auch in anderen Klassen aufgerufen werden.
Zugriffsrecht
Folie-213
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Zugriffsrechte:
Die Klasse Fraction bietet anderen Klassen bisher nur genau den Konstruktor an,
da die beiden Attribute als private deklariert sind.
Attribute sollten immer als private deklariert werden.
(Die Gründe werden hoffentlich im Verlauf der folgenden Vervollständigung
der Klasse Fraction deutlich.)
Konstruktoren werden nur in sehr speziellen Fällen nicht als public deklariert.
Anmerkungen:
Bei dem Fehlen eines explizit angegebenen Zugriffsrechts besitzt ein Element der Klasse
(Attribut, Methode, Konstruktor) implizit das Zugriffsrecht package, das hier noch nicht
erläutert werden kann.
Attribute können als public deklariert werden.
Dieses sollte aber unbedingt vermieden werden.
Beispiel (nicht zur Nachahmung): length ist ein öffentliches Attribut eines Feldes.
Folie-214
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Planung des Konstruktors:
Der Aufruf des Konstruktors erzeugt eine neue rationale Zahl (bzw. einen neuen Bruch).
Zähler und Nenner (Attribute numerator, denominator) müssen
eine zulässige Kombination von Werten enthalten.
Dem Nenner darf nicht der Wert 0 zugewiesen werden.
Die Division durch 0 wäre unzulässig.
Der Nenner des Bruchs soll nicht negativ sein.
Wird ein negativer Wert für den Nenner als Argument übergeben,
so müssen bei Zähler und Nenner die Vorzeichen gewechselt werden.
Der Bruch muss gekürzt werden,
d.h. Zähler und Nenner müssen durch ihren größten gemeinsamen Teiler
geteilt werden.
Folie-215
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Implementierung des Konstruktors
public Fraction ( int num, int denom )
{
if ( denom != 0 )
{
if ( denom < 0 )
{
numerator = -num;
denominator = -denom;
}
else
{
numerator = num;
denominator = denom;
}
reduce();
}
else
{
// error: division by zero
throw new IllegalArgumentException();
}
}
Folie-216
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Implementierung des Konstruktors
public Fraction ( int num, int denom )
{
if ( denom != 0 )
{
if ( denom < 0 )
{
numerator = -num;
denominator = -denom;
}
else
{
numerator = num;
denominator = denom;
}
reduce();
}
else
{
// error: division by zero
throw new IllegalArgumentException();
}
}
if-else-
Anweisung
if-else-
Anweisung
Folie-217
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Semantik der if-else-Anweisung
if ( denom < 0 )
{
numerator = -num;
denominator = -denom;
}
else
{
numerator = num;
denominator = denom;
}
Ein else-Konstrukt ist nur mit vorangehendem if-Konstrukt möglich.
Das else-Konstrukt bezieht sich immer auf das vorangehende if-Konstrukt auf der gleichen
Ebene der Blockschachtelung.
if ( Bedingung ) { Block1 } else { Block2 }
entspricht immer: boolean b = Bedingung;
if ( b ) { Block1 }
if ( !b ) { Block2 }
Es wird also immer entweder nur das if-Konstrukt oder nur das else-Konstrukt ausgeführt.
Folie-218
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Syntaxdiagramm zu bedingte Anweisung
( Ausdruck )
bedingte Anweisung
if
Block
Anweisung
Block
Anweisung
else
Folie-219
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Implementierung des Konstruktors
public Fraction ( int num, int denom )
{
if ( denom != 0)
{
if ( denom < 0 )
{
numerator = -num;
denominator = -denom;
}
else
{
numerator = num;
denominator = denom;
}
reduce();
}
else
{
// error: division by zero
throw new IllegalArgumentException();
}
}
keine Division durch 0
negatives Argument für Nenner
Wertzuweisungen an die Attribute
Kürzen des Bruchs
(einstelliger) - -Operator
Folie-220
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Implementierung des Konstruktors
public Fraction ( int num, int denom )
{
if ( denom != 0)
{
if ( denom < 0 )
{
numerator = -num;
denominator = -denom;
}
else
{
numerator = num;
denominator = denom;
}
reduce();
}
else
{
// error: division by zero
throw new IllegalArgumentException();
}
} *) Erklärung folgt auf Folie 236
Fehlerfall behandeln *)
Folie-221
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Implementierung des Konstruktors
Anmerkungen:
Ein Attribut übernimmt wie eine Variable das Speichern von Werten.
Ein Attribut wird im Rumpf der Klasse deklariert und ist in allen ihren Methoden zugreifbar.
Bei Ausführung eines Konstruktors erfolgen nacheinander:
– Es wird im «Rechner» Speicherplatz für die Attribute besorgt und reserviert.
– Die Initialisierung von Attributen wird ausgeführt.
– Wird ein Attribut nicht explizit initialisiert, ist es implizit mit einem ausgezeichneten
Wert seines Typs initialisiert. Die Attribute numerator und denominator werden
nicht explizit initialisiert und erhalten daher implizit jeweils den Wert 0.
– Der Rumpf des Konstruktors wird ausgeführt.
Hinweis:
Im Gegensatz zu den bisher vorgestellten Methoden darf ein Konstruktor
nicht mit dem Modifizierer static versehen werden.
Das Kürzen eines Bruchs stellt eine eigenständige Aufgabe dar,
die in dieser Implementierung in eine private Methode reduce ausgelagert ist:
– Der Programmcode des Konstruktors ist so übersichtlicher und leichter lesbar.
– Die Methode reduce besitzt weder Parameter noch Rückgabe,
da sie direkt die beiden Attribute verändert.
Folie-222
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Implementierung der Methode reduce
private void reduce()
{
if ( numerator != 0 )
{
int gcd = calculateGcd();
numerator /= gcd;
denominator /= gcd;
}
else
{
denominator = 1;
}
}
Die Methode reduce greift auf die beiden Attribute der Klasse zu
und verändert ihre Werte: reduce benötigt daher weder Parameter noch eine Rückgabe.
Da die Wirkung der Methode reduce nicht an der Deklaration ihres Kopfes sichtbar
wird, spricht man davon, dass reduce einen Seiteneffekt auf die Attribute hat.
Das Berechnen des für das Kürzen benötigten größten gemeinsamen Teilers ist ebenfalls in eine
private Methode calculateGcd() ausgelagert, um die Lesbarkeit zu verbessern.
Zugriff auf Attribut
normierte Speicherung der 0
Folie-223
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Aufbau der Klasse
public class Fraction
{
private int numerator;
private int denominator;
public Fraction( int num, int denom )
{ ... }
private void reduce()
{ ... }
private int calculateGcd()
{ ... }
}
ruft auf
ruft auf
Folie-224
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Aufrufreihenfolge
public class Fraction
{
private int numerator;
private int denominator;
public Fraction( int num, int denom )
{ ... }
private void reduce()
{ ... }
private int calculateGcd()
{ ... }
}
ruft auf
ruft auf
Fraction
reduce
calculateGcd
: Fraction
Folie-225
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Notation
Fraction
reduce
calculateGcd
: Fraction
Aufruf des Konstruktors
(Erzeugung eines Objekts)
Aufruf einer Methode
Rückkehr zur
Lebenslinie
Ausführung
(des Objekts)
aufrufenden Position
(Notation: angelehnt an Sequenzdiagramme, siehe Vorlesung SWT)
Objekt
einer Methode
Folie-226
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Implementierung der Methode reduce
private void reduce()
{
...
}
Die Methode reduce ist ohne den Modifizierer static deklariert.
Das macht sie zu einer Instanzmethode, die auf die (Instanz-)Attribute zugreifen kann.
Die Instanzmethode reduce ist mit dem Zugriffsrecht private versehen und daher nur
innerhalb der Klasse Fraction sichtbar.
Da die durch Fraction realisierten Brüche immer gekürzt sein sollen,
ist ein Aufruf außerhalb der Klasse Fraction auch nicht erforderlich.
Als Instanzmethode bezieht sich die Ausführung von reduce immer auf genau ein Objekt.
Terminologie:
– Instanzmethoden werden in der Folge als Methoden bezeichnet.
– Methoden, die mit dem Modifizierer static deklariert werden,
werden im Folgenden explizit als statische Methoden bezeichnet.
Folie-227
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Implementierung der Methode calculateGcd
public int calculateGcd()
{
int value1 = Math.abs( numerator );
int value2 = denominator;
while (value1 != 0 & value2 != 0)
{
if ( value1 > value2 )
{
value1 = value1 % value2;
} else {
value2 = value2 % value1;
}
}
if ( value1 == 0 )
{
return value2;
} else {
return value1;
}
}
Betragsbestimmung mit
Methode aus Math
berechnet den größten gemeinsamen
Teiler (greatest common divisor, gcd)
nach dem Algorithmus von Euklid
(geb. ca. 360 v. Chr.)
Folie-228
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Erzeugen eines Objekts
Der Konstruktor dient dazu, ein Objekt der Klasse Fraction zu erzeugen.
Der Aufruf des Konstruktors erfolgt immer hinter dem new-Operator.
Beispiel:
public class FractionCalculator
{
public static void main( String[] args )
{
Fraction f1 = new Fraction ( 4, 5 );
Fraction f2 = new Fraction ( 6, -9 );
}
}
Jeder Aufruf des Konstruktors erzeugt ein neues Objekt der Klasse Fraction.
Die erzeugten Objekte werden hier den Variablen f1 und f2 zugewiesen.
f1 und f2 bezeichnen nun zwei unterschiedliche rationale Zahlen.
Aufruf des Konstruktors
new-Operator
Folie-229
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Klassenstruktur
ruft auf
public class FractionCalculator
{
public static void main( String[] args )
{
Fraction f1 = new Fraction ( 4, 5 );
Fraction f2 = new Fraction ( 6, -9 );
}
}
public class Fraction
{
private int numerator;
private int denominator;
public Fraction( int num, int denom )
{ … }
private void reduce()
{ … }
private int calculateGcd()
{ … }
}
ruft auf
ruft auf
Folie-230
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Fraction
reduce
calculateGcd
f1:Fraction
Problemstellung «Rationale Zahlen» (Fortsetzung)
Klassenstruktur
public class FractionCalculator
{
public static void main( String[] args )
{
Fraction f1 = new Fraction ( 4, 5 );
Fraction f2 = new Fraction ( 6, -9 );
}
}
Fraction
reduce
calculateGcd
f2:Fraction
main
Folie-231
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Visualisierung
public class FractionCalculator
{
public static void main( String[] args )
{
Fraction f1 = new Fraction ( 4, 5 );
Fraction f2 = new Fraction ( 6, -9 );
}
}
f1
numerator
denominator
f2
numerator
denominator
4
5 -2
3
Konstruktor kürzt
und normiert
Folie-232
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Exkurs: Modell der Speicherung von Objekten
(vergleiche auch Folie 160)
Hardware: Software:
«Speicher»
Fraction f1 = new Fraction ( 4, 5 )
Fraction f2 = new Fraction ( 6, -9 )
«Freispeicher»
Folie-233
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Exkurs: Modell der Speicherung von Objekten (Fortsetzung)
Hardware: Software:
«Speicher»
Fraction f1 = new Fraction ( 4, 5 )
Fraction f2 = new Fraction ( 6, -9 )
«Freispeicher»
-2
54
3
Folie-234
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Exkurs: Modell der Speicherung von Objekten (Fortsetzung)
Hardware: Software:
«Speicher»
Fraction f1 = new Fraction ( 4, 5 )
Fraction f2 = new Fraction ( 6, -9 )
«Freispeicher»
Die Werte von f1 und f2 werden als
Referenzen auf die entsprechenden Objekte
bezeichnet.-2
54
3
Folie-235
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Referenzvariablen und Referenzattribute
Die Werte von Variablen und Attributen, über die Objekte erreicht werden können,
sind die Referenzen zu solchen Objekten.
Diese Variablen bzw. Attribute werden als Referenzvariablen bzw. -attribute bezeichnet.
Referenzvariable bzw. Referenzattribute kennen also den Speicherort eines Objekts,
speichern aber das Objekt nicht selbst ab.
In Java sind alle Variablen oder Attribute, deren Typ eine Klasse ist, Referenzvariablen bzw.
Referenzattribute.
Abgrenzung:
int value; value bezeichnet einen Speicherbereich, in dem ein int-Wert
abgelegt werden kann.
Fraction f; f bezeichnet einen Speicherbereich, in dem die Referenz
auf ein Fraction-Objekt abgelegt werden kann.
Der Dereferenzierungsoperator . liefert für eine Referenzvariable das Objekt, dessen
Speicherort sie kennt. Er wertet dazu die in der Referenzvariablen gespeicherte Referenz aus.
In Java kann auch jede Feldvariable (vergleiche Folie 164) als eine Referenzvariable auf ein
Feld(-Objekt) angesehen werden.
Folie-236
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Ausnahmesituation für «Rationale Zahlen»
Implementierung des Konstruktors (Rückblick)
public Fraction ( int num, int denom )
{
if ( denom != 0)
{
if ( denom < 0 )
{
numerator = -num;
denominator = -denom;
}
else
{
numerator = num;
denominator = denom;
}
reduce();
}
else
{
// error: division by zero
throw new IllegalArgumentException();
}
}
Fehlerfall als Ausnahme
behandeln
Folie-237
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Ausnahmesituation für «Rationale Zahlen» (Fortsetzung)
throw new IllegalArgumentException();
Wird als Argument für den Nenner der Wert 0 übergeben,
so kann kein Bruch mit einer mathematisch erlaubten Belegung der Attribute erzeugt werden.
In diesem Fall wird als Lösung die throw-Anweisung aufgerufen, die ein neu erzeugtes Objekt
der Klasse IllegalArgumentException wirft. *)
new IllegalArgumentException() ist das Erzeugen eines solchen Objekts mit Hilfe des
new-Operators und des (parameterlosen) Konstruktors der Klasse IllegalArgumentException.
Java stellt zahlreiche spezielle Klassen bereit, mit denen auf diese Weise Ausnahmesituationen
angezeigt werden können, u.a.:
ArithmeticException, IllegalArgumentException, IndexOutOfBoundsException,
ArrayIndexOutOfBoundsException, NoSuchElementException, NullPointerException
Das Werfen eines Objekts einer dieser Klassen führt zum Abbruch der Programmausführung
mit einer entsprechenden Meldung, die den Namen der Klasse des Objekts enthält.
*) Die technischen Details der throw-Anweisung können hier noch nicht erklärt werden.
Folie-238
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Weitere Planung der Klasse Fraction
Benötigt werden:
Weitere Konstruktoren:
Fraction() ohne Parameter soll die rationale Zahl mit dem Wert 0 erzeugen.
Fraction( int num ) soll die rationale Zahl num als Bruch num/1 erzeugen.
Eine Methode zur Darstellung einer rationalen Zahl als Bruch:
String toString() gibt einen Text mit einem Bruch der Form 7/41 zurück.
Methoden für die Rechenoperationen:
Fraction changeSign()
Fraction reverse()
Fraction add( Fraction other )
Fraction subtract( Fraction other )
Fraction multiply( Fraction other )
Fraction divideBy( Fraction other )
double toDouble()
Fraction clone()
boolean equals( Fraction other )
Folie-239
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
public class Fraction
{
private int numerator;
private int denominator;
public Fraction( int num, int denom ) { ... }
public Fraction() { ... }
public Fraction( int num ) { ... }
public String toString() { ... }
public Fraction changeSign() { ... }
public Fraction reverse() { ... }
public Fraction add( Fraction other ) { ... }
public Fraction subtract( Fraction other ) { ... }
public Fraction multiply( Fraction other ) { ... }
public Fraction divideBy( Fraction other ) { ... }
public double toDouble() { ... }
public Fraction clone() { ... }
public boolean equals( Fraction other ) { ... }
private void reduce() { ... }
private int calculateGcd() { ... }
}
Methoden
private Attribute
Zugriff
private Methoden
Zugriff
Folie-240
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Implementierung der weiteren Konstruktoren
public Fraction()
{
numerator = 0;
denominator = 1;
}
public Fraction( int num )
{
numerator = num;
denominator = 1;
}
Um den Komfort bei der Benutzung einer Klasse in anderen Klassen zu verbessern,
ist es manchmal angebracht, Variationen mit der gleichen Operationalität bereitzustellen.
Konstruktoren oder Methoden mit gleichen Namen müssen sich in ihren Signaturen
unterscheiden, damit während der Ausführung eindeutig eine der Implementierungen
ausgewählt werden kann.
Anlegen des Wertes 0.
Anlegen einer ganzen Zahl num
Folie-241
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
alternative Implementierung der weiteren Konstruktoren
public Fraction()
{
this( 0, 1 );
}
public Fraction( int num )
{
this( num, 1 );
}
Ein Konstruktor der eigenen Klasse kann unabhängig von dem Namen seiner Klasse immer nur
durch this( ... ) aufgerufen werden, wobei die Folge der Argumente der Parameterliste der
Deklaration entsprechen muss.
this( ... ) darf genau einmal als erste Anweisung im Rumpf eines Konstruktors auftreten.
Anmerkung:
Der Aufruf des (komplexeren) Konstruktors mit zwei Parametern bringt im Beispiel oben keine
Vorteile, sondern führt zur Ausführung unnötiger Abfragen in diesem Konstruktor.
this( ... ) ist der Aufruf eines Konstruktors
this( ... ) ist der Aufruf eines Konstruktors
Folie-242
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Implementierung der Methode toString
public String toString()
{
return numerator + " / " + denominator;
}
Ganze einfache Methode, die
den Wert des Zählers, das /-Zeichen und den Wert des Nenners
zu einem Text zusammensetzt.
Die Klasse String ist in Java bereits definiert und realisiert Zeichenketten (Texte).
Die toString-Methode kann benutzt werden,
um den Wert eines Objekts der Klasse Fraction als Bruch auszugeben.
Folie-243
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Aufruf der Methode toString
public String toString()
{
return numerator + " / " + denominator;
}
Beispiel für einen Aufruf:
Fraction f1 = new Fraction ( 4, 5 );
System.out.print( f1.toString() ); erzeugt: 4 / 5
f1
numerator
denominator
4
5
toString()"4 / 5"
Aufruf der Methode toString
für das Objekt f1
ZugriffeRückgabe
Folie-244
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Aufruf der Methode toString
Beispiel für einen Aufruf:
Fraction f1 = new Fraction ( 4, 5 );
System.out.print( f1.toString() );
Notation: f1.toString()
Die Methode toString wird für das über f1 erreichbare Objekt aufgerufen und ausgeführt.
Dieses Objekt wird daher als das toString ausführende Objekt bezeichnet.
Der Dereferenzierungsoperator . ermöglicht den Zugriff zu dem über f1 erreichbaren
Objekt und damit die Ausführung einer Methode auf diesem Objekt.
Voraussetzung hierfür ist, dass das Zugriffsrecht der Methode diesen Aufruf gestattet:
Da toString eine öffentliche Methode ist, ist dieses immer der Fall.
Dereferenzierung
Folie-245
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Exkurs: Modell der Speicherung von Objekten
(siehe Folie 232)
Hardware: Software:
«Speicher»
Fraction f1 = new Fraction ( 4, 5 )
System.out.print( f1.toString() )
«Freispeicher»
ausführendes Objekt54
Folie-246
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Implementierung der Methode changeSign
public Fraction changeSign()
{
return new Fraction( -numerator, denominator );
}
Die Methode changeSign erzeugt ein Objekt, das gegenüber dem ausführenden Objekt ein
geändertes Vorzeichen besitzt.
Die Methode changeSign benötigt daher keinen Parameter.
Folie-247
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Implementierung der Methode changeSign
public Fraction changeSign()
{
return new Fraction( -numerator, denominator );
}
Die Methode changeSign erzeugt ein Objekt, das gegenüber dem ausführenden Objekt ein
geändertes Vorzeichen besitzt.
Die Methode changeSign benötigt daher keinen Parameter.
numerator
denominator
4
5
changeSign()
numerator
denominator
-4
5
Folie-248
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Implementierung der Methode changeSign
public Fraction reverse()
{
return new Fraction( denominator, numerator );
}
Die Methode reverse erzeugt ein Objekt, das den Kehrwert des ausführenden Bruchs enthält,
bei dem also Zähler (numerator) und Nenner (denominator) getauscht worden sind.
numerator
denominator
4
5
reverse()
numerator
denominator
5
4
Folie-249
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Implementierung der Methode add
public Fraction add( Fraction other )
{
int num = numerator * other.denominator + other.numerator * denominator;
int denom = denominator * other.denominator;
return new Fraction ( num, denom );
}
Die Methode add bestimmt nach den Regeln der Bruchrechung
die Werte von Zähler (num) und Nenner (denom) der Addition.
Die Methode add erzeugt durch den Aufruf des Konstruktors
ein neues Objekt der Klasse Fraction und
übergibt dabei die berechneten Werte für Zähler und Nenner
an diesen Konstruktoraufruf als Argumente.
Der Konstruktor sorgt für ein eventuell notwendiges Kürzen des neuen Bruchs.
Der Dereferenzierungsoperator . ermöglicht den Zugriff auf das über other erreichbare
Objekt der Klasse Fraction.
other.numerator liefert also den Wert des Attributs numerator des über other erreichbaren
Objekts.
Dereferenzierung
Folie-250
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Aufruf von Methoden für Objekte
public class FractionCalculator
{
public static void main( String[] args )
{
Fraction f1 = new Fraction ( 4, 5 );
Fraction f2 = new Fraction ( 6, -9 );
Fraction f3 = f1.add( f2 );
System.out.println( "add: " + f1.toString() + " + " + f2.toString() +
" = " + f3.toString() );
}
}
Notation: f1.add( f2 )
Die Methode add wird für das über f1 erreichbare Objekt mit dem Parameter f2
aufgerufen, f1 verweist auf das ausführende Objekt.
In der Klasse FractionCalculator können nur die öffentlich sichtbaren (public)
Methoden der Klasse Fraction aufgerufen werden.
Folie-251
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Visualisierung
Fraction f3 = f1.add( f2 );
f1
numerator
denominator
f2
numerator
denominator
4
5
-2
3
f3
numerator
denominator
2
15
add( other )
Folie-252
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Visualisierung
Fraction f3 = f1.add( f2 );
Fraction
f1:Fraction
Fraction
f2:Fraction
main
add
Fraction
f3:Fraction
Folie-253
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Implementierung der Methode subtract
public Fraction subtract( Fraction other )
{
int num = numerator * other.denominator - other.numerator * denominator;
int denom = denominator * other.denominator;
return new Fraction ( num, denom );
}
Der Aufbau des Algorithmus und der Implementierung
sind analog zu dem der Methode add.
Eine alternative Implementierung greift auf die schon vorhandenen Methoden zurück:
public Fraction subtract( Fraction other )
{
return add ( other.changeSign() );
}
Folie-254
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Visualisierung: alternative Implementierung
Fraction f3 = f1.subtract( f2 );
f1
numerator
denominator
f2
numerator
denominator
4
5
1
3
f3
numerator
denominator
7
15
add( ... )
subtract( other )
changeSign()
numerator
denominator
-1
3
Folie-255
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Implementierung der Methoden multiply und divideBy
public Fraction multiply( Fraction other )
{
int num = numerator * other.numerator;
int denom = denominator * other.denominator;
return new Fraction ( num, denom );
}
public Fraction divideBy( Fraction other )
{
return multiply ( other.reverse() );
}
Die Division erfolgt durch Multiplikation mit dem Kehrbruch.
Der Aufbau der Algorithmen und der Implementierungen
sind analog zu dem der Methoden add bzw. subtract.
Folie-256
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Anwendung der Klasse Fraction
Fraction f1 = new Fraction ( 4, 5 );
Fraction f2 = new Fraction ( 6, -9 );
Fraction f3 = f1.add( f2 );
Fraction f4 = new Fraction(7);
Fraction f5 = f4.add( f2.multiply( f3.subtract( f1 ) ) );
System.out.println( f5.toString() );
Ausgabe:
67 / 9
Mit der Klasse Fraction lassen sich Berechnungen mit Brüchen im Rahmen der Genauigkeit
des Typs int programmieren.
Folie-257
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
weitere Methode
public double toDouble()
{
return (double)numerator / (double)denominator;
}
Die Methode toDouble liefert das Ergebnis der Division von Zähler und Nenner als reelle Zahl.
Um die ganzzahlige Division mit einem ganzzahligen Ergebnis zu vermeiden, muss mindestens
einer der Operatoren der Division explizit in einen double-Wert konvertiert werden
(Type-Cast).
Der Type-Cast (double) erzeugt den dem int-Wert des nachfolgenden Attributs
entsprechenden double-Wert, der dann in die Division eingeht.
Ein Type-Cast der Form (primitiver-Typ) kann auch benutzt werden, um Werte eines Typs
mit einem größeren Wertebereich in Werte eines Typs mit einem kleineren Wertebereich
umzuwandeln. Da es dabei zu Rundungsfehlern kommen kann, muss eine solche Umwandlung
in Java explizit angestoßen werden.
double x = 13.567;
int n = (int)x * 4; Ergebnis ist: 52
int m = (int)( x * 4 ); Ergebnis ist: 54
explizite Typumwandlung
Folie-258
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
weitere Methoden
public Fraction clone() {
return new Fraction( numerator, denominator );
}
Die Methode clone erzeugt eine Kopie des Objekts, für das sie aufgerufen wird.
Die Methode clone benötigt daher keine Parameter, liefert aber
ein mit den Attributwerten des ausführenden Objekts neu erzeugtes Objekt zurück.
Die Werte der Attribute von beiden Objekten sind gleich, die Objekte müssen aber sehr wohl
unterschieden werden.
Folie-259
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
weitere Methoden
public boolean equals( Fraction other )
{
return numerator == other.numerator & denominator == other.denominator;
}
Die Methode equals vergleicht die Werte von Zähler und Nenner von zwei Brüchen, um so
die Gleichheit festzustellen.
Stimmen die Werte überein, wird true zurückgegeben, sonst wird false zurückgegeben.
Da Brüche in der Klasse Fraction immer in gekürzer Form vorliegen, ist sichergestellt,
dass nur bei gleichen Attributwerten auch Brüche mit identischen Zahlenwert vorliegen.
Folie-260
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Zusammenfassung
Eine Klasse dient als Vorlage für Objekte,
die anhand der Deklaration der Klasse erzeugt werden.
Eine Klasse beschreibt ein semantisch zusammen gehörendes Konzept,
das an anderer Stelle bei der Entwicklung von Software wiederverwendet werden soll.
Eine Klasse enthält verschiedene Elemente: Attribute, Konstruktoren und Methoden.
Diese Elemente müssen mit Zugriffsrechten versehen werden:
– private Elemente können nur im Rumpf der Klasse genutzt werden, in der sie deklariert sind,
– öffentliche Elemente können in beliebigen anderen Klassen genutzt werden.
Zugriffsrechte dienen dazu, den korrekten Umgang bei der Benutzung der Elemente durch
Einschränkungen sicherzustellen.
Attribute dienen der (dauerhaften) Aufbewahrung von Werten,
die über die Ausführung einer Methode hinausgeht.
Konstruktoren bestimmen den Ablauf beim Erzeugen von Objekten und
sorgen insbesondere für die korrekte erste Belegung von Attributen mit Werten.
Methoden greifen auf die Werte der Attribute zu und führen Algorithmen damit aus.
Methoden liefern dabei Rückgabewerte oder manipulieren die Werte von Attributen.
Folie-261
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Rationale Zahlen» (Fortsetzung)
Zusammenfassung (Fortsetzung)
Methoden sollen immer die innere Konsistenz der Objekte erhalten.
Es kann mehrere Konstruktoren oder Methoden gleichen Namens geben,
die sich dann durch ihre Signaturen unterscheiden müssen.
Methoden können mit dem Dereferenzierungsoperator über den Namen eines
Objekts aufgerufen werden.
In Methoden einer Klasse kann mit dem Dereferenzierungsoperator über den Namen eines
Objekts der gleichen Klasse auch auf dessen private Elemente zugegriffen werden.
Das Zugriffsrecht private schränkt den Zugriff auf den Bereich innerhalb der
Deklaration einer Klasse ein.
Anmerkungen:
Statische Methoden können nicht auf (nicht-statische) Attribute eines Objekts zugreifen.
Statische Methoden können keine (nicht-statischen) Methoden eines Objekts aufrufen.
Folie-262
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Syntaxdiagramm zu Klassenrumpf
Da Attribute grundsätzlich wie Variablen deklariert werden,
können auch Attribute bei der Deklaration initialisiert werden.
Eine solche Initialisierung erfolgt vor der Ausführung der Anweisungen des Konstruktors.
Aus Gründen der Übersichtlichkeit sollte so eine Initialisierung aber nur dann erfolgen,
wenn kein Konstruktor deklariert wird.
Methodendeklaration
Klassenrumpf
Attributdeklaration
Attributdeklaration
Modifiziererliste Deklarationen
Konstruktordeklaration
Folie-263
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Syntaxdiagramm zu Konstruktor
Die Nebenbedingung, dass der Bezeichner eines Konstruktors dem Namen der Klasse
entsprechen muss, in der die Deklaration vorgenommen wird, lässt sich im
Syntaxdiagramm nicht ausdrücken.
( Parameterliste )
Konstruktorkopf Modifiziererliste Bezeichner
Konstruktordeklaration Konstruktorkopf Methodenrumpf
Folie-264
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Standardkonstruktor
Anmerkungen zu Konstruktoren:
In der Beispielklasse Fraction werden benutzt:
– Konstruktoren mit Parametern,
die den Attributen die als Argumente übergebenen Werte zuweisen
– der parameterlose Konstruktor,
der den Attributen feste Werte zuweist
Der parameterlose Konstruktor heißt Standardkonstruktor.
Default-Konstruktor:
Falls in einer Klasse überhaupt kein Konstruktor deklariert wird,
stellt eine solche Klasse implizit einen Standardkonstruktor als Default-Konstruktor bereit:
Der Default-Konstruktor legt ein Objekt der Klasse an und
initialisiert alle Attribute mit ihren typspezifischen Nullwerten.
public class SimpleClass
{
int att;
}
Der Aufruf new SimpleClass() ist erlaubt und
erzeugt ein Objekt, bei dem att mit dem Wert 0 initialisiert wird.
Folie-265
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Exkurs – main-Methode
Nun kann der Aufbau des Kopfes der main-Methode erklärt werden:
public static void main( String[] args )
Der Parameter args ist ein Feld, dessen Elemente Texte beinhalten.
Ein Java-Programm wird von einem Betriebssystem immer in folgender Form gestartet:
java className option1 option2 option3
java bezeichnet die Virtuelle Maschine (Folie 31).
className ist der Name der .class-Datei, die die main-Methode enthält.
option1, option2, option3 sind beliebige Texte,
die in dem Feld args anschließend in der main-Methode verfügbar sind.
Die Methode main ist als static deklariert,
damit sie ohne das Erzeugen eines Objekts aufgerufen werden kann.
Beim Aufruf über eine Entwicklungsumgebung hat args in der Regel die Länge 0.
Die meisten Entwicklungsumgebungen erwarten trotzdem eine Methode main mit der
vorgestellten Signatur als Einstiegspunkt in die Ausführung.
Hinweis: BlueJ erlaubt jedoch das einfache Ausführen beliebiger statischer Methoden.
Folie-266
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Vorlesung»
Entwicklung zweier Klassen, um das Konzept von Klasse und Objekt weiter zu verdeutlichen.
Ziel:
Definiere eine Klasse, die die Verwaltung einer Vorlesung mit diesen Eigenschaften realisiert:
Eine Vorlesung hat eine Bezeichnung und kennt die teilnehmenden Studierenden. *)
Eine Vorlesung hat eine Obergrenze für die Zahl der teilnehmenden Studierenden.
Eine Studierende hat einen Namen, ein Studienfach und eine Matrikelnummer. *)
*) Auf weitere Attribute wird verzichtet.
Folie-267
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Vorlesung» (Fortsetzung)
public class Lecture
{
private String title;
private Student[] students;
public Lecture( String t, int cap )
{
title = t;
students = new Student[cap];
}
}
Das Attribut students ist ein Feld, dessen Grundtyp die Referenz auf die Klasse Student ist.
Die Elemente des Feldes students sind also Referenzen auf Objekte der Klasse Student.
Der Wert des Parameters cap (capacity) wird direkt
zur Initialisierung der Größe des Feldes students verwendet.
Der Wert von cap muss daher nicht in einem eigenen Attribut abgelegt werden,
da er immer durch students.length ermittelt werden kann.
Attribut für den Veranstaltungsnamen
Attribut für die teilnehmenden Studierenden
Konstruktor
Folie-268
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Vorlesung» (Fortsetzung)
Anmerkungen:
Beim Erzeugen des Feldes students werden die Elemente
mit dem Wert null initialisiert, der eine Referenz auf kein Objekt anzeigt.
null ist ein Schlüsselwort.
Nach dem Erzeugen eines Objekts der Klasse Lecture liegt also folgende Situation vor:
Lecture dap1 = new Lecture( "DAP 1", 5 );
dap1
title "DAP 1"
students
nullnull nullnull null
Folie-269
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Vorlesung» (Fortsetzung)
«Anmelden» von Studierenden zur Vorlesung
Ziel:
Ein Objekt der Klasse Student soll in das Element des Feldes students mit dem kleinsten
Index eintragen werden, in dem der Wert null steht.
Falls die Vorlesung «voll» ist, das Feld students also kein Element mit dem Wert null
aufweist, soll nichts geschehen.
Die Methode soll anzeigen, ob das Eintragen erfolgreich war (oder nicht).
Implementierung der folgenden Methode:
public boolean add( Student s )
{
...
}
Folie-270
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Vorlesung» (Fortsetzung)
«Anmelden» von Studierenden zur Vorlesung
public boolean add( Student s )
{
for ( int i = 0; i < students.length; i++ )
{
if ( students[i] == null )
{
students[i] = s;
return true;
}
}
return false;
}
Die Konzeption und auch die Implementierung der Klasse Lecture können ohne detaillierte
Kenntnisse der Implementierung der Klasse Student erstellt werden, da in den bisher
betrachteten Methoden der Klasse Lecture keine Methoden der Klasse Student benötigt
werden.
Für das Compilieren der Klasse Lecture wird aber eine Implementierung der Klasse Student
benötigt.
Das Vorliegen von null kann in Bedingungen überprüft werden.
Überprüfen auf null
Folie-271
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Vorlesung» (Fortsetzung)
«Anmelden» von Studierenden zur Vorlesung
Analyse:
Solange keine Methode zum Löschen in der Klasse Lecture vorgesehen ist, ist die vorhandene
Implementierung der Methode add umständlich und ineffizient:
Obwohl nach jedem Einfügen klar ist, an welcher Position im Feld students das nächste
Einfügen stattfinden wird, erfolgt immer wieder eine Suche vom Beginn des Feldes aus.
Das Problem ist, das «Wissen» von einem Aufruf der Methode add zum nächsten Aufruf
dieser Methode zu übertragen.
Diese Aufgabe kann ein Attribut übernehmen, da der dort gespeicherte Wert über den Aufruf
einer Methode hinaus erhalten bleibt:
Das Attribut firstUnused soll die Position des ersten unbelegten Elements speichern,
also die Position, an der das nächste Student-Objekt abgelegt wird.
Attribute können also nicht nur Informationen speichern, die das Objekt beschreiben,
sondern auch Informationen, die die Arbeit der Methoden des Objekts unterstützen.
Anmerkung:
Nach außen wird das Austauschen der Implementierung der Methode nicht sichtbar:
Vor und nach der Änderung stellt die Klasse Lecture eine Methode add bereit.
Folie-272
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
weiteres Attribut
add ohne Schleife
Startwert setzen
Problemstellung «Vorlesung» (Fortsetzung)
«Anmelden»« von Studierenden zur Vorlesung (geänderte Implementierung)
public class Lecture
{
private String title;
private Student[] students;
private int firstUnused;
public Lecture( String t, int cap )
{
title = t;
students = new Student[cap];
firstUnused = 0;
}
public boolean add( Student s )
{
if ( firstUnused < students.length )
{
students[firstUnused] = s;
firstUnused++;
return true;
}
return false;
}
...
Folie-273
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Vorlesung» (Fortsetzung)
Klasse für Studierende
public class Student
{
private String name;
private String subject;
private int registrationNo;
public Student( String n, String sub, int no ) {
name = n;
subject = sub;
registrationNo = no;
}
public String toString() {
return "student: " + name +
", registration number: " + registrationNo +
"(" + subject + ")";
}
}
Folie-274
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Vorlesung» (Fortsetzung)
Erzeugen eines Objekts der Klasse Lecture:
Lecture dap1 = new Lecture( "DAP 1", 5 );
2 Studierende werden erzeugt und der Vorlesung hinzugefügt:
dap1.add( new Student( "C", "M", 17 ) );
dap1.add( new Student( "A", "Inf", 22 ) );
Visualisierung der Situation:
dap1
title "DAP 1"
students
nullnull null
name "C"
subject "M"
regNo 17
name "A"
subject "Inf"
regNo 22
firstUnused 2
Folie-275
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Vorlesung» (Fortsetzung)
Lecture dap1 = new Lecture( "DAP 1", 5 );
dap1.add( new Student( "C", "M", 17 ) );
dap1.add( new Student( "A", "Inf", 22 ) );
Lecture
dap1:Lecture
Student
:Student
add
Student
:Student
add
Folie-276
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Vorlesung» (Fortsetzung)
Erzeugen eines weiteren Studierenden:
Student s = new Student( "E", "M", 11 );
Hinzufügen dieses Studierenden:
dap1.add( s );
Visualisierung der Situation:
name "C"
subject "M"
regNo 17
name "A"
subject "Inf"
regNo 22 name "E"
subject "M"
regNo 11
s
dap1
students
nullnull
title "DAP 1"
firstUnused 3
Folie-277
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Vorlesung» (Fortsetzung)
Analyse
Dasselbe Objekt ist
sowohl über das Feld
als auch über die Variable s
erreichbar.
Der Aufruf dap1.add( s ) weist dem dritten Element des Feldes students die in der
Referenzvariablen s abgelegte Referenz zu.
Da die Referenz immer das gleiche Objekt erreicht, führen nun students[2] und s zum
gleichen Ziel.
Objekte werden also – wie auch Felder – bei einer Zuweisung
(an den Parameter der Methode add) nicht kopiert.
Nach einer Zuweisung unter Referenzvariablen ist das gleiche Objekt
über mehrere Variablen (students[2] und s) erreichbar.
students
name "E"
subject "M"
regNo 11
s
nullnull
Folie-278
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Referenzvariablen (Fortsetzung)
nach
Student t =
new Student( "E", "M", 11 );
dap1.add( t );
liegt die folgende Situation vor:
s ist eine Referenzvariable,
die das rote Objekt kennt.
students[2] ist eine Referenzvariable,
die das rote Objekt kennt.
s == students[2] vergleicht daher die in beiden Referenzvariablen gespeicherten Referenzen,
die das gleiche Objekt bezeichnen. Als Ergebnis wird daher true zurückgegeben.
Das blaue Objekt besitzt als Inhalte die gleichen Attributwerte wie das rote Objekt,
die aber, da es sich um eine eigenständges Objekt handelt, an einem anderen Ort liegen.
s == t vergleicht wieder die von den beiden Referenzvariablen gespeicherten Referenzen
die unterschiedliche Objekte bezeichnen. Als Ergebnis wird daher false zurückgegeben.
Sollen die Inhalte zweier Objekt miteinander verglichen werden, wird immer eine Methode
benötigt, die auf die Werte der Attribute zugreift und diese miteinander vergleicht.
students
name "E"
subject "M"
regNo 11
s
dap1
name "E"
subject "M"
regNo 11
t
Folie-279
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Vorlesung» (Fortsetzung)
Anmerkungen zum Wert null:
null ist keine Referenz auf ein Objekt, sondern ermöglicht es auszudrücken,
dass einer Referenzvariable kein Objekt zugeordnet ist.
Jede Referenzvariable kann den Wert null annehmen.
Sie verweist dann nicht auf ein Objekt.
Auf den Wert null kann der Dereferenzierungsoperator nicht angewandt werden,
da ja kein Objekt existiert, zu dem dereferenziert werden könnte.
Wird versucht, den Dereferenzierungsoperator auf den Wert null anzuwenden,
so wird eine Ausnahme der Klasse NullPointerException geworfen und damit
die Programmausführung abgebrochen.
Folie-280
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Vorlesung» (Fortsetzung)
get-Methoden für die Klasse Student
public String getName()
{
return name;
}
public String getSubject()
{
return subject;
}
public int getRegistrationNo()
{
return registrationNo;
}
Die get-Methoden für die Klasse Student erlauben einen Zugriff auf die Attributwerte,
ohne eine Möglichkeit zur Änderung zu geben.
Das schließt zufällige und unerwünschte Zuweisungen an die Attribute eines schon
erzeugten Objekts aus.
Folie-281
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Vorlesung» (Fortsetzung)
Vergleichsmethoden für die Klasse Student
public boolean hasGreaterNumber( Student s )
{
return getRegistrationNo() > s.getRegistrationNo();
}
Diese Methode erlaubt einen Größenvergleich von zwei Objekten der Klasse Student anhand
der Werte des Attributs registrationNo.
Nutzung:
Student s1 = new Student( “C”, “M”, 17 );
Student s2 = new Student( “A”, “Inf”, 22 );
if ( s1.hasGreaterNumber( s2 ) )
{ …
Der eine Operand für den Vergleich mit > wird durch das Attribut des ausführenden Objekts
gegeben, der zweite Operand durch das Attribut des als Argument an den Parameter
übergebenen Objekts.
Das Ergebnis entspricht der ausgesprochenen Notation:
true wird zurückgegeben, falls gilt: s1 has greater number (than) s2
Folie-282
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Vorlesung» (Fortsetzung)
Vergleichsmethoden für die Klasse Student
public boolean hasEqualNumber( Student s )
{
return getRegistrationNo() == s.getRegistrationNo();
}
Die Implementierung ist analog zu der der Methode hasGreaterNumber.
Folie-283
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Vorlesung» (Fortsetzung)
show-Methode für die Klasse Lecture
public void show()
{
System.out.println( “lecture: ” + title );
System.out.println( “participants:”);
for ( Student s : students )
{
if ( s != null )
{
System.out.println( s.toString() );
}
}
}
Die Methode show dient zur Unterstützung von Testläufen, da sich mit ihr der Inhalt aller mit
einer Vorlesung verbundenen Objekte einfach ausgeben läßt.
Die Methode show beinhaltet eine geeignete zeilenorientierte Formatierung durch println.
Folie-284
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse String, primitiver Typ char
String ist eine vordefinierte Klasse, die in Java immer zur Verfügung steht.
Java erlaubt deshalb eine besondere Form für die Erzeugung von String-Objekten
(Textliterale), die ohne den Aufruf eines Konstruktors auskommt:
String s = “hello”;
statt String s = new String ( … );
Die Beschreibung der Klasse String findet sich unter (siehe Folie 188):
http://docs.oracle.com/javase/8/docs/api/
Ein String-Objekt beinhaltet eine nicht änderbare Folge von Zeichen,
ein String-Objekt kann sich daher während der Ausführung nicht ändern.
Anmerkung:
Daher können String-Objekte mit gleichen Inhalten durch ein einziges Objekt mit diesem
Inhalt ersetzt werden. Das Laufzeitsystem nimmt solche Ersetzungen vor, um u.a. Speicherplatz
zu sparen.
Als Folge kann für Referenzvariablen der Klasse String ein Vergleich mit dem Operator ==
manchmal zu unerwarteten Ergebnissen führen. Zum Vergleich zweier String-Objekte sollte
immer eine Methode benutzt werden.
Folie-285
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse String, primitiver Typ char (Fortsetzung)
Ein einzelnes Zeichen wird in Java durch den Typ char repräsentiert.
Literale des Typs char werden in ‘ ‘ angegeben:
char c = ‘a’;
Der Typ char ist ein Teilbereich des Typs int:
Für jedes Zeichen aus char ist eine Abbildung auf einen Wert aus int definiert:
‘0’ 48
‘9’ 57
‘A’ 65
‘Z’ 90
‘a’ 97
‘z’ 122
char c1 = ‘1’;
char c2 = ‘A’;
char c3 = (char)(c1 + c2);
System.out.println( “c1: ” + c1 + “, c2: ” + c2 + “, c3: ” + c3 );
c1: 1, c2: A, c3: r
int-Addition
Folie-286
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse String, primitiver Typ char (Fortsetzung)
Konstruktoren (u.a.):
String()
Initializes a newly created String object so that it represents an empty character
sequence. *)
String( char[] value )
Allocates a new String so that it represents the sequence of characters currently
contained in the character array argument.
String( char[] value, int offset, int count )
Allocates a new String that contains characters from a subarray of the character array
argument.
String( String original )
Initializes a newly created String object so that it represents the same sequence of
characters as the argument; in other words, the newly created string is a copy of the
argument string.
*) Beschreibungen aus http://docs.oracle.com/javase/8/docs/api/
Folie-287
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse String, primitiver Typ char (Fortsetzung)
Methoden (u.a.):
char charAt( int index )
Returns the char value at the specified index.
int compareTo( String anotherString )
Compares two strings lexicographically.
int compareToIgnoreCase( String str )
Compares two strings lexicographically, ignoring case differences.
String concat( String str )
Concatenates the specified string to the end of this string.
int indexOf( int ch )
Returns the index within this string of the first occurrence of the specified character.
boolean isEmpty()
Returns true if, and only if, length() is 0.
Ergebnis ist int, um
>, < und ==
anzeigen zu können
Folie-288
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse String, primitiver Typ char (Fortsetzung)
Methoden (u.a.):
int lastIndexOf( int ch )
Returns the index within this string of the last occurrence of the specified character.
int length()
Returns the length of this string.
String replace( char oldChar, char newChar )
Returns a new string resulting from replacing all occurrences of oldChar in this string
with newChar.
String substring( int beginIndex, int endIndex )
Returns a new string that is a substring of this string.
char[] toCharArray()
Converts this string to a new character array.
String trim()
Returns a copy of the string, with leading and trailing whitespace omitted.
Folie-289
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Vorlesung» (Fortsetzung)
weitere Methode für die Klasse Student
public boolean hasGreaterName( Student s )
{
return getName().compareTo( s.getName() ) > 0;
}
public boolean hasEqualName( Student s )
{
return getName().compareTo( s.getName() ) == 0;
}
Diese Methoden erlauben einen Vergleich von zwei Objekten der Klasse Student
anhand der Werte des Attributs name.
Folie-290
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Vorlesung» (Fortsetzung)
Visualisierung der Objektstruktur
Lecture dap1 = new Lecture( “DAP 1”, 5 );
dap1.add( new Student( “C”, “M”, 17 ) );
dap1.add( new Student( “A”, “Inf”, 22 ) );
dap1.add( new Student( “E”, “M”, 11 ) );
dap1
title
students
nullnull
name
subject
regNo 17
name
subject
regNo 22 name
subject
regNo 11
“C”
“M”
“A”
“Inf”
“E”
“M”
“C”
“DAP 1”
firstUnused 3
Folie-291
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Vorlesung»
Anmerkung:
Die beiden Klassen Lecture und Student unterscheiden sich von der Klasse Fraction:
Die Attribute besitzen unterschiedliche Typen.
Objekte der Klasse Student können Attributwerte der Klasse Lecture sein.
Die Methoden beider Klassen berechnen keine neuen Attributwerte,
sondern speichern diese nur.
Alle Methoden der Klasse Student sind recht trivial.
Folie-292
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Vorlesung» (Fortsetzung)
Visualisierung der Klassenstruktur *)
Bedeutung von : kennt Objekt(e) «länger als nur für einen Methodenaufruf»
*) Notation: UML (Unified Modeling Language, Details in der Vorlesung Softwaretechnik)
Lecture
String
Student
Folie-293
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Gestaltung von Klassen (und Objekten)
Klassen sollen helfen, Programme übersichtlich und verständlich zu gestalten.
Eine Klasse sollte eine abgeschlossene Aufgabe erfüllen.
Die Namen von Klassen, Methoden, Attributen und Variablen sollten selbsterklärend sein:
– Klassennamen sind immer Substantive.
– Methodennamen sind immer Verben.
Die Sichtbarkeit von Attributen sollte als private deklariert werden.
Die Sichtbarkeit von Methoden sollten aufgrund ihrer Verwendung deklariert werden:
– Methoden, die außerhalb der Klasse nicht benötigt werden, sollten privat bleiben.
– Methoden, die außerhalb der Klasse benötigt werden,
müssen öffentlich gemacht werden.
Öffentliche Methoden sollen den Zugang zu den privaten Attributen kontrollieren.
Methoden können
– Attributwerte zurückgeben,
– Attributwerte setzen,
– Attributwerte manipulieren,
– Attributwerte zur Berechnung von Ergebnissen verwenden.
Konstruktoren sollten dafür sorgen, dass nur Objekte entstehen, die konzeptionell sinnvolle
Werte enthalten.
Folie-294
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Gestaltung von Klassen (und Objekten) (Fortsetzung)
Attribute können internes Wissen der Klasse speichern.
Das zeigen die Beispiele:
– Mit der Klasse Fraction wird ein bekannter mathematischer Datentyp realsiert,
der so in Java nicht verfügbar ist.
– Die Klassen Student und Lecture schaffen spezielle Datentypen, die genau auf eine
bestimmte Aufgabe zugeschnitten sind, die wir selbst vorher definiert haben.
Ziel der objektorientierten Softwareentwicklung mit Klassen und Objekten ist es,
situationsangemessene (abstrakte) Datentypen zu bestimmen, die Daten und die
darauf zulässigen Operationen zusammenfassen.
Die Deklaration einer Java-Klasse ist dann die Konkretisierung eines solchen Datentyps.
Daher sollen die Attribute einer Klasse als private deklariert werden,
so dass bei der Benutzung der Klasse nur die – durch Methoden realisierten – zulässigen
Operationen durchgeführt werden können.
Folie-295
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Vorlesung» (Fortsetzung)
Wie geht es weiter?
Sortieren der Studierenden einer Vorlesung nach
– Matrikelnummern oder
– Namen
Betrachtung verschiedener Sortieralgorithmen
Betrachtung des zum Sortieren notwendigen Aufwandes
Betrachtung von Sonderfällen wie einer bereits vorliegenden Sortierung
Folie-296
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Klasse und Objekt
(siehe Folie 200)
Nach Durcharbeiten des Kapitels Klasse und Objekt sollen
die teilnehmenden Studierenden
eine Klasse deklarieren können
in einer Klasse (Instanz-)Attribute anlegen können
in einer Klasse Konstruktoren anlegen können
in einer Klasse (Instanz-)Methoden anlegen können
Objekte einer Klasse erzeugen können
die Bedeutung von Referenzvariablen verstanden haben
Methoden eines Objekts über eine Referenzvariable aufrufen können
die Bedeutung des Wertes null kennen
mehrere Klassen durch Deklarationen und Aufrufe im Verbund arbeiten lassen können
die dabei entsehenden Klassen- und Objektstrukturen visualisieren können
die Klasse String nutzen können
Folie-297
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen, Algorithmen
und Programmierung 1 (DAP 1)
Fakultät für Informatik
Wintersemester 2019/20
Stefan Dissmann
Sortieralgorithmen
Folie-298
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Sortieralgorithmen
Nach Durcharbeiten des Kapitels Sortieralgorithmen sollen
die teilnehmenden Studierenden
den Sortieralgorithmus SelectionSort kennen
den Sortieralgorithmus InsertionSort kennen
den Sortieralgorithmus QuickSort kennen
grobe Analysen zur Laufzeit dieser Algorithmen erklären können
die O-Notation erklären und anwenden können
die Implementierungen der Algorithmen erklären können
den rekursiven Ansatz von QuickSort verstanden haben
Folie-299
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Auswählen» (Fortsetzung)
Ziel:
Die im Feld students eines Objekts der Klasse Lecture abgelegten Studierenden sollen
aufsteigend nach ihren Matrikelnummern sortiert werden.
Lösungsansatz über Analogie:
Wie würde man einen ungeordneten Stapel von Karteikarten von Studierenden sortieren?
Algorithmus Sortieren durch Auswählen (SelectionSort):
Suche im Ausgangsstapel die Karte mit der kleinsten Matrikelnummer heraus.
Lege mit dieser Karte einen neuen Stapel an: die bereits sortierten Karten.
Suche im Ausgangsstapel erneut die Karte mit der kleinsten Matrikelnummer heraus.
Lege diese Karte unter den Stapel der sortierten Karten.
Fahre mit diesen letzten beiden Schritten fort, bis der Ausgangsstapel abgearbeitet ist.
Folie-300
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Auswählen» (Fortsetzung)
Implementierung SelectionSort:
Es liegt bereits ein Feld students vor, das Platz für alle zu sortierenden Objekte besitzt.
students
belegter Teil des Feldes leer
firstUnused
Ausgangssituation:
Folie-301
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Auswählen» (Fortsetzung)
Implementierung SelectionSort:
Es liegt bereits ein Feld students vor, das Platz für alle zu sortierenden Objekte besitzt.
Es wird daher kein neues Feld für die sortierten Objekte angelegt, sondern im bestehenden Feld
students werden der sortierte und der unsortierte Teil unterschieden:
students
unsortierter Teil leer
firstUnused
Ausgangssituation:
Folie-302
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Auswählen» (Fortsetzung)
Implementierung SelectionSort:
Es liegt bereits ein Feld students vor, das Platz für alle zu sortierenden Objekte besitzt.
Es wird daher kein neues Feld für die sortierten Objekte angelegt, sondern im bestehenden Feld
students werden der sortierte und der unsortierte Teil unterschieden:
students
firstUnused
Ausgangssituation:
unsortierter Teil leer
students
MinimumMinimum bestimmen:
unsortierter Teil leer
Folie-303
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
students
firstUnused
students
Minimum
Ausgangssituation:
Minimum bestimmen:
unsortierter Teil leer
unsortierter Teil leer
Problemstellung «Sortieren durch Auswählen» (Fortsetzung)
Implementierung SelectionSort:
Es liegt bereits ein Feld students vor, das Platz für alle zu sortierenden Objekte besitzt.
Es wird daher kein neues Feld für die sortierten Objekte angelegt, sondern im bestehenden Feld
students werden der sortierte und der unsortierte Teil unterschieden:
students
Minimum wird zum
sortiertem Teil:
unsortierter Teil leersortierter Teil
Folie-304
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Auswählen» (Fortsetzung)
Implementierung SelectionSort:
Es liegt bereits ein Feld students vor, das Platz für alle zu sortierenden Objekte besitzt.
Es wird daher kein neues Feld für die sortierten Objekte angelegt, sondern im bestehenden Feld
students werden der sortierte und der unsortierte Teil unterschieden:
students
sortierter Teil unsortierter Teil leer
firstUnused
allgemeiner
Zwischenzustand:
Folie-305
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Auswählen» (Fortsetzung)
Implementierung SelectionSort:
Es liegt bereits ein Feld students vor, das Platz für alle zu sortierenden Objekte besitzt.
Es wird daher kein neues Feld für die sortierten Objekte angelegt, sondern im bestehenden Feld
students werden der sortierte und der unsortierte Teil unterschieden:
students
sortierter Teil unsortierter Teil leer
firstUnused
allgemeiner
Zwischenzustand:
students
MinimumMinimum bestimmen:
unsortierter Teil leersortierter Teil
Folie-306
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Auswählen» (Fortsetzung)
Implementierung SelectionSort:
Es liegt bereits ein Feld students vor, das Platz für alle zu sortierenden Objekte besitzt.
Es wird daher kein neues Feld für die sortierten Objekte angelegt, sondern im bestehenden Feld
students werden der sortierte und der unsortierte Teil unterschieden:
students
sortierter Teil unsortierter Teil leer
firstUnused
allgemeiner
Zwischenzustand:
students
MinimumMinimum bestimmen:
unsortierter Teil leersortierter Teil
students
unsortierter Teil leersortierter Teil
Minimum erweitert den
sortierten Teil:
Folie-307
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Auswählen» (Fortsetzung)
Implementierung SelectionSort:
Es liegt bereits ein Feld students vor, das Platz für alle zu sortierenden Objekte besitzt.
Es wird daher kein neues Feld für die sortierten Objekte angelegt, sondern im bestehenden Feld
students werden der sortierte und der unsortierte Teil unterschieden:
students
sortierter Teil unsortierter Teil leer
firstUnused
Endzustand:
Folie-308
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Auswählen» (Fortsetzung)
Implementierung SelectionSort:
Es liegt bereits ein Feld students vor, das Platz für alle zu sortierenden Objekte besitzt.
Es wird daher kein neues Feld für die sortierten Objekte angelegt, sondern im bestehenden Feld
students werden der sortierte und der unsortierte Teil unterschieden:
students
sortierter Teil unsortierter Teil leer
firstUnused
Endzustand:
students
Minimumletzter Wert
unsortierter Teil leersortierter Teil
ist Minimum:
Folie-309
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Auswählen» (Fortsetzung)
Implementierung SelectionSort:
Es liegt bereits ein Feld students vor, das Platz für alle zu sortierenden Objekte besitzt.
Es wird daher kein neues Feld für die sortierten Objekte angelegt, sondern im bestehenden Feld
students werden der sortierte und der unsortierte Teil unterschieden:
students
sortierter Teil unsortierter Teil leer
firstUnused
Endzustand:
students
Minimumletzter Wert
unsortierter Teil leersortierter Teil
students
leersortierter Teil
Minimum erweitert den
sortierten Teil:
ist Minimum:
Folie-310
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Auswählen» (Fortsetzung)
Implementierung SelectionSort:
Es liegt bereits ein Feld students vor, das Platz für alle zu sortierenden Objekte besitzt.
Es wird daher kein neues Feld für die sortierten Objekte angelegt, sondern im bestehenden Feld
students werden der sortierte und der unsortierte Teil unterschieden:
sortierter Teil unsortierter Teil leer
firstUnusedZwischenzustände
students
MinimumMinimum suchen
unsortierter Teil leersortierter Teil
students
unsortierter Teil leersortierter Teil
Vertauschen
herstellen
students
Folie-311
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Auswählen» (Fortsetzung)
Implementierung SelectionSort:
Es liegt bereits ein Feld students vor, das Platz für alle zu sortierenden Objekte besitzt.
Es wird daher kein neues Feld für die sortierten Objekte angelegt, sondern im bestehenden Feld
students werden der sortierte und der unsortierte Teil unterschieden:
Minimum suchen
Vertauschen
Methode void selectionSortByNumber()
Methode searchForMinimalNumber( int start )
Methode void swapStudents( int i, int j )
Zwischenzustände
herstellen
Folie-312
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Auswählen» (Fortsetzung)
public void selectionSortByNumber()
{
for ( int i = 0; i < firstUnused - 1; i++ )
{
int position = searchForMinimalNumber( i );
swapStudents( i, position );
}
}
Der letzte zu sortierende Eintrag muss nicht betrachtet werden,
da er immer sein eigenes Minimum bildet.
Die Methode searchForMinimalNumber gibt den Index des Student-Objekts mit der kleinsten
Matrikelnummer zurück.
Die Suche mit searchForMinimalNumber erfolgt im unsortierten Teil des Feldes students:
– Der unsortierte Teil beginnt bei Index i.
– Der unsortierte Teil endet bei Index firstUnused-1.
Vertauschen
letzten Eintrag nicht betrachten
Minimum suchen ab i
Folie-313
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Auswählen» (Fortsetzung)
private int searchForMinimalNumber( int start )
{
int selected = start;
for ( int i = start + 1; i < firstUnused; i++ )
{
if ( students[selected].hasGreaterNumber( students[i] ) )
{
selected = i;
}
}
return selected;
}
Die Methode searchForMinimalNumber gibt den Index zurück, an dem das Student-Objekt
mit der kleinsten Matrikelnummer innerhalb des unsortierten Teils des Feldes students steht.
Die Variable selected enthält nach jedem Durchlauf durch die Schleife den Index, an dem das
bis dahin gefundene Student-Objekt mit der kleinsten Matrikelnummer steht.
Folie-314
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Auswählen» (Fortsetzung)
private void swapStudents( int i, int j )
{
if ( i != j)
{
Student temp = students[i];
students[i] = students[j];
students[j] = temp;
}
}
Das Vertauschen der Inhalte von Elementen des Feldes students wird in verschiedenen
Methoden innerhalb der Klasse Lecture benötigt.
Daher wird dieses Vertauschen als eigenständige, private Methode realisiert.
Das Vertauschen von Inhalten von zwei Variablen oder Attributen erfordert immer den Einsatz
einer Hilfsvariablen, um durch Zwischenspeichern ein Überschreiben zu vermeiden.
Die Methode vermeidet das (unnütze) Vertauschen von Objekten an der gleichen Position.
Folie-315
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Auswählen» (Fortsetzung)
public void selectionSortByNumber()
{
for ( int i = 0; i < firstUnused - 1; i++ )
{
int position = searchForMinimalNumber( i );
swapStudents( i, position );
}
}
Analyse:
Wie häufig wird vertauscht (Aufruf der Methode swapStudents), wenn n Einträge vorliegen,
also firstUnused den Wert n hat?
n-1 -mal
Folie-316
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Auswählen» (Fortsetzung)
public void selectionSortByNumber()
{
for ( int i = 0; i < firstUnused - 1; i++ )
{
int position = searchForMinimalNumber( i );
swapStudents( i, position );
}
}
private int searchForMinimalNumber( int start )
{
int selected = start;
for ( int i = start + 1; i < firstUnused; i++ )
{
if ( students[selected].hasGreaterNumber( students[i] ) )
{
selected = i;
}
}
return selected;
}
Analyse:
Wie häufig wird die Methode hasGreaterNumber in der Methode searchForMinimalNumber
aufgerufen, wenn n Student-Objekte vorliegen, also firstUnused den Wert n hat?
n-1 + n-2 + ... + 1 = (n–1) . n/2 = n2/2–n/2 -mal
Folie-317
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Auswählen» (Fortsetzung)
public void selectionSortByNumber()
{
for ( int i = 0; i < firstUnused - 1; i++ )
{
int position = searchForMinimalNumber( i );
swapStudents( i, position );
}
}
private int searchForMinimalNumber( int start )
{
int selected = start;
for ( int i = start + 1; i < firstUnused; i++ )
{
if ( students[selected].hasGreaterNumber( students[i] ) )
{
selected = i;
}
}
return selected;
}
Analyse:
Hängt die Zahl der Vergleiche von der Verteilung der Werte in der Ausgangsfolge ab?
Nein, da die Schleifen beider Methoden immer vollständig durchlaufen werden.
Auch eine schon sortierte Folge erfordert n2/2–n/2 Vergleiche.
Folie-318
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Auswählen» (Fortsetzung)
Variation: Sortieren anhand der Namen der Studierenden
public void selectionSortByName()
{
for ( int i = 0; i < firstUnused - 1; i++ )
{
int position = searchForMinimalName( i );
swapStudents( i, position );
}
}
Algorithmus bleibt gleich,
nur die Suche erfolgt mit
einer anderen Methode
Folie-319
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Auswählen» (Fortsetzung)
Variation: Sortieren anhand der Namen der Studierenden
private int searchForMinimalName( int start )
{
int selected = start;
for ( int i = start + 1; i < firstUnused; i++ )
{
if ( students[selected].hasGreaterName( students[i] ) )
{
selected = i;
}
}
return selected;
}
Anmerkung: Es ist ungeschickt, den ganzen Code zu duplizieren, nur um das Sortierkriterium zu
ändern. Eine elegante Lösung zur Lösung dieser Problematik wird im Laufe späterer
Vorlesungen vorgestellt.
Algorithmus bleibt gleich,
nur Vergleich erfolgt mit
einer anderen Methode
Folie-320
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Abschätzung der Laufzeit
Analyseergebnis für selectionSort:
Zahl der Vertauschungen für n Elemente: n–1 also: f(n) = n–1
Zahl der Vergleiche für n Elemente: n2/2–n/2 also: g(n) = n2/2–n/2
Was ist die Aussage dieser beiden Funktionen?
Folie-321
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Abschätzung der Laufzeit (Fortsetzung)
Analyseergebnis für selectionSort:
Zahl der Vertauschungen für n Elemente: n-1 also: f(n) = n-1
Zahl der Vergleiche für n Elemente: n2/2-n/2 also: g(n) = n2/2-n/2
Was ist die Aussage dieser beiden Funktionen?
f(n) = n–1 f(n) ist Gerade mit gleichbleibender Steigung:
= gleichmäßiges Verschlechtern durch
weitere Elemente
Folie-322
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Abschätzung der Laufzeit (Fortsetzung)
Analyseergebnis für selectionSort:
Zahl der Vertauschungen für n Elemente: n-1 also: f(n) = n-1
Zahl der Vergleiche für n Elemente: n2/2-n/2 also: g(n) = n2/2-n/2
Was ist die Aussage dieser beiden Funktionen?
f(n) = n-1 f(n) ist Gerade mit gleichbleibender Steigung:
= gleichmäßiges Verschlechtern durch
weitere Elemente
g(n) = n2/2–n/2
g(n) ist Parabel mit zunehmender Steigung:
= zunehmendes Verschlechtern durch
weitere Elemente
Folie-323
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Abschätzung der Laufzeit (Fortsetzung)
Ideen für die Analyse der Laufzeit:
Es soll die Laufzeit von Algorithmen eingeordnet werden:
Das ist eine (abstrakte) qualitative Aussage, nicht eine Angabe für die Ausführungszeit.
Die Laufzeit dient insbesondere zur Unterscheidung und zum Vergleich von verschiedenen
Algorithmen zur Lösung des gleichen Problems.
Die konkrete Ausführungzeit hängt von der Ausführungsumgebung und insbesondere von der
verwendeten Hardware ab. Die konkrete Ausführungzeit wird nicht betrachtet.
Konstante Faktoren werden ignoriert.
Es wird die Laufzeit von f(n) für n betrachtet:
Dann ist das Wachstum von f(n) wesentlich. *)
Um Laufzeiten miteinander vergleichen zu können, werden Algorithmen
durch die Angabe sich ähnlich verhaltender einfacher Funktionen klassifiziert.
*) Falls n nicht gilt, muss die Aussage einer Analyse kritisch geprüft werden.
Folie-324
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Abschätzung der Laufzeit (Fortsetzung)
O-Notation:
O( f(n) ) = { g(n) | c>0, n0>0 n n0 : g(n) c
. f(n) } mit f(n)>0, g(n)>0
Hinweis:
O( f(n) ) ist eine Menge von Funktionen.
Interpretation:
g(n) O( f(n) ) bedeutet, dass ab einem n0 g(n) höchstens so stark wächst wie f(n).
Folie-325
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Abschätzung der Laufzeit (Fortsetzung)
O-Notation:
O( f(n) ) = { g(n) | c>0, n0>0 n n0 : g(n) c
. f(n) } mit f(n)>0, g(n)>0
Hinweis:
O( f(n) ) ist eine Menge von Funktionen.
Interpretation:
g(n) O( f(n) ) bedeutet, dass ab einem n0 g(n) höchstens so stark wächst wie f(n).
Beispiele:
10n O( n )
O( 10n ) O( n )
n2+10 O( n2 )
10n O( n2 )
n2 O( n )
O( n ) O( n2 )
Folie-326
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Abschätzung der Laufzeit (Fortsetzung)
Einordnung der Laufzeit von SelectionSort:
SelectionSort O( n2 )
da für f(n) = n2/2–n/2 gilt: f(n) O( n2 )
Folie-327
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Algorithmus «Sortieren durch Auswählen»
Idee des Sortierverfahrens «Sortieren durch Auswählen» (selection sort)
Während des Sortierens werden unterschieden:
– die Menge M der noch nicht sortierten Einheiten
– die Folge F der bereits sortierten Einheiten
In jedem Sortierschritt
– wird eine Einheit e mit vorgegebenen Eigenschaften in M gesucht,
– deren Position in F aufgrund der Eigenschaften feststeht.
Aufwändig ist also immer das Bestimmen von e,
während das Hinzufügen zu F einfach ist.
Folie-328
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Einfügen»
neuer Lösungsansatz über Analogie:
Wie würde man einen ungeordneten Stapel von Karteikarten von Studierenden sortieren?
Algorithmus Sortieren durch Einsetzen (InsertionSort):
Entferne aus dem Ausgangsstapel die erste Karte.
Lege mit dieser Karte einen neuen Stapel der sortierten Karten an.
Entferne aus dem Ausgangsstapel die erste Karte.
Sortiere diese Karte im Stapel der sortierten Karten an der richtigen Stelle ein.
Fahre mit diesen beiden Schritten fort, bis der Ausgangsstapel abgearbeitet ist.
Anmerkungen:
Dieser Algorithmus ist anders als SelectionSort.
Das Suchen des Minimums entfällt, dafür muss einsortiert werden.
Macht sich dieser Unterschied
in der Zahl der notwendigen Vergleiche und Vertauschungen bemerkbar?
Folie-329
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Einfügen» (Fortsetzung)
Implementierung InsertionSort:
Es liegt die gleiche Ausgangssituation wie bei SelectionSort vor.
students
firstUnused
Ausgangssituation:
unsortierter Teil leer
Folie-330
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Einfügen» (Fortsetzung)
Implementierung InsertionSort:
Es liegt die gleiche Ausgangssituation wie bei SelectionSort vor.
students
firstUnused
students
einzufügendes Objekt
Ausgangssituation:
Position zum Einfügen
unsortierter Teil leer
unsortierter Teil leer
bestimmen:
Folie-331
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Einfügen» (Fortsetzung)
Implementierung InsertionSort:
Es liegt die gleiche Ausgangssituation wie bei SelectionSort vor.
students
firstUnused
students
einzufügendes Objekt
Ausgangssituation:
Position zum Einfügen
unsortierter Teil leer
unsortierter Teil leer
bestimmen:
einzufügendes Objekt
students
Einfügen:
unsortierter Teil leersortierter Teil
Folie-332
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Einfügen» (Fortsetzung)
Implementierung InsertionSort:
Es liegt die gleiche Ausgangssituation wie bei SelectionSort vor.
students
sortierter Teil unsortierter Teil leer
firstUnused
allgemeiner
Zwischenzustand:
einzufügendes Objekt
Folie-333
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
students
Problemstellung «Sortieren durch Einfügen» (Fortsetzung)
Implementierung InsertionSort:
Es liegt die gleiche Ausgangssituation wie bei SelectionSort vor.
Position zum Einfügen:
students
sortierter Teil unsortierter Teil leer
firstUnused
allgemeiner
Zwischenzustand:
einzufügendes Objekt
einzufügendes Objekt
Folie-334
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
students
Einsortieren
(durch Verschieben):
Problemstellung «Sortieren durch Einfügen» (Fortsetzung)
Implementierung InsertionSort:
Es liegt die gleiche Ausgangssituation wie bei SelectionSort vor.
students
sortierter Teil unsortierter Teil leer
firstUnused
allgemeiner
Zwischenzustand:
einzufügendes Objekt
students
Position zum Einfügen: einzufügendes Objekt
Folie-335
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
students
Einsortieren
(durch Verschieben):
Problemstellung «Sortieren durch Einfügen» (Fortsetzung)
Implementierung InsertionSort:
Es liegt die gleiche Ausgangssituation wie bei SelectionSort vor.
students
sortierter Teil unsortierter Teil leer
firstUnused
allgemeiner
Zwischenzustand:
einzufügendes Objekt
einzufügendes Objekt
students
Position zum Einfügen: einzufügendes Objekt
Folie-336
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
students
Einsortieren
(durch Verschieben):
Problemstellung «Sortieren durch Einfügen» (Fortsetzung)
Implementierung InsertionSort:
Es liegt die gleiche Ausgangssituation wie bei SelectionSort vor.
students
sortierter Teil unsortierter Teil leer
firstUnused
allgemeiner
Zwischenzustand:
einzufügendes Objekt
students
Position zum Einfügen: einzufügendes Objekt
Folie-337
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
students
Einsortieren
(durch Verschieben):
Problemstellung «Sortieren durch Einfügen» (Fortsetzung)
Implementierung InsertionSort:
Es liegt die gleiche Ausgangssituation wie bei SelectionSort vor.
students
sortierter Teil unsortierter Teil leer
firstUnused
allgemeiner
Zwischenzustand:
einzufügendes Objekt
students
Position zum Einfügen: einzufügendes Objekt
Folie-338
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
students
Einsortieren
(durch Verschieben):
Problemstellung «Sortieren durch Einfügen» (Fortsetzung)
Implementierung InsertionSort:
Es liegt die gleiche Ausgangssituation wie bei SelectionSort vor.
students
sortierter Teil unsortierter Teil leer
firstUnused
allgemeiner
Zwischenzustand:
einzufügendes Objekt
students
Position zum Einfügen: einzufügendes Objekt
Folie-339
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
students
Einsortieren
(durch Verschieben):
Problemstellung «Sortieren durch Einfügen» (Fortsetzung)
Implementierung InsertionSort:
Es liegt die gleiche Ausgangssituation wie bei SelectionSort vor.
students
sortierter Teil unsortierter Teil leer
firstUnused
allgemeiner
Zwischenzustand:
einzufügendes Objekt
students
Position zum Einfügen: einzufügendes Objekt
Folie-340
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Einfügen
(durch Verschieben)
Problemstellung «Sortieren durch Einfügen» (Fortsetzung)
Implementierung InsertionSort:
Es liegt die gleiche Ausgangssituation wie bei SelectionSort vor.
Position zum Einfügen
allgemeiner
Zwischenzustand Methode void insertionSortByNumber()
Methode shiftStudentsByNumber( int start )
Folie-341
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Einfügen» (Fortsetzung)
public void insertionSortByNumber()
{
for ( int i = 1; i < firstUnused; i++ )
{
shiftStudentsByNumber( i );
}
}
Die Implementierung setzt unmittelbar den geplanten Algorithmus um.
Folie-342
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Einfügen» (Fortsetzung)
private void shiftStudentsByNumber( int start )
{
Student toInsert = students[start];
int i = start;
while ( i > 0 && students[i – 1].hasGreaterNumber( toInsert ) )
{
students[i] = students[i – 1];
i–;
}
students[i] = toInsert;
}
Die Implementierung setzt unmittelbar den geplanten Algorithmus um.
Folie-343
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Einfügen» (Fortsetzung)
private void shiftStudentsByNumber( int start )
{
Student toInsert = students[start];
int i = start;
while ( i > 0 && students[i – 1].hasGreaterNumber( toInsert ) )
{
students[i] = students[i – 1];
i–;
}
students[i] = toInsert;
}
Short-Cut-Evaluation der logischen Operatoren && und || :
Die Auswertung des linken Operanden erfolgt
immer vor der Auswertung des rechten Operanden.
Die Auswertung bricht ab, sobald das Ergebnis der Auswertung feststeht:
– Konjunktion mit &&-Operator: linker Operand ist false
– Disjunktion mit ||-Operator: linker Operand ist true
daher im Beispiel:
für i==0 wird der dann fehlerhafte Zugriff students[-1] nicht mehr ausgeführt
UND-Operator
(Short-Cut-Evaluation)
Folie-344
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Einfügen» (Fortsetzung)
public void insertionSortByNumber()
{
for ( int i = 1; i < firstUnused; i++ )
{
shiftStudentsByNumber( i );
}
}
private void shiftStudentsByNumber( int start )
{
Student toInsert = students[start];
int i = start;
while ( i > 0 && students[i – 1].hasGreaterNumber( toInsert ) )
{
students[i] = students[i – 1];
i–;
}
students[i] = toInsert;
}
Analyse:
Wie häufig wird die Methode hasGreaterNumber aufgerufen, wenn n Einträge vorliegen?
maximal: n–1 + n–2 + … + 1 = (n–1) . n/2 = n2/2–n/2 -mal
minimal: n–1 -mal (falls die Einträge schon sortiert vorliegen)
durchschnittlich: dazwischen
Folie-345
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Einfügen» (Fortsetzung)
public void insertionSortByNumber()
{
for ( int i = 1; i < firstUnused; i++ )
{
shiftStudentsByNumber( i );
}
}
private void shiftStudentsByNumber( int start )
{
Student toInsert = students[start];
int i = start;
while ( i > 0 && students[i – 1].hasGreaterNumber( toInsert ) )
{
students[i] = students[i – 1];
i–;
}
students[i] = toInsert;
}
Analyse:
Wie häufig wird umkopiert, wenn n Einträge vorliegen?
maximal: n–1 + n–2 + … + 1 = (n–1) . n/2 = n2/2–n/2 -mal
minimal: 0 -mal (falls Einträge bereits sortiert vorliegen)
durchschnittlich: dazwischen
Folie-346
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren durch Einfügen» (Fortsetzung)
Variation: Sortieren anhand der Namen der Studierenden
private void shiftStudentsByNumber( int start )
{
Student toInsert = students[start];
int i = start;
while ( i > 0 && students[i – 1].hasGreaterNumber( toInsert ) )
{
students[i] = students[i – 1];
i–;
}
students[i] = toInsert;
}
Anmerkung:
Bei InsertionSort werden gleiche Objekte in der Reihenfolge einsortiert,
in der sie in der Ausgangsfolge auftreten:
Das Sortierverfahren verhält sich stabil.
Studierende mit dem gleichen Namen werden also in ihrer Reihenfolge nicht geändert.
stoppt bei
Gleichheit
Folie-347
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung «Sortieren der Studierenden einer Vorlesung»
Vergleich der Algorithmen SelectionSort und InsertionSort:
SelectionSort InsertionSort
bei n zu sortierenden Einträgen:
maximale Zahl an Vergleichen n2 *) n2
durchschnittliche Zahl an Vergleichen n2 ?
minimale Zahl an Vergleichen n2 n–1 also n
maximale Zahl an Zuweisungen =n–1 also n n2
durchschnittliche Zahl an Zuweisungen =n–1 also n ?
minimale Zahl an Zuweisungen =n–1 also n
Reihenfolge gleicher Elemente nicht stabil **) stabil
Speicherbedarf in situ ***) in situ
*) Beispiel zur Verdeutlichung: n = 100 000 n2 = 10 000 000 000
**) Die Position der in den unsortierten Teil getauschten Objekte ist zufällig.
***) in situ (lat.) = am (Ursprungs-)Ort, d.h. es wird in dem vorhandenen Feld sortiert
Folie-348
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Algorithmus «Sortieren durch Einfügen»
Idee des Sortierverfahrens «Sortieren durch Einfügen» (insertion sort)
Während des Sortierens werden unterschieden:
– die Menge M der noch nicht sortierten Einheiten
– die Folge F der bereits sortierten Einheiten
In jedem Sortierschritt
– wird eine beliebige Einheit e aus M genommen,
– für die die Position in F aufgrund ihrer Eigenschaften bestimmt wird.
Einfach ist also immer das Bestimmen von e,
während das Hinzufügen zu F aufwändig ist.
Folie-349
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beschleunigung des Sortierens
Feststellung:
Wenn die Zahl der Vergleiche/Zuweisungen sich quadratisch bezüglich der Anzahl der zu
sortierenden Elemente verhält, dann wird das Sortieren großer Datenmengen sehr aufwändig.
Überlegung:
Man könnte den Aufwand reduzieren, wenn man die zu sortierenden Datenmengen geschickt
aufteilt, die Teile sortiert und die sortierten Teile zusammenfügt.
Eine grobe Abschätzung, die die Idee verdeutlichen soll:
Das Sortieren von n Einträgen erfordert etwa n2/2 Operationen.
Das Sortieren von 2 Teilen mit je n/2 Einträgen erfordert 2 . (n/2)2/2 = n2/4 Operationen.
Das Sortieren von 4 Teilen mit je n/4 Einträgen erfordert 4 . (n/4)2/2 = n2/8 Operationen.
…
Voraussetzung:
Das Aufteilen und das Zusammenfügen darf selbst nicht aufwändig sein.
Folie-350
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort»
Ziel:
Das Sortieren soll folgendermaßen realisiert werden:
– die zu sortierenden Elemente werden in eine Menge mit den kleineren und eine Menge mit den
größeren Elementen aufgeteilt,
– für beide Mengen wird dieses Verfahren solange erneut angewendet, bis die zu sortierenden
Teilmengen nur noch aus einem Element bestehen (und damit sortiert sind) und
– alle Teilmengen werden so zusammengesetzt, dass die sortierten kleineren vor den sortierten
größeren Elementen stehen.
Diese Art des Sortierens heißt QuickSort, da so tatsächlich relativ schnell sortiert werden kann. *)
*) Grundidee zu QuickSort stammt von C.A.R. Hoare, 1962
Folie-351
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Beispiel
Sei diese Folge von Matrikelnummern von Studierenden gegeben:
28 19 4 12 17 3 9 11 1 7
Daraus entstehen durch Aufteilen in kleine und große Werte:
4 3 9 1 7 und 28 19 12 17 11
und durch weiteres Aufteilen:
4 3 1 und 9 7 und 12 17 11 und 28 19
und:
1 | 4 3 | 7 | 9 | 12 11 | 17 | 19 | 28
und:
1 | 3 | 4 | 7 | 9 | 11 | 12 | 17 | 19 | 28
Folie-352
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Anmerkungen:
Das Beispiel zeigt:
Sortieren ist möglich durch ein wiederholtes Aufteilen
in Folgen mit größeren und kleineren Elementen.
Problem: Voraussetzung für das Bestimmen gleichmächtiger Folgen ist eine
vorliegende Sortierung (– die erst erzeugt werden soll).
Lösung: Es wird ein geeignetes Pivot-Element p ausgewählt
anhand dessen eine Folge zerlegt wird in
eine Folge mit Elementen, die kleiner als p sind, und
eine Folge von Elementen, die größer oder gleich p sind.
Das Zusammenfügen der Teile ist einfach,
wenn der Algorithmus innerhalb eines Feldes arbeitet:
Die Teile sind nur Abschnitte des Feldes,
in denen verschoben wird,
in ihrer Gesamtheit aber immer zusammen bleiben.
Methode
groupByNumber
Folie-353
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Anmerkungen:
Es wird ein geeignetes Pivot-Element p ausgewählt
anhand dessen eine Folge zerlegt wird in
eine Folge mit Elementen, die kleiner als p sind, und
eine Folge von Elementen, die größer oder gleich p sind.
Möglichkeiten zur Auswahl des Pivot-Elements sind zum Beispiel:
– ein zufällig gewähltes Element
– ein Element an immer der gleichen festen Position
– mehrere Elemente, von denen das mit dem mittleren Wert gewählt wird.
Folie-354
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Entscheidungen für die hier folgende Implementierung:
Auswahl des Pivot-Elements:
Das Element an der letzten Position des betrachteten Abschnitts des Feldes wird gewählt.
Zuordnung des Pivot-Elements:
Das Pivot-Element wird in den Teil mit den größeren Elementen eingeordnet.
Folie-355
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
private void groupByNumber( int leftBound, int rightBound )
{
– anhand des Pivot-Elements in Teilfolgen zerlegen
– Algorithmus auf Teilfolgen anwenden
}
Die Parameter geben den kleinsten (leftBound) und den größten (rightBound) Index
eines Ausschnitts des Feldes students an, der mit der Methode bearbeitet werden soll.
Die Methode ist privat, da außerhalb der Klasse Lecture das Feld unbekannt ist und damit eine
Angabe von Indizes sinnvoll nicht erfolgen kann.
Grenzen der
Ausgangsfolge
Folie-356
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
private void groupByNumber( int leftBound, int rightBound )
{
if ( leftBound < rightBound )
{
– anhand des Pivot-Elements in Teilfolgen zerlegen
– Algorithmus auf Teilfolgen anwenden
}
}
Die Idee für das Zerlegen in Teilfolgen ist:
mindestens zwei
Elemente müssen
sortiert werden
students
Teilfolge der unsortierter Teil
Vergleich
kleineren
Elemente
Teilfolge der
größer-gleichen
Elemente
Pivot-
Element
Folie-357
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
falls students[candidate] kleiner als students[rightBound] ist,
muss die Teilfolge der kleineren Elemente verlängert werden:
students
Teilfolge der unsortierter Teil
Vergleich
kleineren
Elemente
Teilfolge der
größer-gleichen
Elemente
Pivot-
Element
leftBound candidate
leftOfGreaterPart
rightBound
students
Teilfolge der unsortierter Teil
Austausch
kleineren
Elemente
Teilfolge der
größer-gleichen
Elemente
Pivot-
Element
leftBound candidate
leftOfGreaterPart
rightBound
Folie-358
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
falls students[candidate] größer als oder gleich students[rightBound] ist,
muss die Teilfolge der größer-gleichen Elemente verlängert werden:
students
Teilfolge der unsortierter Teil
Vergleich
kleineren
Elemente
Teilfolge der
größer-gleichen
Elemente
Pivot-
Element
leftBound candidate
leftOfGreaterPart
rightBound
students
Teilfolge der unsortierter Teil
kleineren
Elemente
Teilfolge der
größer-gleichen
Elemente
Pivot-
Element
leftBound candidate
leftOfGreaterPart
rightBound
Folie-359
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Endsituation der Aufteilung:
Das Pivot-Element kann durch Austausch einsortiert werden, da das Pivot-Element
immer der kleinste Wert in der Teilfolge der größer-gleichen Elemente ist:
students
Teilfolge der
kleineren Elemente
Teilfolge der
größer-gleichen Elemente
Pivot-
Element
leftBound candidateleftOfGreaterPart rightBound
students
Teilfolge der
kleineren Elemente
Teilfolge der
größer-gleichen Elemente
Pivot-
Element
leftBound leftOfGreaterPart rightBound
Austausch
Folie-360
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Fortsetzung:
Algorithmus anwenden auf den Bereich leftBound ... leftOfGreaterPart-1
Algorithmus anwenden auf den Bereich leftOfGreaterPart+1 ... rightBound
Das Pivot-Element liegt an der Position leftOfGreaterPart genau an der Position, an der es
in der sortierten Folge stehen muss. Es muss daher nicht weiter betrachtet werden.
students
Teilfolge der
kleineren Elemente
Teilfolge der
größer-gleichen Elemente
leftBound leftOfGreaterPart rightBound
leftOfGreaterPart+1leftOfGreaterPart-1
Folie-361
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
private void groupByNumber( int leftBound, int rightBound )
{
if ( leftBound < rightBound )
{
int candidate = leftBound;
int leftOfGreaterPart = leftBound;
– anhand des Pivot-Elements in Teilfolgen zerlegen
– Algorithmus auf Teilfolgen anwenden
}
}
mindestens zwei
Elemente müssen
sortiert werden
students
unsortierter Teil Pivot-
Element
leftBound candidate
leftOfGreaterPart
rightBound
Folie-362
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Beispiel für die Zerlegung der bekannten Folge von Matrikelnummern von Studierenden gegeben:
28 19 4 12 17 3 9 11 1 7
Dann wird das Student-Objekt mit der Matrikelnummer 7 als Pivot-Element genutzt.
Nun wird gesucht:
28 19 4 12 17 3 9 11 1 7 rightBound (Pivot-Element)
und getauscht: leftOfGreaterPart
4 19 28 12 17 3 9 11 1 7 candidate
und gesucht:
4 19 28 12 17 3 9 11 1 7
und getauscht:
4 3 28 12 17 19 9 11 1 7
und gesucht:
4 3 28 12 17 19 9 11 1 7
und getauscht:
4 3 1 12 17 19 9 11 28 7 alle Vergleiche sind vorgenommen
und Pivot-Element einsortiert:
4 3 1 7 17 19 9 11 28 12 Aufteilung ist abgeschlossen
Folie-363
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
private void groupByNumber( int leftBound, int rightBound )
{
if (leftBound < rightBound )
{
int leftOfGreaterPart = leftBound;
for ( int candidate = leftBound; candidate < rightBound; candidate++ )
{
if ( students[rightBound].hasGreaterNumber( students[candidate] ) )
{
swapStudents( candidate, leftOfGreaterPart );
leftOfGreaterPart++;
}
}
swapStudents( leftOfGreaterPart, rightBound );
groupByNumber( leftBound, leftOfGreaterPart - 1 );
groupByNumber( leftOfGreaterPart + 1 , rightBound );
}
}
es müssen noch Elemente
verteilt werden
Folie-364
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
private void groupByNumber( int leftBound, int rightBound )
{
if (leftBound < rightBound )
{
int leftOfGreaterPart = leftBound;
for ( int candidate = leftBound; candidate < rightBound; candidate++ )
{
if ( students[rightBound].hasGreaterNumber( students[candidate] ) )
{
swapStudents( candidate, leftOfGreaterPart );
leftOfGreaterPart++;
}
}
swapStudents( leftOfGreaterPart, rightBound );
groupByNumber( leftBound, leftOfGreaterPart - 1 );
groupByNumber( leftOfGreaterPart + 1 , rightBound );
}
}
betrachtetes Element ist
Vertauschen in den Teil
kleiner als das Pivot-Element
der kleineren Elemente
Folie-365
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
private void groupByNumber( int leftBound, int rightBound )
{
if (leftBound < rightBound )
{
int leftOfGreaterPart = leftBound;
for ( int candidate = leftBound; candidate < rightBound; candidate++ )
{
if ( students[rightBound].hasGreaterNumber( students[candidate] ) )
{
swapStudents( candidate, leftOfGreaterPart );
leftOfGreaterPart++;
}
}
swapStudents( leftOfGreaterPart, rightBound );
groupByNumber( leftBound, leftOfGreaterPart - 1 );
groupByNumber( leftOfGreaterPart + 1 , rightBound );
}
}
Pivot-Element wird zwischen
die Teile verschoben
Folie-366
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
private void groupByNumber( int leftBound, int rightBound )
{
if (leftBound < rightBound )
{
int leftOfGreaterPart = leftBound;
for ( int candidate = leftBound; candidate < rightBound; candidate++ )
{
if ( students[rightBound].hasGreaterNumber( students[candidate] ) )
{
swapStudents( candidate, leftOfGreaterPart );
leftOfGreaterPart++;
}
}
swapStudents( leftOfGreaterPart, rightBound );
groupByNumber( leftBound, leftOfGreaterPart - 1 );
groupByNumber( leftOfGreaterPart + 1 , rightBound );
}
}
Pivot-Element wird zwischen
die Teile verschoben
eventuell gilt
leftOfGreaterPart==rightBound:
Dann wird nicht getauscht.
Folie-367
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
private void groupByNumber( int leftBound, int rightBound )
{
if (leftBound < rightBound )
{
int leftOfGreaterPart = leftBound;
for ( int candidate = leftBound; candidate < rightBound; candidate++ )
{
if ( students[rightBound].hasGreaterNumber( students[candidate] ) )
{
swapStudents( candidate, leftOfGreaterPart );
leftOfGreaterPart++;
}
}
swapStudents( leftOfGreaterPart, rightBound );
groupByNumber( leftBound, leftOfGreaterPart - 1 );
groupByNumber( leftOfGreaterPart + 1 , rightBound );
}
}
Teilfolgen anwenden
Algorithmus auf
Folie-368
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
private void groupByNumber( int leftBound, int rightBound )
{
if (leftBound < rightBound )
{
int leftOfGreaterPart = leftBound;
for ( int candidate = leftBound; candidate < rightBound; candidate++ )
{
if ( students[rightBound].hasGreaterNumber( students[candidate] ) )
{
swapStudents( candidate, leftOfGreaterPart );
leftOfGreaterPart++;
}
}
swapStudents( leftOfGreaterPart, rightBound );
groupByNumber( leftBound, leftOfGreaterPart - 1 );
groupByNumber( leftOfGreaterPart + 1 , rightBound );
}
}
«kleine Matrikelnummern»
«große Matrikelnummern»
Folie-369
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Aufruf der Methode groupByNumber
im Rumpf der (eigenen) Deklaration von groupByNumber
Geht das überhaupt?
Ja, weil
für jeden Aufruf eigene Speicherbereiche für die Parameter
leftBound und rightBound angelegt werden und
für jeden Aufruf eigene Speicherbereiche für die lokalen Variablen
leftOfGreaterPart und candidate angelegt werden.
Das Konzept des Selbstaufrufs einer Methode heißt Rekursion.
Folie-370
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Beispiel – Überblick:
Studierende einer Vorlesung (unsortiert) im Feld students:
student: A, registration number: 11(Inf)
student: C, registration number: 3(M)
student: B, registration number: 14(Inf)
student: B, registration number: 8(M)
student: B, registration number: 22(Inf)
student: D, registration number: 19(Ph)
student: F, registration number: 4(Inf)
student: E, registration number: 7(Inf)
Folie-371
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Beispiel – Überblick:
Studierende einer Vorlesung (unsortiert) im Feld students:
student: A, registration number: 11(Inf)
student: C, registration number: 3(M)
student: B, registration number: 14(Inf)
student: B, registration number: 8(M)
student: B, registration number: 22(Inf)
student: D, registration number: 19(Ph)
student: F, registration number: 4(Inf)
student: E, registration number: 7(Inf)
groupByNumber(0,7)
groupByNumber(0,1)
groupByNumber(0,0)
groupByNumber(2,1)
Folie-372
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Beispiel – Überblick:
Studierende einer Vorlesung (unsortiert) im Feld students:
student: A, registration number: 11(Inf)
student: C, registration number: 3(M)
student: B, registration number: 14(Inf)
student: B, registration number: 8(M)
student: B, registration number: 22(Inf)
student: D, registration number: 19(Ph)
student: F, registration number: 4(Inf)
student: E, registration number: 7(Inf)
Aufrufe: groupByNumber( 0, 7 )
groupByNumber( 0, 1 )
groupByNumber( 0, 0 )
groupByNumber( 2, 1 )
groupByNumber( 3, 7 )
groupByNumber( 3, 4 )
groupByNumber( 3, 3 )
groupByNumber( 5, 4 )
groupByNumber( 6, 7 )
groupByNumber( 6, 5 )
groupByNumber( 7, 7 )
Folie-373
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Beispiel – 1. Aufruf: groupByNumber( 0, 7 )
Studierende einer Vorlesung im Feld students:
student: A, registration number: 11(Inf)
student: C, registration number: 3(M)
student: B, registration number: 14(Inf)
student: B, registration number: 8(M)
student: B, registration number: 22(Inf)
student: D, registration number: 19(Ph)
student: F, registration number: 4(Inf)
student: E, registration number: 7(Inf)
Aufruf von groupByNumber( 0, 7 ) führt zu:
student: C, registration number: 3(M)
student: F, registration number: 4(Inf)
student: E, registration number: 7(Inf)
student: B, registration number: 8(M)
student: B, registration number: 22(Inf)
student: D, registration number: 19(Ph)
student: A, registration number: 11(Inf)
student: B, registration number: 14(Inf)
Pivot-Element
Folie-374
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Beispiel – 2. Aufruf: groupByNumber( 0, 1 )
Studierende einer Vorlesung im Feld students:
student: C, registration number: 3(M)
student: F, registration number: 4(Inf)
student: E, registration number: 7(Inf)
student: B, registration number: 8(M)
student: B, registration number: 22(Inf)
student: D, registration number: 19(Ph)
student: A, registration number: 11(Inf)
student: B, registration number: 14(Inf)
Aufruf von groupByNumber( 0, 1 ) führt zu:
student: C, registration number: 3(M)
student: F, registration number: 4(Inf)
student: E, registration number: 7(Inf)
student: B, registration number: 8(M)
student: B, registration number: 22(Inf)
student: D, registration number: 19(Ph)
student: A, registration number: 11(Inf)
student: B, registration number: 14(Inf)
Pivot-Element
richtig positioniert
Folie-375
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Beispiel – 5. Aufruf: groupByNumber( 3, 7 ) *)
Studierende einer Vorlesung im Feld students:
student: C, registration number: 3(M)
student: F, registration number: 4(Inf)
student: E, registration number: 7(Inf)
student: B, registration number: 8(M)
student: B, registration number: 22(Inf)
student: D, registration number: 19(Ph)
student: A, registration number: 11(Inf)
student: B, registration number: 14(Inf)
Aufruf von groupByNumber( 3, 7 ) führt zu:
student: C, registration number: 3(M)
student: F, registration number: 4(Inf)
student: E, registration number: 7(Inf)
student: B, registration number: 8(M)
student: A, registration number: 11(Inf)
student: B, registration number: 14(Inf)
student: B, registration number: 22(Inf)
student: D, registration number: 19(Ph)
*) Die Aufrufe groupByNumber( 0, 0 ) und groupByNumber( 2, 1 ) führen zu keinen Änderungen.
Pivot-Element
richtig positioniert
richtig positioniert
richtig positioniert
Folie-376
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Beispiel – 6. Aufruf: groupByNumber( 3, 4 )
Studierende einer Vorlesung im Feld students:
student: C, registration number: 3(M)
student: F, registration number: 4(Inf)
student: E, registration number: 7(Inf)
student: B, registration number: 8(M)
student: A, registration number: 11(Inf)
student: B, registration number: 14(Inf)
student: B, registration number: 22(Inf)
student: D, registration number: 19(Ph)
Aufruf von groupByNumber( 3, 4 ) führt zu:
student: C, registration number: 3(M)
student: F, registration number: 4(Inf)
student: E, registration number: 7(Inf)
student: B, registration number: 8(M)
student: A, registration number: 11(Inf)
student: B, registration number: 14(Inf)
student: B, registration number: 22(Inf)
student: D, registration number: 19(Ph)
Pivot-Element
richtig positioniert
richtig positioniert
richtig positioniert
richtig positioniert
Folie-377
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Beispiel – 9. Aufruf: groupByNumber( 6, 7 ) *)
Studierende einer Vorlesung im Feld students:
student: C, registration number: 3(M)
student: F, registration number: 4(Inf)
student: E, registration number: 7(Inf)
student: B, registration number: 8(M)
student: A, registration number: 11(Inf)
student: B, registration number: 14(Inf)
student: B, registration number: 22(Inf)
student: D, registration number: 19(Ph)
Aufruf von groupByNumber( 6, 7 ) führt zu:
student: C, registration number: 3(M)
student: F, registration number: 4(Inf)
student: E, registration number: 7(Inf)
student: B, registration number: 8(M)
student: A, registration number: 11(Inf)
student: B, registration number: 14(Inf)
student: D, registration number: 19(Inf)
student: B, registration number: 22(Ph)
*) Der 7. und 8. Aufruf führen nicht zu Änderungen.
Pivot-Element
richtig positioniert
richtig positioniert
richtig positioniert
richtig positioniert
richtig positioniert
richtig positioniert
Folie-378
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Beispiel:
Analyse des Beispieldurchlaufs:
11 Aufrufe, davon 5 mit Bestimmung eines Pivot-Elements
6 Vertauschungen
Aufrufbaum:
groupByNumber(0,7)
groupByNumber(0,1)
groupByNumber(2,1)
groupByNumber(3,7)
groupByNumber(0,0) groupByNumber(6,7)groupByNumber(3,4)
groupByNumber(5,4)groupByNumber(3,3) groupByNumber(7,7)groupByNumber(6,5)
Folie-379
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Wie kann eine Analyse eines konkreten Durchlaufes erfolgen?
Durch geeignete Instrumentierung des Programmcodes:
Einbau von Testausgaben
Einbau von Zählern
private int countCalls;
...
private void groupByNumber( int leftBound, int rightBound )
{
countCalls++;
System.out.println( "groupByNumber( " + leftBound + ", " + rightBound + " )" );
...
}
Folie-380
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Analyse des Algorithmus:
Laufzeit – Sonderfall aufsteigend sortierte Eingabe:
Es wird in jedem rekursiven Aufruf das größte Element als Pivot-Element gewählt und daher
in jedem rekursiven Aufruf nur ein Element abgetrennt.
Dabei müssen aber alle restlichen Elemente überprüft – also mit dem Pivot-Element
verglichen – werden.
Bei n zu sortierenden Einträgen ergibt sich für Vergleiche die Größenordnung: n2
Es müssen aber keine Elemente vertauscht werden, da die Sortierung schon vorliegt.
Bei n zu sortierenden Einträgen ergibt sich für Vertauschungen: 0
Folie-381
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Analyse des Algorithmus:
Laufzeit – Sonderfall aufsteigend sortierte Eingabe:
Es wird in jedem rekursiven Aufruf das größte Element als Pivot-Element gewählt und daher
in jedem rekursiven Aufruf nur ein Element abgetrennt. Dabei müssen alle restlichen Elemente
überprüft – also mit dem Pivot-Element verglichen – werden.
Bei n zu sortierenden Elementen ergibt sich für Aufrufe die Größenordnung: . n
Bei n zu sortierenden Elementen ergibt sich für Vergleiche die Größenordnung: n2
Es müssen aber keine Elemente vertauscht werden, da die Sortierung schon vorliegt.
Bei n zu sortierenden Elementen ergibt sich für Vertauschungen: 0
Laufzeit – Sonderfall absteigend sortierte Eingabe:
Es wird in jedem rekursiven Aufruf das kleinste Element als Pivot-Element gewählt und daher
in jedem rekursiven Aufruf nur ein Element abgetrennt. Dabei müssen alle restlichen Elemente
überprüft – also mit dem Pivot-Element verglichen – werden.
Bei n zu sortierenden Elementen ergibt sich für Aufrufe die Größenordnung: . n
Bei n zu sortierenden Elementen ergibt sich für Vergleiche die Größenordnung: n2
Die Elemente werden paarweise getauscht und drehen die Sortierung um.
Bei n zu sortierenden Elementen ergibt sich für Vertauschungen: n/2
Folie-382
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Analyse des Algorithmus:
Laufzeit – bestmöglicher Fall:
Die zu betrachtende Folge wird durch das Pivot-Element immer genau halbiert.
Dann hängt die Zahl der Aufrufe der Methode groupByNumber davon ab,
wie häufig sich n durch 2 teilen lässt:
2x n
oder x = log2(n) (Logarithmus zur Basis 2)
f(n) = n
g(n) = n2 log2(n) besitzt eine abnehmende Steigung:
= abnehmendes Verschlechtern bei
mehr Elemente
log2(n)
Folie-383
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Analyse des Algorithmus:
Laufzeit – bestmöglicher Fall:
Die zu betrachtende Folge wird durch das Pivot-Element immer genau halbiert.
Bei n zu sortierenden Elementen ergibt sich für Aufrufe die Größenordnung: log2(n)
In jedem der log2(n) Aufrufe der Methode groupByNumber wird ein Ausschnitt der n zu
sortierenden Elemente mit dem Pivot-Element verglichen.
Es ergibt sich für Vergleiche die Größenordnung: n . log2(n)
Da Vertauschungen eine Konsequenz der Vergleiche sind, treten nie mehr Vertauschungen auf.
Es ergibt sich für Vertauschungen ebenfalls die Größenordnung: n . log2(n)
Folie-384
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Analyse des Algorithmus:
Laufzeit – bestmöglicher Fall:
Die zu betrachtende Folge wird durch das Pivot-Element immer genau halbiert.
Bei n zu sortierenden Elementen ergibt sich für Aufrufe die Größenordnung: log2(n)
In jedem der log2(n) Aufrufe der Methode groupByNumber wird ein Ausschnitt der n zu
sortierenden Elemente mit dem Pivot-Element verglichen.
Es ergibt sich für Vergleiche die Größenordnung: n . log2(n)
Da Vertauschungen eine Konsequenz der Vergleiche sind, treten nie mehr Vertauschungen auf.
Es ergibt sich für Vertauschungen ebenfalls die Größenordnung: n . log2(n)
Laufzeit – durchschnittlicher Wert:
QuickSort O( n . log2(n) ) (kann hier aber noch nicht bewiesen werden)
QuickSort kann also deutlich schneller als InsertionSort und SelectionSort arbeiten. *)
*) Für n=100 000 ist n2=10 000 000 000, aber n . log2(n)<=1 700 000 (ganzzahlig).
Folie-385
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Analyse des Algorithmus:
Laufzeit – bestmöglicher Fall:
Die zu betrachtende Folge wird durch das Pivot-Element immer genau halbiert.
Bei n zu sortierenden Elementen ergibt sich für Aufrufe die Größenordnung: log2(n)
In jedem der log2(n) Aufrufe der Methode groupByNumber wird ein Ausschnitt der n zu
sortierenden Elemente mit dem Pivot-Element verglichen.
Es ergibt sich für Vergleiche die Größenordnung: n . log2(n)
Da Vertauschungen eine Konsequenz der Vergleiche sind, treten nie mehr Vertauschungen auf.
Es ergibt sich für Vertauschungen ebenfalls die Größenordnung: n . log2(n)
Laufzeit – durchschnittlicher Wert:
QuickSort O( n . log2(n) ) (kann hier aber noch nicht bewiesen werden)
QuickSort kann also deutlich schneller als InsertionSort und SelectionSort arbeiten. *)
QuickSort ist nicht stabil, da die Elemente abhängig von ihrem Vorkommen getauscht werden.
QuickSort arbeitet in situ, benötigt aber neben dem Feld den Speicherplatz für die lokalen
Variablen und Parameter der gleichzeitig ausgeführten Instanzen der rekursiven Methode.
*) Für n=100 000 ist n2=10 000 000 000, aber n . log2(n)<=1 700 000 (ganzzahlig).
Folie-386
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Algorithmus «QuickSort»
Idee des Sortierverfahrens «QuickSort»
Die zu sortierenden Elemente werden in zwei Folgen aufgeteilt
– bezüglich ihrer Eigenschaften und
– bezüglich einer Referenzeinheit p («Pivot-Element»),
so dass die bezüglich p kleineren und die bezüglich p größeren Elemente
jeweils eine Folge bilden.
Auf die beiden Folgen wird das Verfahren immer wieder angewandt,
bis Folgen der Länge 1 entstehen.
Der gleiche Vorgang wird also immer wieder auf immer kleiner werdenden Folgen ausgeführt.
Folie-387
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Aufruf für Objekte der Klasse Lecture
Methode ist privat:
private void groupByNumber( int leftBound, int rightBound )
Sinnvoll, da die Parameterwerte ja auch abhängig sind von der Größe und der Belegung des
Feldes students und dieses ebenfalls privat deklariert ist.
Daher wird für eine Lösung, die ein einfaches Sortieren der Studierenden einer Vorlesung
erlaubt, eine zusätzliche öffentliche Methode benötigt,
die den ersten Aufruf von groupByNumber übernimmt.
public void quickSortByNumber()
{
groupByNumber( 0, firstUnused - 1 );
}
berechnet das letzte benutzte Element in students
Folie-388
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
analoge Methode: quickSortByName
sorted by number:
lecture: DAP 1
participants:
student: C, registration number: 3(M)
student: F, registration number: 4(Inf)
student: E, registration number: 7(Inf)
student: B, registration number: 8(M)
student: A, registration number: 11(Inf)
student: B, registration number: 14(Inf)
student: D, registration number: 19(Ph)
student: B, registration number: 22(Inf)
sorted by name:
lecture: DAP 1
participants:
student: A, registration number: 11(Inf)
student: B, registration number: 22(Inf)
student: B, registration number: 14(Inf)
student: B, registration number: 8(M)
student: C, registration number: 3(M)
student: D, registration number: 19(Ph)
student: E, registration number: 7(Inf)
student: F, registration number: 4(Inf)
arbeitet auch mit
mehrfachen Einträgen
korrekt
(aber nicht stabil)
Folie-389
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Sortieren durch «QuickSort» (Fortsetzung)
Sortierung nach Namen
public void quickSortByName()
{
groupByName( 0, firstUnused - 1 );
}
private void groupByName( int leftBound, int rightBound )
{
if (leftBound < rightBound )
{
int leftOfGreaterPart = leftBound;
for ( int candidate = leftBound; candidate < rightBound; candidate++ )
{
if ( students[rightBound].hasGreaterName( students[candidate] ) )
{
swapStudents( candidate, leftOfGreaterPart );
leftOfGreaterPart++;
}
}
swapStudents( leftOfGreaterPart, rightBound );
groupByName( leftBound, leftOfGreaterPart - 1 );
groupByName( leftOfGreaterPart + 1 , rightBound );
}
}
Die Algorithmen der Methoden sind identisch, nur die Namen unterscheiden sich, da eine
andere Vergleichsmethode der Klasse Student zum Einsatz kommen muss.
Im weiteren Verlauf der Vorlesung werden Konzepte eingeführt,
mit denen sich das Duplizieren des Programmtextes vermeiden lässt.
Folie-390
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vergleich der Sortierverfahren in der Praxis
Experiment:
zufälliges Erzeugen einer großen Zahl von Student-Objekten
Sortieren dieser Student-Objekte mit einem der drei Sortierverfahren
SelectionSort, InsertionSort, Quicksort
Messen der benötigten Ausführungszeit
mehrfaches Wiederholen des Erzeugens und Sortierens, um Einflüsse von
für einzelne Verfahren besonders günstigen/ungünstigen Ausgangsfolgen auszuschießen
Bilden von Mittelwerten
Folie-391
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vergleich der Sortierverfahren in der Praxis (Fortsetzung)
zufällig erzeugte, unsortierte Folge
(durchschnittliche Ausführungszeit in Millisekunden)
Anzahl der Sortierverfahren
Objekte SelectionSort InsertionSort QuickSort
10 000 95
20 000 380
30 000 859
40 000 1517
Folie-392
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vergleich der Sortierverfahren in der Praxis (Fortsetzung)
zufällig erzeugte, unsortierte Folge
(durchschnittliche Ausführungszeit in Millisekunden)
Anzahl der Sortierverfahren
Objekte SelectionSort InsertionSort QuickSort
10 000 95 63
20 000 380 257
30 000 859 588
40 000 1517 1052
Folie-393
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vergleich der Sortierverfahren in der Praxis (Fortsetzung)
zufällig erzeugte, unsortierte Folge
(durchschnittliche Ausführungszeit in Millisekunden)
Anzahl der Sortierverfahren
Objekte SelectionSort InsertionSort QuickSort
10 000 95 63 1
20 000 380 257 2
30 000 859 588 3
40 000 1517 1052 5
Folie-394
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vergleich der Sortierverfahren in der Praxis (Fortsetzung)
bereits aufsteigend sortierte Folge
(Ausführungszeit in Millisekunden)
Anzahl der Sortierverfahren
Objekte SelectionSort InsertionSort QuickSort
1000 1 0 1
2000 3 0 4
3000 7 0 8
10 000 71 0 overflow *)
20 000 290 0 overflow
30 000 656 0 overflow
40 000 1154 0 overflow
*) Der Speicherplatzbedarf der rekursiven Aufrufe kann durch das Java Runtime System nicht erfüllt werden.
Folie-395
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vergleich der Sortierverfahren in der Praxis (Fortsetzung)
bereits absteigend sortierte Folge
(Ausführungszeit in Millisekunden)
Anzahl der Sortierverfahren
Objekte SelectionSort InsertionSort QuickSort
1000 1 1 2
2000 4 3 4
3000 7 10 9
10 000 73 112 overflow
20 000 292 449 overflow
30 000 671 1014 overflow
40 000 1057 1975 overflow
Folie-396
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Sortieralgorithmen
(siehe Folie 298)
Nach Durcharbeiten des Kapitels Sortieralgorithmen sollen
die teilnehmenden Studierenden
den Sortieralgorithmus SelectionSort kennen
den Sortieralgorithmus InsertionSort kennen
den Sortieralgorithmus QuickSort kennen
grobe Analysen zur Laufzeit dieser Algorithmen erklären können
die O-Notation erklären und anwenden können
die Implementierungen der Algorithmen erklären können
den rekursiven Ansatz von QuickSort verstanden haben
Folie-397
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen, Algorithmen
und Programmierung 1 (DAP 1)
Fakultät für Informatik
Wintersemester 2019/20
Stefan Dissmann
Rekursive Algorithmen
Folie-398
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Rekursive Algorithmen
Nach Durcharbeiten des Kapitels Rekursive Algorithmen sollen
die teilnehmenden Studierenden
den Grundaufbau rekursiver Methoden kennen
rekursive Algorithmen konzipieren und formulieren können
rekursive Methoden implementieren können
Backtracking als Prinzip der Gestaltung von Algorithmen kennen
die vorgestellten Beispiele für rekursive Methoden nachvollziehen können
Folie-399
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Erinnerung: «QuickSort» – wesentliche Eigenschaften
private void groupByNumber( int leftBound, int rightBound )
{
if (leftBound < rightBound )
{
int leftOfGreaterPart = leftBound;
for ( int candidate = leftBound; candidate < rightBound; candidate++ )
{
if ( students[rightBound].hasGreaterNumber( students[candidate] ) )
{
swapStudents( candidate, leftOfGreaterPart );
leftOfGreaterPart++;
}
}
swapStudents( leftOfGreaterPart, rightBound );
groupByNumber( leftBound, leftOfGreaterPart - 1 );
groupByNumber( leftOfGreaterPart + 1 , rightBound );
}
}
Selbstaufruf
kleiner werdende Aufgabe
Berechnung ohne Rekursion
Folie-400
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – technische Voraussetzungen
Java stellt folgendes Konzept bereit:
Jedes Ausführen einer Methode ist unabhängig von anderen Ausführungen von Methoden.
Inbesondere:
Jede Ausführung einer Methode ist unabhängig von anderen Ausführungen
derselben Methodendeklaration.
Jeder Aufruf einer Methode erhält für seine Ausführung
neuen Speicherplatz für alle Parameter und alle Variablen zugeteilt.
Gleichzeitig bleibt der Speicherplatz von Parametern und Variablen erhalten,
der für bereits laufende Ausführungen der derselben Methodendeklaration benutzt wird.
Beispiel:
Jede Ausführung der Methode groupByNumber benötigt und erhält also Speicherplatz
für vier Werte:
leftBound, rightBound, leftOfGreaterPart, candidate
Folie-401
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – konzeptionelle Voraussetzungen
Damit ein rekursiv formulierter Algorithmus korrekt arbeitet,
müssen immer drei Eigenschaften vorhanden sein:
Selbstaufruf
Die Ausführung einer Methode führt zu einer weiteren Ausführung derselben Methode.
– Die Methode kann sich im Rumpf ihrer Deklaration selbst aufrufen (direkte Rekursion).
– Es gibt aber auch indirekte Rekursion,
bei der eine Methode m1 die Ausführung einer anderen Methode m2 veranlasst,
von der aus wiederum die Methode m1 aufgerufen wird.
m1
m1
m1
m1
m1
m1
direkte Rekursion
m1
m2
m1
m2
m1
m2
indirekte Rekursion
Folie-402
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – konzeptionelle Voraussetzungen (Fortsetzung)
Damit ein rekursiver Algorithmus korrekt arbeitet,
müssen immer drei Eigenschaften vorhanden sein:
Selbstaufruf
Die Ausführung einer Methode führt zu einer weiteren Ausführung derselben Methode.
– Die Methode kann sich im Rumpf ihrer Deklaration selbst aufrufen (direkte Rekursion).
– Es gibt aber auch indirekte Rekursion,
bei der eine Methode m1 die Ausführung einer anderen Methode m2 veranlasst,
von der aus wiederum die Methode m1 aufgerufen wird.
Abbruchkriterium für den Selbstaufruf
Der Algorithmus einer rekursiven Methode muss in ausgewählten Situationen
ein Ergebnis ohne erneuten rekursiven Aufruf berechnen können.
(Nur dann kann die Folge der rekursiven Ausführungen irgendwann abbrechen.)
Folie-403
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – konzeptionelle Voraussetzungen (Fortsetzung)
Damit ein rekursiver Algorithmus korrekt arbeitet,
müssen immer drei Eigenschaften vorhanden sein:
Selbstaufruf
Die Ausführung einer Methode führt zu einer weiteren Ausführung der gleichen Methode.
– Die Methode kann sich im Rumpf ihrer Deklaration selbst aufrufen (direkte Rekursion).
– Es gibt aber auch indirekte Rekursion,
bei der eine Methode m1 die Ausführung einer anderen Methode m2 veranlasst,
von der aus wiederum die Methode m1 aufgerufen wird.
Abbruchkriterium für den Selbstaufruf
Der Algorithmus einer rekursiven Methode muss in ausgewählten Situationen
ein Ergebnis ohne erneuten rekursiven Aufruf berechnen können.
(Nur dann kann die Folge der rekursiven Ausführungen irgendwann abbrechen.)
Reduktion der Problemstellung
Der Selbstaufruf einer rekursiven Methode muss immer für ein verkleinertes Problem erfolgen,
das «näher» an dem Abbruchkriterium für die Rekursion liegt.
(Nur dann wird das Abbruchkriterium irgendwann erreicht.)
Folie-404
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Töpfe der Pride of Lake Phoenix»
Szenario:
Der Schiffskoch des Kreuzfahrtschiffes Pride of Lake Phoenix hat 28 neue Töpfe bekommen, die
einfach auf dem Herd seiner Bordküche abgestellt worden sind. Diese muss er nun in den Schrank
schaffen, hat dabei aber folgende Probleme:
Die Töpfe sind so schwer, dass er immer nur genau einen Topf anheben und bewegen kann.
Um Platz zu sparen besitzen die Töpfe unterschiedliche Durchmesser, so dass sie sich
ineinander stellen lassen.
In der engen Bordküche gibt es nur noch die Spüle, auf der nur genau ein Topf Platz hat.
Wegen des starken Seegangs können die Töpfe nicht gestapelt werden ohne sofort umzufallen.
Die Töpfe müssen also immer ineinander gestellt werden.
Folie-405
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Töpfe der Pride of Lake Phoenix» (Fortsetzung)
Szenario:
Der Schiffskoch des Kreuzfahrtschiffes Pride of Lake Phoenix hat 28 neue Töpfe bekommen, die
einfach auf dem Herd seiner Bordküche abgestellt worden sind. Diese muss er nun in den Schrank
schaffen, hat dabei aber folgende Probleme:
Die Töpfe sind so schwer, dass er immer nur genau einen Topf anheben und bewegen kann.
Um Platz zu sparen besitzen die Töpfe unterschiedliche Durchmesser, so dass sie sich
ineinander stellen lassen.
In der engen Bordküche gibt es nur noch die Spüle, auf der nur genau ein Topf Platz hat.
Wegen des starken Seegangs können die Töpfe nicht gestapelt werden ohne sofort umzufallen.
Die Töpfe müssen also immer ineinander gestellt werden.
Ausgangssituation:
...
Herd Spüle Schrank
Folie-406
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Töpfe der Pride of Lake Phoenix» (Fortsetzung)
Das Problem lässt sich wohl nur durch geschicktes Umlagern lösen.
Folie-407
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Töpfe der Pride of Lake Phoenix» (Fortsetzung)
Das Problem lässt sich wohl nur durch geschicktes Umlagern lösen.
Beispiel für drei Töpfe:
Herd Spüle Schrank
jeweils zuletzt
bewegter Topf
Folie-408
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Töpfe der Pride of Lake Phoenix» (Fortsetzung)
Das Problem lässt sich durch geschicktes Umlagern lösen!
Aber: Das Beispiel mit drei Töpfen zeigt, dass die Situation mit mehr Töpfen leicht
unübersichtlich werden kann.
Und: Bei Fehlern im Umlagern stehen alle Töpfe am Ende möglicherweise
nicht im Schrank – sondern auf der Spüle oder (wieder) auf dem Herd.
Der Schiffskoch entwickelt also einen Algorithmus, der angibt, in welcher Folge die Töpfe wie
versetzt werden müssen.
Folie-409
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Töpfe der Pride of Lake Phoenix» (Fortsetzung)
Um zu einem Algorithmus zu kommen,
betrachten wir die folgende Zwischenstufe des Beispiels:
Damit der größte Topf vom Herd in den Schrank gelangen kann,
müssen alle anderen Töpfe auf der Spüle stehen.
Das Umlagern von n Töpfen vom Herd in den Schrank kann daher zerlegt werden in:
Herd Spüle Schrank
Folie-410
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Töpfe der Pride of Lake Phoenix» (Fortsetzung)
Um zu einem Algorithmus zu kommen,
betrachten wir die folgende Zwischenstufe des Beispiels:
Damit der größte Topf vom Herd in den Schrank gelangen kann,
müssen alle anderen Töpfe auf der Spüle stehen.
Das Umlagern von n Töpfen vom Herd in den Schrank kann daher zerlegt werden in:
– das Umlagern der inneren n–1 Töpfe vom Herd auf die Spüle,
also die einzige Lagermöglichkeit, die weder Start- noch Zielpunkt ist.
Herd Spüle Schrank
Folie-411
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Töpfe der Pride of Lake Phoenix» (Fortsetzung)
Um zu einem Algorithmus zu kommen,
betrachten wir die folgende Zwischenstufe des Beispiels:
Damit der größte Topf vom Herd in den Schrank gelangen kann,
müssen alle anderen Töpfe auf der Spüle stehen.
Das Umlagern von n Töpfen vom Herd in den Schrank kann daher zerlegt werden in:
– das Umlagern der inneren n–1 Töpfe vom Herd auf die Spüle,
also die einzige Lagermöglichkeit, die weder Start- noch Zielpunkt ist.
– das Versetzen des größten, äußersten Topfes in den Schrank,
Herd Spüle Schrank
Folie-412
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Töpfe der Pride of Lake Phoenix» (Fortsetzung)
Um zu einem Algorithmus zu kommen,
betrachten wir die folgende Zwischenstufe des Beispiels:
Damit der größte Topf vom Herd in den Schrank gelangen kann,
müssen alle anderen Töpfe auf der Spüle stehen.
Das Umlagern von n Töpfen vom Herd in den Schrank kann daher zerlegt werden in:
– das Umlagern der inneren n–1 Töpfe vom Herd auf die Spüle,
also die einzige Lagermöglichkeit, die weder Start- noch Zielpunkt ist.
– das Versetzen des größten, äußersten Topfes vom Herd in den Schrank,
– das Umlagern der n–1 Töpfe von der Spüle in den Topf im Schrank.
Herd Spüle Schrank
Folie-413
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Töpfe der Pride of Lake Phoenix» (Fortsetzung)
Algorithmus für den ersten Teilschritt:
Das Umlagern der inneren n–1 Töpfe vom Herd auf die Spüle kann zerlegt werden in:
– das Umlagern der inneren n–2 Töpfe vom Herd in den Schrank,
also die Lagermöglichkeit, die weder Start- noch Zielpunkt ist.
– das Versetzen des größten, äußersten Topfes vom Herd auf die Spüle,
– das Umlagern der n–2 Töpfe vom Schrank in den Topf auf der Spüle.
Und so läßt sich das Umlagern fortsetzen,
bis keine Töpfe mehr versetzt werden müssen.
Folie-414
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Töpfe der Pride of Lake Phoenix» (Fortsetzung)
Es ergibt sich also folgender, rekursiver Algorithmus:
Umlagern von n Töpfen von einer Startposition zu einer Zielposition
wird ausgeführt durch
falls n größer als 0 ist
Umlagern von n–1 Töpfen von der Startposition zur Hilfsposition
(die weder Start- noch Zielposition ist)
Versetzen von einem Topf von der Startposition zur Zielposition
Umlagern von n–1 Töpfen von der Hilfsposition zur Zielposition
Folie-415
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Töpfe der Pride of Lake Phoenix» (Fortsetzung)
Es ergibt sich also folgender, rekursiver Algorithmus:
Umlagern von n Töpfen von einer Startposition zu einer Zielposition
wird ausgeführt durch
falls n größer als 0 ist
Umlagern von n–1 Töpfen von der Startposition zur Hilfsposition
(die weder Start- noch Zielposition ist)
Versetzen von einem Topf von der Startposition zur Zielposition
Umlagern von n–1 Töpfen von der Hilfsposition zur Zielposition
Wie wird die Hilfsposition bestimmt?
Folie-416
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Töpfe der Pride of Lake Phoenix» (Fortsetzung)
Es ergibt sich also folgender, rekursiver Algorithmus:
Umlagern von n Töpfen von einer Startposition zu einer Zielposition
wird ausgeführt durch
falls n größer als 0 ist
Umlagern von n–1 Töpfen von der Startposition zur Hilfsposition
(= weder Start- noch Zielposition)
Versetzen von einem Topf von der Startposition zur Zielposition
Umlagern von n–1 Töpfen von der Hilfsposition zur Zielposition
Wie wird die Hilfsposition bestimmt?
Die Positionen werden mit Nummern versehen: Herd = 0, Spüle = 1, Schrank = 2
Die Summe aller Nummern ist dann: 0 + 1 + 2 = 3
Die Hilfsposition ergibt sich daher immer als: 3 – Startposition – Zielposition
Folie-417
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Töpfe der Pride of Lake Phoenix» (Fortsetzung)
private static void rearrangePots( int quantity, int start, int target )
{
String[] locations = { "stove", "sink", "cupboard" };
if (quantity > 0)
{
rearrangePots( quantity – 1, start, computeInterimPosition( start, target ) );
System.out.println(
“pot ” + quantity + “: ” + locations[start] + ” -> ” + locations[target] );
rearrangePots( quantity – 1, computeInterimPosition(start, target), target );
}
}
private static int computeInterimPosition( int start, int target )
{
return 3 – start – target;
}
Die Implementierung setzt den zuvor entwickelten Algorithmus direkt um.
Abbruchkriterium
Reduktion
rekursive
Aufrufe
Folie-418
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Töpfe der Pride of Lake Phoenix» (Fortsetzung)
public static void rearrangeAllPots( int quantity )
{
rearrangePots( quantity, 0, 2 );
}
Die öffentliche Methode rearrangeAllPots dient wiederum dazu,
für den ersten Aufruf der rekursiven Methode die Argumente geeignet zu übergeben.
Folie-419
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Töpfe der Pride of Lake Phoenix» (Fortsetzung)
Ausgabe für das Beispiel mit drei Töpfen:
pot 1: stove -> cupboard
pot 2: stove -> sink
pot 1: cupboard -> sink
pot 3: stove -> cupboard
pot 1: sink -> stove
pot 2: sink -> cupboard
pot 1: stove -> cupboard
Folie-420
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Töpfe der Pride of Lake Phoenix» (Fortsetzung)
rekursive Aufrufstruktur für das Beispiel mit drei Töpfen:
rearrangePots( 3, 0, 2 )
rearrangePots( 2, 0, 1 )
rearrangePots( 1, 0, 2 )
rearrangePots( 0, 0, 1 )
rearrangePots( 0, 1, 2 )
rearrangePots( 1, 2, 1 )
rearrangePots( 0, 2, 0 )
rearrangePots( 0, 0, 1 )
rearrangePots( 2, 1, 2 )
rearrangePots( 1, 1, 0 )
rearrangePots( 0, 1, 2 )
rearrangePots( 0, 2, 0 )
rearrangePots( 1, 0, 2 )
rearrangePots( 0, 0, 1 )
rearrangePots( 0, 1, 2 )
Schachtelung der rekursiven Aufrufe
Folie-421
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Töpfe der Pride of Lake Phoenix» (Fortsetzung)
Erkenntnisse:
Der rekursive Algorithmus hat sich nach kurzer Überlegung recht unmittelbar ergeben.
Entscheidend für die Entwicklung war nur die Reduktion des Problems auf das Versetzen des
größten Topfes.
Da rekursive Algorithmen immer eine Reduktion des Problems für den rekursiven Aufruf
enthalten müssen, ist es naheliegend, über einen passenden Denkansatz zu einem Algorithmus
zu kommen.
Anmerkungen:
Für das regelgerechte Umsetzen aller 28 Töpfe müssen 26 843 455 Bewegungen ausgeführt
werden. Selbst wenn der Schiffskoch nur eine Sekunde für das Versetzen eines Topfes braucht,
erfordert das Umsetzen aller 28 Töpfe etwa ein Jahr Arbeit ohne Pause.
Das hier in die Schifffahrt verlagerte Problem ist in der Informatik unter dem Namen
«Türme von Hanoi» bekannt.
Folie-422
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Beladen der Pride of Lake Phoenix»
Szenario:
Für seine Passagiere muss das Schiff Vorräte in Containern an Bord nehmen.
Jeder Container hat ein bekanntes Gewicht.
Die Container werden in einer nicht zu beeinflussenden Folge angeliefert.
Container können in Laderäumen auf der Backbord- oder Steuerbordseite verstaut werden.
Allerdings muss darauf geachtet werden, dass die Balance des Schiffes erhalten bleibt, damit
das Schiff nicht bereits während des Beladevorgangs eine zu große Schlagseite bekommt.
Der Lademeister möchte also bereits im Vorfeld der Beladung prüfen,
ob eine geeignete Verteilung der ankommenden Container auf die beiden Seiten des Schiffes
überhaupt möglich ist.
Folie-423
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Beladen der Pride of Lake Phoenix» (Fortsetzung)
Szenario:
Für seine Passagiere muss das Schiff Vorräte in Containern an Bord nehmen.
Jeder Container hat ein bekanntes Gewicht.
Die Container werden in einer nicht zu beeinflussenden Folge angeliefert.
Container können in Laderäumen auf der Backbord- oder Steuerbordseite verstaut werden.
Allerdings muss darauf geachtet werden, dass die Balance des Schiffes erhalten bleibt, damit
das Schiff nicht bereits während des Beladevorgangs eine zu große Schlagseite bekommt.
Der Lademeister möchte also bereits im Vorfeld der Beladung prüfen,
ob eine geeignete Verteilung der ankommenden Container auf die beiden Seiten des Schiffes
überhaupt möglich ist.
Folie-424
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Beladen der Pride of Lake Phoenix» (Fortsetzung)
Laderaum backbord
Laderaum steuerbord
Anleger
22 19 11 5 14 20 10
unbalanciert ab: 16
Folie-425
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Beladen der Pride of Lake Phoenix» (Fortsetzung)
Laderaum backbord
Laderaum steuerbord
Anleger
22 19 11 5 14 20 10
unbalanciert ab: 16
22
19
11 5
14
20
10
Lösung
Folie-426
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Beladen der Pride of Lake Phoenix» (Fortsetzung)
Szenario:
Für seine Passagiere muss das Schiff Vorräte in Containern an Bord nehmen.
Jeder Container hat ein bekanntes Gewicht.
Die Container werden in einer nicht zu beeinflussenden Folge angeliefert.
Container können in Laderäumen auf der Backbord- oder Steuerbordseite verstaut werden.
Allerdings muss darauf geachtet werden, dass die Balance des Schiffes erhalten bleibt, damit
das Schiff nicht bereits während des Beladevorgangs eine zu große Schlagseite bekommt.
Der Lademeister möchte also bereits im Vorfeld der Beladung prüfen,
ob eine geeignete Verteilung der ankommenden Container auf die beiden Seiten des Schiffes
überhaupt möglich ist.
Das Problem wird hier etwas vereinfacht modelliert:
– Es gibt ein Feld containers mit positiven ganzen Zahlen, die die Gewichte der Container in
der Reihenfolge ihres Ankommens darstellen.
– Es gibt einen positiven Wert limit, der den Grenzwert für das Ungleichgewicht angibt,
bei dessen Überschreiten das Schiff umkippen würde.
Folie-427
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Beladen der Pride of Lake Phoenix» (Fortsetzung)
Voraussetzung:
Da die Folge der zu ladenden Gewichte festliegt, muss von Beginn des Ladevorgangs an
eine geeignete Verteilung der Gewichte vorgenommen werden.
Folie-428
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Beladen der Pride of Lake Phoenix» (Fortsetzung)
Voraussetzung:
Da die Folge der zu ladenden Gewichte festliegt, muss von Beginn des Ladevorgangs an
eine geeignete Verteilung der Gewichte vorgenommen werden.
Lösungsidee:
Lade den Container n auf eine Seite des Schiffes.
Prüfe, ob das Schiff noch im Gleichgewicht liegt:
– falls das der Fall ist, setze fort mit dem Laden des Containers n+1
– falls das nicht der Fall ist, lade den Container n auf die andere Seite um
Folie-429
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Beladen der Pride of Lake Phoenix» (Fortsetzung)
Voraussetzung:
Da die Folge der zu ladenden Gewichte festliegt, muss von Beginn des Ladevorgangs an
eine geeignete Verteilung der Gewichte vorgenommen werden.
Lösungsidee:
Lade den Container n auf eine Seite des Schiffes.
Prüfe, ob das Schiff noch im Gleichgewicht liegt:
– falls das der Fall ist, setze fort mit dem Laden des Containers n+1
– falls das nicht der Fall ist, lade den Container n auf die andere Seite um
– Prüfe, ob das Schiff noch im Gleichgewicht liegt:
– falls das der Fall ist, setze fort mit dem Laden des Containers n+1
– falls das nicht der Fall ist, passt die Ausgangssituation nicht:
versuche, den Container n-1 auf die andere Seite umzuladen
und dann fortzusetzen
Folie-430
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Beladen der Pride of Lake Phoenix» (Fortsetzung)
Voraussetzung:
Da die Folge der zu ladenden Gewichte festliegt, muss von Beginn des Ladevorgangs an
eine geeignete Verteilung der Gewichte vorgenommen werden.
Lösungsidee:
Lade den Container n auf eine Seite des Schiffes.
Prüfe, ob das Schiff noch im Gleichgewicht liegt:
– falls das der Fall ist, setze fort mit dem Laden des Containers n+1
– falls das nicht der Fall ist, lade den Container n auf die andere Seite um
– Prüfe, ob das Schiff noch im Gleichgewicht liegt:
– falls das der Fall ist, setze fort mit dem Laden des Containers n+1
– falls das nicht der Fall ist, passt die Ausgangssituation nicht:
versuche, den Container n-1 auf die andere Seite umzuladen
und dann fortzusetzen
Gehe gegebenenfalls noch weiter zurück und versuche,
eine andere Ausgangssituationen zu schaffen.
Folie-431
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Beladen der Pride of Lake Phoenix» (Fortsetzung)
Laderaum backbord
Laderaum steuerbord
Anleger
19 11 5 14 20 10
11
5 14
20
10
22
19 ?
unbalanciert ab: 16
Folie-432
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Beladen der Pride of Lake Phoenix» (Fortsetzung)
Lösungsidee (Kurzfassung):
Erstelle schrittweise eine Beladung.
Sobald das Gleichgewicht nicht gehalten werden kann, gehe schrittweise zurück und
versuche von einer der vorherigen Beladungen aus anders fortzusetzen.
Das Verfahren endet, wenn
– entweder alle Container erfolgreich verladen werden konnten
– oder alle möglichen Beladungsalternativen erfolglos abgebrochen worden sind.
Folie-433
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Beladen der Pride of Lake Phoenix» (Fortsetzung)
Lösungsidee (Kurzfassung):
Erstelle schrittweise eine Beladung.
Sobald das Gleichgewicht nicht gehalten werden kann, gehe schrittweise zurück und
versuche von einer der vorherigen Beladungen aus anders fortzusetzen.
Das Verfahren endet, wenn
– entweder alle Container erfolgreich verladen werden konnten
– oder alle möglichen Beladungsalternativen erfolglos abgebrochen worden sind.
Rekursive Methode zur Lösung:
Jede Instanz einer rekursiven Methode enthält einen eigenen Satz von Variablen mit Werten.
Wird dieser Satz von Variablen dazu genutzt, um den Zwischenstand der Beladung
festzuhalten, so kann einfach durch das Beenden von jüngeren Instanzen der Methode
zu den älteren Instanzen und damit zu einem älteren Zwischenstand der Beladung
zurückgekehrt werden.
Die aufeinander folgenden rekursiven Aufrufe bilden also ein Gedächtnis der bisher
vorgenommenen Entscheidungen zur Beladung des Schiffes.
Folie-434
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Beladen der Pride of Lake Phoenix» (Fortsetzung)
Signatur der rekursiven Methode:
private static boolean existsBalanceUpTo(
int[] containers, int limit, int divergence, int unitsLoaded )
{
…
}
Containergewichte
Gleichgewichtsgrenze
bei aktueller Beladung
Ungleichgewicht
Anzahl der verladenen Container
Folie-435
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Beladen der Pride of Lake Phoenix» (Fortsetzung)
private static boolean existsBalanceUpTo(
int[] containers, int limit, int divergence, int unitsLoaded )
{
}
Abbruchkriterium: alle Container sind verladen
rekursiver Aufruf: Container auf Backbord-Seite laden
rekursiver Aufruf: Container auf Steuerbord-Seite laden
Folie-436
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Abbruchkriterium:
rekursiver Aufruf: Container auf Backbord-Seite laden
rekursiver Aufruf: Container auf Steuerbord-Seite laden
Rekursion – Beispiel «Beladen der Pride of Lake Phoenix» (Fortsetzung)
private static boolean existsBalanceUpTo(
int[] containers, int limit, int divergence, int unitsLoaded )
{
if ( unitsLoaded >= containers.length )
{
return true;
}
}
alle Container verladen
Folie-437
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Beladen der Pride of Lake Phoenix» (Fortsetzung)
private static boolean existsBalanceUpTo(
int[] containers, int limit, int divergence, int unitsLoaded )
{
if ( unitsLoaded >= containers.length )
{
return true;
}
int nextDivergence = divergence + containers[unitsLoaded];
if ( Math.abs( nextDivergence ) <= limit )
{
boolean loadedOnPortside =
existsBalanceUpTo( containers, limit, nextDivergence, unitsLoaded+1);
if ( loadedOnPortside )
{
return true;
}
}
}
rekursiver Aufruf:
rekursiver Aufruf: Container auf Steuerbord-Seite laden
Container auf Backbord-Seite laden
Abbruchkriterium:
alle Container verladen
Folie-438
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Beladen der Pride of Lake Phoenix» (Fortsetzung)
private static boolean existsBalanceUpTo(
int[] containers, int limit, int divergence, int unitsLoaded )
{
if ( unitsLoaded >= containers.length )
{
return true;
}
int nextDivergence = divergence + containers[unitsLoaded];
if ( Math.abs( nextDivergence ) <= limit )
{
boolean loadedOnPortside =
existsBalanceUpTo( containers, limit, nextDivergence, unitsLoaded+1);
if ( loadedOnPortside )
{
return true;
}
}
nextDivergence = divergence - containers[unitsLoaded];
if ( Math.abs( nextDivergence ) <= limit )
{
return existsBalanceUpTo(containers, limit, nextDivergence, unitsLoaded+1);
}
else
{
return false;
}
}
rekursiver Aufruf:
Container auf Steuerbord-Seite laden
Folie-439
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Beladen der Pride of Lake Phoenix» (Fortsetzung)
public static boolean existsBalance( int[] containers, int limit )
{
return existsBalanceUpTo( containers, limit, 0, 0 );
}
initialer Aufruf der rekursiven Methode
– das Schiff ist im Gleichgewicht: divergence = 0
– es wurde noch kein Container verladen: unitsLoaded = 0
Beide Angaben werden nur zur Steuerung der rekursiven Aufrufe benötigt.
Die Methode existsBalance verbirgt die Parameter und die initial übergebenen Argumente.
Folie-440
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Beladen der Pride of Lake Phoenix» (Fortsetzung)
Die Algorithmen QuickSort und zum Umlagern der Töpfe streben unmittelbar
auf das gewünschte Ergebnis zu. Die Rekursion dient dazu, die Ausführung von
Teilen der Algorithmen zu koordinieren:
– QuickSort:
Zerlegen in zwei Abschnitte, Sortieren des einen Abschnitts, dann des anderen Abschnitts
– Umstapeln der Töpfe:
Stapeln auf dem Hilfsplatz, von dort Umstapeln zum Ziel
Das Konzept der Rekursion wird beim Beladen anders eingesetzt:
Hier wird zunächst versucht, eine Lösung zu finden.
Scheitert der Versuch, so wird die Rekursion eingesetzt, um zurückgehen zu können.
Diese Art der Gestaltung von Algorithmen wird als Backtracking bezeichnet.
Folie-441
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Treppe der Informatik»
Szenario:
Ein körperlich leistungsfähiger Mensch
kann auf einer Treppe zwei Stufen mit einem Schritt überwinden.
Die Treppe des Informatik-Gebäudes OH14 hat 80 Stufen.
Wie viele Schrittfolgen gibt es, diese Treppe hinaufzugehen, wenn beliebig Schritte über eine
oder zwei Stufen miteinander kombiniert werden können.
Folie-442
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Treppe der Informatik» (Fortsetzung)
Szenario:
Ein körperlich leistungsfähiger Mensch
kann auf einer Treppe zwei Stufen mit einem Schritt überwinden.
Die Treppe des Informatik-Gebäudes OH14 hat 80 Stufen.
Wie viele Schrittfolgen gibt es, diese Treppe hinaufzugehen, wenn beliebig Schritte über eine
oder zwei Stufen miteinander kombiniert werden können.
Beispiel: Treppe mit fünf Stufen
mögliche Schrittfolgen:
1-1-1-1-1
1-1-1-2
1-1-2-1
1-2-1-1
2-1-1-1
1-2-2
2-1-2
2-2-1
Folie-443
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Treppe der Informatik» (Fortsetzung)
Visualisierung:
mögliche Schrittfolgen:
1-1-1-1-1
1-1-1-2
1-1-2-1
1-2-1-1
2-1-1-1
1-2-2
2-1-2
2-2-1
Folie-444
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Treppe der Informatik» (Fortsetzung)
Visualisierung:
Treppe mit 5 Stufen
(Rest-)Treppe mit 4 Stufen
Treppe mit 3 Stufen
Folie-445
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Treppe der Informatik» (Fortsetzung)
Berechnung für das Beispiel:
Schrittfolgen für eine Treppe mit 5 Stufen =
Schrittfolgen für eine Treppe mit 4 Stufen
(wenn mit einem kleinen Schritt begonnen wurde)
+ Schrittfolgen für eine Treppe mit 3 Stufen
(wenn mit einem großen Schritt begonnen wurde)
Folie-446
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Treppe der Informatik» (Fortsetzung)
Berechnung für das Beispiel:
Schrittfolgen für eine Treppe mit 5 Stufen =
Schrittfolgen für eine Treppe mit 4 Stufen
(wenn mit einem kleinen Schritt begonnen wurde)
+ Schrittfolgen für eine Treppe mit 3 Stufen
(wenn mit einem großen Schritt begonnen wurde)
Berechnung (allgemein):
Schrittfolgen für eine Treppe mit n Stufen =
falls n <= 2:
n
sonst:
Schrittfolgen für eine Treppe mit n–1 Stufen
(wenn mit einem kleinen Schritt begonnen wurde)
+ Schrittfolgen für eine Treppe mit n–2 Stufen
(wenn mit einem großen Schritt begonnen wurde)
offensichtlich eine rekursive
Berechnungsvorschrift
Abbruchkriterium
Folie-447
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Treppe der Informatik» (Fortsetzung)
public static long routesToTop( long stairs )
{
if ( stairs <= 2 )
{
return stairs;
}
else
{
return routesToTop( stairs - 1 ) + routesToTop( stairs - 2 );
}
}
Die Implementierung setzt den zuvor entwickelten Algorithmus direkt um.
Folie-448
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Treppe der Informatik» (Fortsetzung)
public static long routesToTop( long stairs )
{
if ( stairs <= 2 )
{
return stairs;
}
else
{
return routesToTop( stairs - 1 ) + routesToTop( stairs - 2 );
}
}
Die Implementierung setzt den zuvor entwickelten Algorithmus direkt um.
Abbruchkriterium
Folie-449
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Treppe der Informatik» (Fortsetzung)
public static long routesToTop( long stairs )
{
if ( stairs <= 2 )
{
return stairs;
}
else
{
return routesToTop( stairs - 1 ) + routesToTop( stairs - 2 );
}
}
Die Implementierung setzt den zuvor entwickelten Algorithmus direkt um.
Die Ergebnisse der rekursiven Aufrufe liefern jeweils ein Ergebnis.
Die Ergebnisse werden addiert, um zum Ergebnis der aufrufenden Methode zu gelangen: +
Abbruchkriterium
rekursive Aufrufe
Reduktion
Folie-450
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Treppe der Informatik» (Fortsetzung)
public static long routesToTop( long stairs )
{
if ( stairs <= 2 )
{
return stairs;
}
else
{
return routesToTop( stairs - 1 ) + routesToTop( stairs - 2 );
}
}
Die Implementierung setzt den zuvor entwickelten Algorithmus direkt um.
Die Ergebnisse der rekursiven Aufrufe liefern jeweils ein Ergebnis.
Die Ergebnisse werden addiert, um zum Ergebnis der aufrufenden Methode zu gelangen: +
Der Aufruf routesToTop( 80 ) für das Informatik-Gebäude liefert: 37889062373143906
Der rechte Turm des Kölner Doms hat 533 Stufen:
Die Berechnung übersteigt die Grenzen des Wertebereichs long deutlich.
Abbruchkriterium
rekursive Aufrufe
Reduktion
Folie-451
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Treppe der Informatik» (Fortsetzung)
rekursive Aufrufstruktur für das Beispiel der Treppe mit fünf Stufen:
routesToTop( 5 )
routesToTop( 4 )
routesToTop( 3 )
routesToTop( 2 )
routesToTop( 1 )
routesToTop( 2 )
routesToTop( 3 )
routesToTop( 2 )
routesToTop( 1 )
Berechnungen für den gleichen Parameterwert werden immer wieder aufgerufen
und daher auch neu berechnet: routesToTop( 3 ) hier schon zweimal.
Folie-452
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Treppe der Informatik» (Fortsetzung)
rekursive Aufrufstruktur für eine Treppe mit sechs Stufen:
routesToTop( 6 )
routesToTop( 5 )
routesToTop( 4 )
routesToTop( 3 )
routesToTop( 2 )
routesToTop( 1 )
routesToTop( 2 )
routesToTop( 3 )
routesToTop( 2 )
routesToTop( 1 )
routesToTop( 4 )
routesToTop( 3 )
routesToTop( 2 )
routesToTop( 1 )
routesToTop( 2 )
Gleiche Berechnungen werden für große Treppen sehr häufig ausgeführt:
Für die Berechnung von routesToTop(20) werden beispielsweise 2639 Aufrufe
von routesToTop( 3 ) durchgeführt.
Folie-453
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Treppe der Informatik» (Fortsetzung)
Wie lassen sich wiederholte Berechnungen vermeiden?
Durch Speichern der berechneten Werte,
z.B. in einem Feld, das als Attribut für jeden Aufruf der Methode routesToTop zugreifbar ist.
routesToTop( 6 )
routesToTop( 5 )
routesToTop( 4 )
routesToTop( 3 )
routesToTop( 2 )
routesToTop( 1 )
routesToTop( 2 )
routesToTop( 3 )
routesToTop( 2 )
routesToTop( 1 )
routesToTop( 4 )
routesToTop( 3 )
routesToTop( 2 )
routesToTop( 1 )
routesToTop( 2 )
alle benötigten Werte werden berechnet
Folie-454
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Treppe der Informatik» (Fortsetzung)
Wie lassen sich wiederholte Berechnungen vermeiden?
Durch Speichern der berechneten Werte,
z.B. in einem Feld, das als Attribut für jeden Aufruf der Methode routesToTop zugreifbar ist.
routesToTop( 6 )
routesToTop( 5 )
routesToTop( 4 )
routesToTop( 3 )
routesToTop( 2 )
routesToTop( 1 )
routesToTop( 2 )
routesToTop( 3 )
routesToTop( 2 )
routesToTop( 1 )
routesToTop( 4 )
routesToTop( 3 )
routesToTop( 2 )
routesToTop( 1 )
routesToTop( 2 )
alle benötigten Werte werden berechnet
keine Berechnungen mehr notwendig
Folie-455
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Treppe der Informatik» (Fortsetzung)
Wie lassen sich wiederholte Berechnungen vermeiden?
Durch Speichern der berechneten Werte,
z.B. in einem Feld, das als Attribut für jeden Aufruf der Methode routesToTop zugreifbar ist.
routesToTop( 6 )
routesToTop( 5 )
routesToTop( 4 )
routesToTop( 3 )
routesToTop( 2 )
routesToTop( 1 )
routesToTop( 2 )
routesToTop( 3 )
routesToTop( 2 )
routesToTop( 1 )
routesToTop( 4 )
routesToTop( 3 )
routesToTop( 2 )
routesToTop( 1 )
routesToTop( 2 )
alle benötigten Werte werden berechnet
keine Berechnungen mehr notwendig
aber:
auch die rekursiven Aufrufe
sind überflüssig
Folie-456
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Treppe der Informatik» (Fortsetzung)
Wie lassen sich wiederholte Berechnungen vermeiden?
Durch Ändern der Reihenfolge der Berechnungen:
routesToTop( 6 )
routesToTop( 5 )
routesToTop( 4 )
routesToTop( 3 )
routesToTop( 2 )
routesToTop( 1 )
also:
routesToTop( 3 ) routesToTop( 2 ) + routesToTop( 1 )
routesToTop( 4 ) routesToTop( 3 ) + routesToTop( 2 )
routesToTop( 5 ) routesToTop( 4 ) + routesToTop( 3 )
routesToTop( 6 ) routesToTop( 5 ) + routesToTop( 4 )
Es werden zur Berechnung des nächsten Wertes immer nur
die Ergebnisse der letzten beiden Berechnungen benötigt:
zwei Variablen reichen aus
mit Schleife und paarweiser Addition
der berechneten Werte
Folie-457
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Treppe der Informatik» (Fortsetzung)
Lösung ohne Rekursion mit einer Schleife (Iteration)
public static long iterativRoutesToTop( long stairs )
{
if ( stairs <= 2 )
{
return stairs;
}
else
{
long next = 0, old1 = 1, old2 = 2;
for (int i = 3; i <= stairs; i++)
{
next = old1 + old2;
old1 = old2;
old2 = next;
}
return next;
}
}
direkt berechenbar
drei Variable
Addition
zur Zwischenablage
"Verschieben" der Inhalte
der Variablen
Folie-458
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Treppe der Informatik» (Fortsetzung)
Vergleich der rekursiven und der iterativen Lösung
Laufzeiten der rekursiven Lösung:
routesToTop( 35 ): 45 Millisekunden
routesToTop( 40 ): 421 Millisekunden
routesToTop( 45 ): 4641 Millisekunden
routesToTop( 50 ): 50560 Millisekunden
Laufzeiten der iterativen Lösung: < 1 Millisekunde
Folie-459
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Beispiel «Die Treppe der Informatik» (Fortsetzung)
Schlussfolgerungen für die Berechnung der Wege auf einer Treppe:
Der rekursive Lösungsansatz kann intuitiv gefunden werden.
Die Formulierung der rekursiven Lösung ist einfach.
Der Berechnungsaufwand der rekursiven Lösung ist hoch und nimmt schnell zu.
Die Analyse des rekursiven Lösungsansatzes kann als Ausgangspunkt für
die Entwicklung einer iterativen Lösung dienen.
Anmerkung:
Bei der durch routesToTop berechneten Zahlenfolge
handelt es sich um die Fibonacci-Zahlen.
(von Leonardo Fibonacci ca. 1200 in Pisa endeckt bei dem Versuch, das Wachstum einer
Kanninchen-Population zu beschreiben.)
Folie-460
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Zusammenfassung
Rekursion ist ein brauchbares Konzept zur Entwicklung von Algorithmen.
Rekursion ist ein brauchbares Konzept zur Implementierung von Algorithmen:
QuickSort, Umstapeln der Töpfe, Backtracking
(Bei diesen Beispielen finden keine überflüssigen rekursiven Aufrufe statt.)
Rekursive Algorithmen können dafür sorgen,
dass kaskadenartig Werte abgearbeitet werden:
– QuickSort bearbeitet so die ständig anwachsende Menge der kleiner werdenden Teile.
– Das Treppensteigen bearbeitet so die ständig anwachsende Menge der kleiner
werdenden Treppen.
Rekursive Algorithmen können ausnutzen,
dass nach Ausführung der rekursiven Aufrufe die Werte von Parametern und lokalen Variablen
noch verfügbar sind. So kann in jedem der Beispiele ein zweiter rekursiver Aufruf mit
vernünftigen Parameterwerten erfolgen:
– groupByNumber( leftBound, rightBound );
– rearrangePots( quantity - 1, 3 - start - target, target );
– existsBalanceUpTo( containers, limit, nextDivergence, unitsLoaded + 1 );
– return routesToTop( stairs - 1 ) + routesToTop( stairs - 2 );
Rekursive Algorithmen können wie andere Methoden Werte zurückgeben (routesToTop),
Seiteneffekte erzeugen (groupByNumber) oder Ausgaben vornehmen (rearrangePots).
Folie-461
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Folgerung
Wenn es möglich ist,
zu einem rekursiven Algorithmus routesToTop einen äquivalenten iterativen Algorithmus anzugeben,
kann dann auch zu iterativen Algorithmen ein äquivalenter rekursiver Algorithmus gefunden werden?
Dazu werden zwei (bekannte) Beispiele untersucht:
Berechnung der Summe der Quadrate aller natürlichen Zahlen bis zu einer Grenze n
(siehe Folie 105)
Berechnung des größten gemeinsamen Teilers
(siehe Folie 227)
Folie-462
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Folgerung (Fortsetzung)
Summe der Quadrate natürlicher Zahlen – rekursive Lösung
public static int recursiveSumOfSquares( int n )
{
if ( n > 1 ) {
return n * n + recursiveSumOfSquares( n – 1 );
}
else
{
return n;
}
}
Folie-463
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Folgerung (Fortsetzung)
Summe der Quadrate natürlicher Zahlen – rekursive Lösung
public static int recursiveSumOfSquares( int n )
{
if ( n > 1 ) {
return n * n + recursiveSumOfSquares( n – 1 );
}
else
{
return n;
}
}
rekursiver Aufruf
Reduktion
Abbruch-
kriterium
Folie-464
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Folgerung (Fortsetzung)
größter gemeinsamer Teiler – rekursive Lösung
public static int recursiveCalculateGcd( int v1, int v2 ) {
int i1 = Math.abs(v1);
int i2 = Math.abs(v2);
if (i1 != 0 & i2 != 0)
{
if ( i1 > i2 )
{
return recursiveCalculateGcd( i1 % i2, i2);
}
else
{
return recursiveCalculateGcd( i1, i2 % i1);
}
}
return i1 + i2;
}
Folie-465
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursion – Folgerung (Fortsetzung)
größter gemeinsamer Teiler – rekursive Lösung
public static int recursiveCalculateGcd( int v1, int v2 ) {
int i1 = Math.abs(v1);
int i2 = Math.abs(v2);
if (i1 != 0 & i2 != 0)
{
if ( i1 > i2 )
{
return recursiveCalculateGcd( i1 % i2, i2);
}
else
{
return recursiveCalculateGcd( i1, i2 % i1);
}
}
return i1 + i2;
}
rekursiver Aufruf
Reduktion
Abbruch-
kriterium
Folie-466
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rekursive Algorithmen
Ein rekursiver Algorithmus
ist dadurch gekennzeichnet, dass
eine Lösung für eine Problemsituation durch erneutes Anwenden des gleichen Algorithmus
auf eine etwas veränderte Situation ermittelt wird (rekursiver Aufruf).
Ein Ende der Ausführung wird dadurch sichergestellt, dass
für ausgezeichnete Situationen die Lösungen direkt ohne rekursiven Aufruf bestimmt werden können
und die rekursiven Aufrufe letztlich immer zu einer solchen Situation hinführen.
Folie-467
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Backtracking-Algorithmus
Ein Backtracking-Algorithmus
ist ein rekursiver Algorithmus,
bei dem die Schachtelung der rekursiven Aufrufe genutzt wird,
um einen Zwischenzustand der Lösungsentwicklung abzuspeichern,
um gegebenenfalls zu diesem Zwischenzustand zurückkehren zu können und
eine andere Fortsetzung der Lösungsentwicklung vorzunehmen.
Folie-468
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Rekursive Algorithmen
(siehe Folie 398)
Nach Durcharbeiten des Kapitels Rekursive Algorithmen sollen
die teilnehmenden Studierenden
den Grundaufbau rekursiver Methoden kennen
rekursive Algorithmen konzipieren und formulieren können
rekursive Methoden implementieren können
Backtracking als Prinzip der Gestaltung von Algorithmen kennen
die vorgestellten Beispiele für rekursive Methoden nachvollziehen können
Folie-469
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen, Algorithmen
und Programmierung 1 (DAP 1)
Fakultät für Informatik
Wintersemester 2019/20
Stefan Dissmann
Datenkompression (Huffman-Codierung)
Folie-470
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Datenkompression (Huffman-Codierung)
Nach Durcharbeiten des Kapitels Datenkompression sollen
die teilnehmenden Studierenden
Datenstrukturen aus Objekten konzipieren und implementieren können,
rekursive Datenstrukturen kennen,
rekursive Datenstrukturen entwerfen und implementieren können,
die Datenstruktur binärer Baum kennen, einsetzen und erweitern können,
den Algorithmus der Huffman-Codierung kennen.
Folie-471
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Motivation
aktuelles, alltagsrelevantes Thema
Bereiche Beispiele
Filme: mp4-Format (H.264)
Musik: mp3-Format, vorbis-Format, flac-Format
Bilder: jpeg-Format, png-Format
Texte: zip-Format, gzip-Format, jar-Format
Unterschiede:
verlustfreie Kompression
= Dekompression führt wieder zu den Originaldaten
(in der Regel bei Texten, Programmtexten, ausführbarem Code notwendig)
Folie-472
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Motivation
aktuelles, alltagsrelevantes Thema
Bereiche Beispiele
Filme: mp4-Format (H.264)
Musik: mp3-Format, vorbis-Format, flac-Format
Bilder: jpeg-Format, png-Format
Texte: zip-Format, gzip-Format, jar-Format
Unterschiede:
verlustfreie Kompression
= Dekompression führt wieder zu den Originaldaten
(in der Regel bei Texten, Programmtexten, ausführbarem Code notwendig)
verlustbehaftete Kompression
= Dekompression kann nicht die Originaldaten herstellen
(bei Filmen, Musik, Bildern möglich, da auf Details eventuell verzichtet werden kann:
die Kompression erfolgt spezifisch für den Anwendungsbereich)
Folie-473
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Motivation (Fortsetzung)
Beispiel:
True Color ermöglicht die Unterscheidung von etwa 16,78 Millionen Farben auf der Basis
von je 256 Abstufungen für die Farben Rot, Grün und Blau.
Im folgenden Bild tauchen aber nur 2 Farben auf.
Soll genau dieses Bild gespeichert werden, muss offensichtlich nicht für jedes Pixel
eine 24-Bit-Farbinformation abgelegt werden.
Folie-474
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Motivation (Fortsetzung)
Beispiel:
ASCII ermöglicht die Unterscheidung von 256 Zeichen.
Im folgenden Text tauchen aber nur 2 Zeichen auf.
Soll genau dieser Text gespeichert werden, muss offensichtlich nicht für jedes Zeichen
eine 8-Bit-Information abgelegt werden.
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Folie-475
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Motivation (Fortsetzung)
Hier wird als Beispiel betrachtet:
verlustfreie Kompression von Textdaten
(der vorgestellte Algorithmus wird aber als Ergänzung
auch in verlustbehafteten Verfahren eingesetzt)
Wann kann verlustfreie Kompression vorgenommen werden?
Wenn die Originaldaten überflüssige Informationen enthalten oder
das Speichern auf Einheiten basiert, die unabhängig von den vorliegenden Informationen sind.
Wie kann verlustfreie Kompression vorgenommen werden?
Indem genau die redundanten Informationen entfernt werden oder
die Speicherungsform an den Bedarf der vorliegenden Information geknüpft wird.
Folie-476
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Motivation (Fortsetzung)
Beispiel:
Dateien mit dem Beispiel-Java-Code zu dieser Vorlesung bestehen aus
– 52 (normalen) Buchstaben
– 10 Ziffern
– ca. 30 Sonderzeichen
also ca. 100 verschiedenen Zeichen
Dateien werden in den meisten Betriebssystemen so abgespeichert,
dass 1 Zeichen in 1 Byte abgelegt wird (z.B. nach ISO Latin 1 oder UTF-8 *) ).
1 Byte entspricht 8 Bit, also einer 8-stelligen Binärzahl.
1 Byte kann daher 256 Werte annehmen.
einfache Analyse:
Es ist offensichtlich, dass die Beispiel-Java-Programme
nur etwa 40% der mit einem Byte darstellbaren Informationen benötigen.
aber: Verkürzen der Speichergröße um 1 Bit (=12,5%)
verkürzt die darstellbaren Werte um 50%.
*) vergleiche Vorlesung Rechnerstrukturen
Folie-477
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Motivation (Fortsetzung)
Ziel der hier vorgestellten Kompression:
Reduktion des benötigten Speicherplatzes für einen festen Inhalt auf das notwendige Minimum.
Beispiel:
Kommen in einem Text nur die Buchstaben a, b, c, d, e vor,
dann müssen auch nur fünf Zeichen unterschieden werden.
Denkbar wäre also eine Kodierung derart,
dass maximal 2 Bit je Buchstabe vorgesehen werden:
a = (0)2 b = (1)2 c = (00)2 d = (01)2 e = (10)2
Folie-478
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Motivation (Fortsetzung)
Ziel der hier vorgestellten Kompression:
Reduktion des benötigten Speicherplatzes für einen festen Inhalt auf das notwendige Minimum.
Beispiel:
Kommen in einem Text nur die Buchstaben a, b, c, d, e vor,
dann müssen auch nur fünf Zeichen unterschieden werden.
Denkbar wäre also eine Kodierung derart,
dass maximal 2 Bit je Buchstabe vorgesehen werden:
a = (0)2 b = (1)2 c = (00)2 d = (01)2 e = (10)2
Diese Kodierung hat jedoch zwei Nachteile:
Bei der Dekompression ist unklar, ob (01)2 zu ab oder zu d expandiert werden soll.
Bei der Kompression muss also auch die Möglichkeit einer eindeutigen Dekompression
berücksichtigt werden.
Wenn beispielsweise e wesentlich häufiger als a im Text vorkommt,
dann ist die Kompression mit der oben vorgestellten Kodierung nicht minimal.
Die Häufigkeit des Auftretens eines Buchstabens muss also in die Kodierung eingehen.
Folie-479
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Motivation (Fortsetzung)
Sei t die Menge der Zeichen, die in einem zu komprimierenden Text t vorkommen.
Für das Beispiel gilt: t = { a, b, c, d, e } für einen Text t.
Dann ist t* die Menge aller beliebig langen Folgen aus diesen Zeichen.
Also gilt: aabcdab t* oder cccea t* oder t t*
Gesucht wird eine Abbildung c: t {0, 1}* (Kodierung der einzelnen Buchstaben)
so dass die Abbildung c*: t* {0, 1}* (Kodierung des ganzen Textes)
ein möglichst kurzes Bild c*(t) besitzt. (Kodierung ist spezifisch für Text t)
Folie-480
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Motivation (Fortsetzung)
Sei t die Menge der Zeichen, die in einem zu komprimierenden Text t vorkommen.
Für das Beispiel gilt: t = { a, b, c, d, e } für einen Text t.
Dann ist t* die Menge aller beliebig langen Folgen aus diesen Zeichen.
Also gilt: aabcdab t* oder cccea t* oder t t*
Gesucht wird eine Abbildung c: t {0, 1}* (Kodierung der einzelnen Buchstaben)
so dass die Abbildung c*: t* {0, 1}* (Kodierung des ganzen Textes)
ein möglichst kurzes Bild c*(t) besitzt. (Kodierung ist spezifisch für Text t)
Um die eindeutige Dekompression zu gewährleisten,
muss das Bild von c präfixfrei sein, d.h.
für beliebige x1 t, x2 t darf es kein b {0, 1}* geben mit c(x1) = c(x2)b
umgangssprachlich: Keine Kodierung eines Zeichens darf
den Anfang der Kodierung eines anderen Zeichens bilden.
(Beispielsweise müssen auch Telefonnummern präfixfrei sein.)
Folie-481
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Motivation (Fortsetzung)
Beispiel mit Text t mit t = { a, b, c, d, e }
Dann sind aufgrund der Forderung nach Präfixfreiheit folgende Bildmengen für Kodierungen denkbar:
c1 mit den folgenden Elementen im Bildbereich:
(0)2 Präfixfreiheit verbietet weitere Nutzung von 0 als Anfang
(10)2 Präfixfreiheit verbietet weitere Nutzung von 10 als Anfang
(110)2 Präfixfreiheit verbietet weitere Nutzung von 110 als Anfang
(1110)2 Präfixfreiheit verbietet weitere Nutzung von 1110 als Anfang
(1111)2
c2 mit den folgenden Elementen im Bildbereich:
(00)2 Präfixfreiheit verbietet weitere Nutzung von 00 als Anfang
(01)2 Präfixfreiheit verbietet weitere Nutzung von 01 als Anfang
(10)2 Präfixfreiheit verbietet weitere Nutzung von 10 als Anfang
(110)2 Präfixfreiheit verbietet weitere Nutzung von 110 als Anfang
(111)2
Weitere Kodierungsabbildungen sind entweder bis auf die 0-1-Kodierung analog oder
besitzen für jedes x t längere Einzelkodierungen, so dass c* zu einer längeren
Gesamtkodierung führen muss.
Feststellung: Die Auswahl und die Zuordnung der Bilder zu den x t muss sich aus der
Häufigkeit ergeben, mit denen die einzelnen x auftreten.
Folie-482
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Motivation (Fortsetzung)
Beispiel mit Text t mit t = { a, b, c, d, e }
Dieses überschaubare Beispiel hat nur zwei sinnvolle Lösungsmöglichkeiten.
Hier kann die Entscheidung leicht durch Ausprobieren getroffen werden.
In der Realität existieren jedoch bei mehr Zeichen sehr viel mehr Lösungsmöglichkeiten.
Begründung für die Auswahl der Codierung c1:
Die Kodierung mit der Länge 1 für e spart mehr Bits ein
als die dafür notwendigen Verlängerungen der Kodierungen für b, c und d kosten.
Zeichen a b c d e
Häufigkeit 30 20 10 15 80
benötigte Bits
c1 (10)2 (110)2 (1110)2 (1111)2 (0)2 300
c2 (00)2 (01)2 (110)2 (111)2 (10)2 335
Folie-483
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Motivation (Fortsetzung)
Ablauf einer Textkompression:
Originaltext
bestimme Zeichen
und Häufigkeiten
bestimme
komprimiere
010110
110011
komprimierte
Information
a:01
b:110
c:111
+
Kodierungsfunktion
Kodierungsfunktion
Originaltext mit
Kodierungsfunktion
Folie-484
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Algorithmus von Huffman
Der Algorithmus von David A. Huffman (aus dem Jahre 1952)
bestimmt konstruktiv die Kodierungsfunktion c.
Konstruktionsidee:
Aufbau eines binären Baums derart, dass
die in einem Text vorkommenden Zeichen die Blätter bilden,
die selten vorkommenden Zeichen an langen Ästen platziert werden und
die häufig vorkommenden Zeichen an kurzen Ästen platziert werden.
Dann lässt sich die Kodierung an den Pfaden im Baum ablesen.
Folie-485
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Algorithmus von Huffman (Fortsetzung)
(rekursive) Definition:
Ein binärer Baum ist
entweder ein leerer Baum
oder besteht aus einem Knoten, der einen linken und einen rechten Teilbaum besitzt,
die wieder binäre Bäume sind.
leerer Baum
Knoten
rechter Teilbaumlinker Teilbaum
Folie-486
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Algorithmus von Huffman (Fortsetzung)
binärer Baum – Beispiel
Knoten
leerer Baum
Folie-487
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Algorithmus von Huffman (Fortsetzung)
binärer Baum – Beispiel und Terminologie
Wurzel
innerer Knoten
Blatt
Folie-488
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Algorithmus von Huffman (Fortsetzung)
binärer Baum – Terminologie:
Die Wurzel (eines Baums) ist der einzige Knoten ohne Vorgänger (in diesem Baum).
(auch übliche Bezeichnung: Wurzel eines Teilbaums, z.B. )
Ein innerer Knoten besitzt mindestens einen nachfolgenden, nicht leeren Teilbaum.
(Beispiel: )
Ein Blatt ist ein Knoten mit zwei nachfolgenden, leeren Teilbäumen z.B. .
(Besitzt eine Baum nur genau einen Knoten, so ist dieser zugleich Wurzel und Blatt)
Folie-489
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Algorithmus von Huffman (Fortsetzung)
Konstruktionsidee:
Aufbau eines binären Baums derart, dass
die in einem Text vorkommenden Zeichen die Blätter bilden,
die selten vorkommenden Zeichen an langen Ästen platziert werden und
die häufig vorkommenden Zeichen an kurzen Ästen platziert werden.
Dann lässt sich die Kodierung an den Pfaden durch den Baum ablesen.
Vorgehen:
Lege für jedes zu kodierende Zeichen einen Baum mit genau einem Knoten an.
Sortiere die Bäume aufsteigend nach der Häufigkeit des Vorkommens.
Fasse die beiden ersten Bäume – also die mit der geringsten Häufigkeit – unter einem neuen
Wurzelknoten zusammen, dessen Häufigkeit sich als Summe der Häufigkeiten der beiden
Teilbäume ergibt.
Wiederhole dieses Vorgehen solange, bis nur noch ein Baum existiert.
Folie-490
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Algorithmus von Huffman (Fortsetzung)
Beispiel:
Zeichen a b c d e
Häufigkeit 30 20 10 15 80
c : 10 b : 20d : 15 a : 30 e : 80
aufsteigend sortiert
Folie-491
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Algorithmus von Huffman (Fortsetzung)
Beispiel:
c : 10 b : 20d : 15 a : 30 e : 80
c : 10 d : 15
: 25 neuer Knoten
= Wurzel des neu entstandenen Baums
Folie-492
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Algorithmus von Huffman (Fortsetzung)
Beispiel:
b : 20 a : 30
: 45
e : 80
c : 10 d : 15
: 25
b : 20
c : 10 d : 15
: 25
Folie-493
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Algorithmus von Huffman (Fortsetzung)
Beispiel:
: 75
a : 30
a : 30 e : 80 : 45
b : 20
c : 10 d : 15
: 25
: 45
b : 20
c : 10 d : 15
: 25
Folie-494
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Algorithmus von Huffman (Fortsetzung)
Beispiel:
: 155
: 75
a : 30 : 45
b : 20
c : 10 d : 15
: 25
e : 80
: 75
a : 30 : 45
b : 20
c : 10 d : 15
: 25
e : 80
Folie-495
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Algorithmus von Huffman (Fortsetzung)
Beispiel:
Ableiten der Kodierung: – Weg zum linken Teilbaum wird als 0 kodiert.
– Weg zum rechten Teilbaum wird als 1 kodiert.
– Kodierung eines Zeichens ergibt sich aus dem Pfad
von der Wurzel zu diesem Zeichen.
Zeichen Kodierung
a
b
c
d
e
: 155
: 75
a : 30 : 45
b : 20
c : 10 d : 15
: 25
e : 80
Folie-496
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Algorithmus von Huffman (Fortsetzung)
Beispiel:
Ableiten der Kodierung: – Weg zum linken Teilbaum wird als 0 kodiert.
– Weg zum rechten Teilbaum wird als 1 kodiert.
– Kodierung eines Zeichens ergibt sich aus dem Pfad
von der Wurzel zu diesem Zeichen.
Zeichen Kodierung
a 00
b 010
c 0110
d 0111
e 1
0
0
0
0
1
1
1
1
: 155
: 75
a : 30 : 45
b : 20
c : 10 d : 15
: 25
e : 80
Folie-497
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Algorithmus von Huffman (Fortsetzung)
Implementierung der Datenstrukturen für den Kodierungsbaum:
Die Klasse HuffmanTriple mit den für die Kompression notwendigen
– Attributen für das Zeichen, seine Häufigkeit und seine Kodierung.
Die Klasse HuffmanTree zur Repräsentation eines aus Knoten bestehenden Baums mit
– einem Attribut für ein HuffmanTriple,
– zwei Attributen für den linken und rechten Teilbaum zum Aufbau der Baumstruktur,
– geeigneten Konstruktoren,
– einer Methode zur Generierung der komprimierenden Kodierung für den Baum,
– einer Methode zur Ausgabe der Kodierung eines Baums.
Die Klasse HuffmanCoding auf der Grundlage der Klasse HuffmanTree mit
– einem Feld zum Speichern der schrittweise entstehenden Bäume,
– einem geeigneten Konstruktor,
– einer Methode zum Sortieren der Bäume,
– einer Methoden zum Aufbau des Huffman-Baums,
– einer Methode zur Ausgabe der Kodierung des Huffman-Baums.
Folie-498
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanTriple
public class HuffmanTriple
{
private char token;
private String code;
private int quantity;
…
benötigte Konstruktoren:
– Zeichen werden zunächst mit ihrer Häufigkeit bestimmt.
– Die Kodierung wird später ermittelt, kann also nicht im Konstruktor gesetzt werden.
benötigte Methoden:
– Lesen der Attribute
– Setzen der Kodierung
– Methode toString fürAusgaben
– Inkrementieren der Häufigkeit *)
*) Diese Methode wird später benötigt.
das Zeichen
die Kodierung
die Häufigkeit
Folie-499
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanTriple (Fortsetzung)
public class HuffmanTriple
{
private char token;
private String code;
private int quantity;
public HuffmanTriple( char t, int q )
{
token = t;
code = “”;
quantity = q;
}
public HuffmanTriple( char t )
{
this( t, 1 );
}
public HuffmanTriple()
{
this( ‘ ‘, 0 );
}
…
Konstruktoren
Folie-500
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanTriple (Fortsetzung)
public class HuffmanTriple
{
…
public char getToken()
{
return token;
}
public String getCode()
{
return code;
}
public int getQuantity()
{
return quantity;
}
public void setCode( String c )
{
code = c;
}
…
…
Zugriff auf die Attribute:
get-Methoden
Setzen der Kodierung
Folie-501
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanTriple (Fortsetzung)
public class HuffmanTriple
{
…
public void incrementQuantity()
{
quantity++;
}
public int compareTo( HuffmanTriple other)
{
return quantity – other.quantity;
}
public String toString()
{
return “token (quantity: ” + quantity + “): ” + token + ” -> code: ” + code ;
}
}
Inkrementieren der
Häufigkeit
Vergleich über
Häufigkeitswert
Folie-502
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanTree (Fortsetzung)
Überlegungen zur Struktur von Huffman-Bäumen
Jedes einzelne Zeichen bildet zunächst einen Baum mit genau einem Knoten:
Hierfür wird ein geeigneter Konstruktor benötigt.
Jeweils zwei Bäume werden unter einer neuen Wurzel zusammengesetzt:
Auch hierfür wird ein geeigneter Konstruktor benötigt.
Jeder innere Knoten eines Huffman-Baums besitzt immer genau zwei Nachfolgeknoten:
Diese Eigenschaft kann beim Bearbeiten eines Baums ausgenutzt werden.
Die Blätter eines Huffman-Baums enthalten die zu kodierenden Zeichen.
Folie-503
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanTree
public class HuffmanTree
{
private HuffmanTriple content;
private HuffmanTree leftChild, rightChild;
…
Die Klasse HuffmanTree ist eine rekursiv definierte Datenstruktur,
da die Deklaration der Klasse Bezug auf sich selbst nimmt.
Jedes HuffmanTree-Objekt enthält
– eine Referenz auf ein HuffmanTriple-Objekt,
– eine Referenz auf ein HuffmanTree-Objekt, das den linken Nachfolger bildet (leftChild),
– eine Referenz auf ein HuffmanTree-Objekt, das den rechten Nachfolger bildet (rightChild).
Ein leerer Baum ist dadurch gekennzeichnet,
dass content auf null verweist.
Ein Blatt ist dadurch gekennzeichnet,
dass leftChild und rightChild auf leere Bäume verweisen.
Die Datenstruktur hat keine vorgegebene Größe, sondern kann durch das Setzen
der Referenzen auf neu erzeugte HuffmanTree-Objekte vergrößert werden.
Inhalt eines Knotens
Baumstruktur
Folie-504
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanTree (Fortsetzung)
Beispiel für eine Objektstruktur
mit der Klasse HuffmanTree
: 45
b : 20
c : 10 d : 15
: 25
leftChild
rightChild
leftChild
rightChild
leftChild
rightChild
leftChild
rightChild
leftChild
rightChild
aus Beispiel:
content
content content
contentcontent
: 45
b : 20
c : 10
d : 15
: 25
…
null
null
null…
null null
null
…
null null
null
…
null null
null …
null null
null
…
null null
null
Folie-505
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanTree (Fortsetzung)
public class HuffmanTree
{
…
public HuffmanTree()
{
content = null;
leftChild = null;
rightChild = null;
}
public HuffmanTree( HuffmanTriple t )
{
content = t;
leftChild = new HuffmanTree();
rightChild = new HuffmanTree();
}
Konstruktor:
erzeugt leeren Baum
Konstruktor:
erzeugt Knoten mit Inhalt
Folie-506
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanTree (Fortsetzung)
public class HuffmanTree
{
…
public HuffmanTree( HuffmanTree lc, HuffmanTree rc )
{
content = new HuffmanTriple
(‘ ‘, lc.getContent().getQuantity()+rc.getContent().getQuantity());
leftChild = lc;
rightChild = rc;
}
public boolean isEmpty()
{
return content == null;
}
public boolean isLeaf()
{
return !isEmpty() && leftChild.isEmpty() && rightChild.isEmpty();
}
…
Konstruktor:
erzeugt Wurzel
leeren Baum identifizieren
Blatt identifizieren
Folie-507
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanTree (Fortsetzung)
public class HuffmanTree
{
…
public HuffmanTriple getContent()
{
if ( !isEmpty() )
{
return content;
} else {
throw new IllegalStateException();
}
}
public int compareTo ( HuffmanTree other )
{
if ( !isEmpty() && !other.isEmpty() )
{
return content.compareTo( other.content );
} else {
throw new IllegalStateException();
}
}
…
Zugriff auf Inhalt
Vergleich
Ausnahmesituation
Folie-508
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanTree (Fortsetzung)
public class HuffmanTree
{
…
public void generateCodes()
{
if ( !isEmpty() && !isLeaf() )
{
leftChild.content.setCode( content.getCode() + “0” );
rightChild.content.setCode( content.getCode() + “1” );
leftChild.generateCodes();
rightChild.generateCodes();
}
}
…
Erzeugen der Kodierung
Folie-509
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanTree (Fortsetzung)
public class HuffmanTree
{
…
public void generateCodes()
{
if ( !isEmpty() && !isLeaf() )
{
leftChild.content.setCode( content.getCode() + “0” );
rightChild.content.setCode( content.getCode() + “1” );
leftChild.generateCodes();
rightChild.generateCodes();
}
}
…
Die Methode generateCodes arbeitet rekursiv auf dem Baum und betrachtet immer zuerst den
linken und danach den rechten nachfolgenden Teilbaum.
rekursive Methode
Erzeugen der Kodierung
Folie-510
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanTree (Fortsetzung)
public class HuffmanTree
{
…
public void generateCodes()
{
if ( !isEmpty() && !isLeaf() )
{
leftChild.content.setCode( content.getCode() + “0” );
rightChild.content.setCode( content.getCode() + “1” );
leftChild.generateCodes();
rightChild.generateCodes();
}
}
…
Generieren für Teilbäume
Erzeugen der Kodierung
Folie-511
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanTree (Fortsetzung)
public class HuffmanTree
{
…
public void generateCodes()
{
if ( !isEmpty() && !isLeaf() )
{
leftChild.content.setCode( content.getCode() + “0” );
rightChild.content.setCode( content.getCode() + “1” );
leftChild.generateCodes();
rightChild.generateCodes();
}
}
…
Abbruchkriterium
Folie-512
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel – Ausführung von generateCodes
public void generateCodes()
{
if ( !isEmpty() && !isLeaf() )
{
leftChild.content.setCode( content.getCode() + “0” );
rightChild.content.setCode( content.getCode() + “1” );
leftChild.generateCodes();
rightChild.generateCodes();
}
} :155:
:75:
a:30: :45:
b:20:
c:10: d:15:
:25:
e:80:
tree.generateCodes()
Folie-513
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel – Ausführung von generateCodes (Fortsetzung)
public void generateCodes()
{
if ( !isEmpty() && !isLeaf() )
{
leftChild.content.setCode( content.getCode() + “0” );
rightChild.content.setCode( content.getCode() + “1” );
leftChild.generateCodes();
rightChild.generateCodes();
}
} :155:
:75:0
a:30: :45:
b:20:
c:10: d:15:
:25:
e:80:1
tree.generateCodes()
Folie-514
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel – Ausführung von generateCodes (Fortsetzung)
public void generateCodes()
{
if ( !isEmpty() && !isLeaf() )
{
leftChild.content.setCode( content.getCode() + “0” );
rightChild.content.setCode( content.getCode() + “1” );
leftChild.generateCodes();
rightChild.generateCodes();
}
} :155:
:75:0
a:30: :45:
b:20:
c:10: d:15:
:25:
e:80:1
tree.generateCodes()
generateCodes()
Folie-515
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel – Ausführung von generateCodes (Fortsetzung)
public void generateCodes()
{
if ( !isEmpty() && !isLeaf() )
{
leftChild.content.setCode( content.getCode() + “0” );
rightChild.content.setCode( content.getCode() + “1” );
leftChild.generateCodes();
rightChild.generateCodes();
}
} :155:
:75:0
a:30:00 :45:01
b:20:
c:10: d:15:
:25:
e:80:1
tree.generateCodes()
generateCodes()
Folie-516
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel – Ausführung von generateCodes (Fortsetzung)
public void generateCodes()
{
if ( !isEmpty() && !isLeaf() )
{
leftChild.content.setCode( content.getCode() + “0” );
rightChild.content.setCode( content.getCode() + “1” );
leftChild.generateCodes();
rightChild.generateCodes();
}
} :155:
:75:0
a:30:00 :45:01
b:20:
c:10: d:15:
:25:
e:80:1
tree.generateCodes()
generateCodes()
generateCodes()
Folie-517
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel – Ausführung von generateCodes (Fortsetzung)
public void generateCodes()
{
if ( !isEmpty() && !isLeaf() )
{
leftChild.content.setCode( content.getCode() + “0” );
rightChild.content.setCode( content.getCode() + “1” );
leftChild.generateCodes();
rightChild.generateCodes();
}
} :155:
:75:0
a:30:00 :45:01
b:20:
c:10: d:15:
:25:
e:80:1
tree.generateCodes()
generateCodes()
generateCodes()
Folie-518
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel – Ausführung von generateCodes (Fortsetzung)
public void generateCodes()
{
if ( !isEmpty() && !isLeaf() )
{
leftChild.content.setCode( content.getCode() + “0” );
rightChild.content.setCode( content.getCode() + “1” );
leftChild.generateCodes();
rightChild.generateCodes();
}
} :155:
:75:0
a:30:00 :45:01
b:20:
c:10: d:15:
:25:
e:80:1
tree.generateCodes()
generateCodes()
generateCodes()
Folie-519
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel – Ausführung von generateCodes (Fortsetzung)
public void generateCodes()
{
if ( !isEmpty() && !isLeaf() )
{
leftChild.content.setCode( content.getCode() + “0” );
rightChild.content.setCode( content.getCode() + “1” );
leftChild.generateCodes();
rightChild.generateCodes();
}
} :155:
:75:0
a:30:00 :45:01
b:20:010
c:10: d:15:
:25:011
e:80:1
tree.generateCodes()
generateCodes()
generateCodes()
Folie-520
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel – Ausführung von generateCodes (Fortsetzung)
public void generateCodes()
{
if ( !isEmpty() && !isLeaf() )
{
leftChild.content.setCode( content.getCode() + “0” );
rightChild.content.setCode( content.getCode() + “1” );
leftChild.generateCodes();
rightChild.generateCodes();
}
} :155:
:75:0
a:30:00 :45:01
b:20:010
c:10: d:15:
:25:011
e:80:1
tree.generateCodes()
generateCodes()
generateCodes()
generateCodes()
Folie-521
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel – Ausführung von generateCodes (Fortsetzung)
public void generateCodes()
{
if ( !isEmpty() && !isLeaf() )
{
leftChild.content.setCode( content.getCode() + “0” );
rightChild.content.setCode( content.getCode() + “1” );
leftChild.generateCodes();
rightChild.generateCodes();
}
} :155:
:75:0
a:30:00 :45:01
b:20:010
c:10: d:15:
:25:011
e:80:1
tree.generateCodes()
generateCodes()
generateCodes()
generateCodes()
Folie-522
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel – Ausführung von generateCodes (Fortsetzung)
public void generateCodes()
{
if ( !isEmpty() && !isLeaf() )
{
leftChild.content.setCode( content.getCode() + “0” );
rightChild.content.setCode( content.getCode() + “1” );
leftChild.generateCodes();
rightChild.generateCodes();
}
} :155:
:75:0
a:30:00 :45:01
b:20:010
c:10: d:15:
:25:011
e:80:1
tree.generateCodes()
generateCodes()
generateCodes()
generateCodes()
und analog fortsetzen …
Folie-523
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanTree (Fortsetzung)
public class HuffmanTree
{
…
public void showCodes()
{
if ( !isEmpty() )
{
if ( isLeaf() )
{
System.out.println( content.toString() );
}
else
{
leftChild.showCodes();
rightChild.showCodes();
}
}
}
}
Erinnerung: Kodierungen von Zeichen stehen nur in den Blättern des Huffman-Baums.
Ausgabe der Kodierungen
für die Blätter
rekursive Suche
nach Blättern
Folie-524
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanCoding
public class HuffmanCoding
{
private HuffmanTree[] trees;
…
Methoden der Klasse HuffmanCoding:
Konstruktor, der
– einzelne Zeichen als Bäume anlegt,
– die Bäume nach der Größenangabe in ihrem Wurzelknoten aufsteigend sortiert,
– die beiden kleinsten Bäume unter einem neuen Wurzelknoten zusammenfasst,
– diesen Vorgang solange wiederholt, bis nur noch ein Baum vorliegt, und
– abschließend die Kodierung erzeugt.
Methode showCodeTable(), die die Kodierungstabelle ausgibt.
Feld mit den Wurzeln
der Teilbäume
Folie-525
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanCoding (Fortsetzung)
public class HuffmanCoding
{
private HuffmanTree[] trees;
public HuffmanCoding( HuffmanTriple[] input )
{
// compression only if different tokens appear
if ( input.length > 1 )
{
initializeTrees( input );
buildTree();
trees[trees.length-1].generateCodes();
}
else
{
throw new IllegalStateException();
}
}
…
Konstruktor
Bäume anlegen
Bäume zusammenfassen
Kodierung eintragen
Folie-526
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanCoding (Fortsetzung)
public class HuffmanCoding
{
private HuffmanTree[] trees;
public HuffmanCoding( HuffmanTriple[] input )
{
// compression only if different tokens appear
if ( input.length > 1 )
{
initializeTrees( input );
buildTree();
trees[trees.length-1].generateCodes();
}
else
{
throw new IllegalStateException();
}
}
…
Ausführung auf
sonst: Abbruch
sinnvolle Situationen
beschränken
Folie-527
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanCoding (Fortsetzung)
public class HuffmanCoding
{
private HuffmanTree[] trees;
…
private void initializeTrees( HuffmanTriple[] input )
{
trees = new HuffmanTree[input.length];
for ( int i = 0; i < input.length; i++ )
{
trees[i] = new HuffmanTree( input[i] );
}
}
...
Es werden die Elemente eines Feldes von HuffmanTriple-Objekten als Inhalte
in die Elemente eines Feldes von HuffmanTree-Objekten übernommen.
Für jedes Zeichen liegt anschließend eine einelementiger Baum im Feld trees vor.
Feld von
Feld von Bäumen
HuffmanTriple-Objekten
Folie-528
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanCoding (Fortsetzung)
public class HuffmanCoding
{
private HuffmanTree[] trees;
...
private void buildTree()
{
for ( int i = 0; i+1 < trees.length; i++ )
{
insertionSort( i );
trees[i+1] = new HuffmanTree( trees[i], trees[i+1] );
}
}
...
Die relevanten Bäume (ab Index i) werden durch insertionSort( i ) sortiert.
Variation des insertionSort-Algorithmus, bei dem das Sortieren mit dem Index start
beginnt. So kann darauf reagiert werden, dass am Anfang des Feldes immer mehr Bäume
zusammengefasst werden.
Sortieren ab Index i
zwei Bäume werden
zusammengefasst
Folie-529
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanCoding (Fortsetzung)
Begründung für die Wahl von InsertionSort für als Sortieralgorithmus:
im ersten Durchlauf der Schleife muss eine vollständige Sortierung durchgeführt werden
ab dem zweiten Durchlauf muss jeweils nur der neu entstandene erste Baum
in die bereits sortierte Folge von Bäumen eingeordnet werden:
– sortierte Folgen führen bei QuickSort zu einem überflüssigen Aufbau von rekursiven
Aufrufen, die nur bereits sortierte Feldabschnitte überprüfen.
– SelectionSort führt immer sehr viele Vergleiche durch,
– InsertionSort erhält die bestehende Ordnung und verschiebt nur schrittweise den neu
entstandenen Baum an seine Position.
InsertionSort ermöglich also mit einem Algorithmus ein erstes Sortieren und anschließend ein
recht effizientes Einordnen in die sortierte Folge.
Folie-530
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanCoding (Fortsetzung)
Arbeitsweise der Methode buildTree() – Ausgangssituation:
Situation nach dem ersten Aufruf von insertionSort( 0 ):
trees
o:20 a:12 e:23 k:9 x:41 y:17
i
trees
k:9 a:12 y:17 o:20 e:23 x:41
i
Folie-531
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanCoding (Fortsetzung)
Arbeitsweise der Methode buildTree() – Situation nach erstem Durchlauf (i++ ist ausgeführt):
Situation nach dem Aufruf von insertionSort( 1 ) im zweiten Durchlauf:
a:12
trees
k:9
y:17 o:20 e:23 x:41
i
:21
(bedeutungslos)
trees
k:9 a:12
o:20 :21 e:23 x:41
i
y:17
Folie-532
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanCoding (Fortsetzung)
Arbeitsweise der Methode buildTree() – Situation nach zweiten Durchlauf (i++ ist ausgeführt):
Situation nach dem Aufruf von insertionSort( 2 ) im dritten Durchlauf:
:21
trees
k:9 a:12o:20
:21 e:23 x:41
i
y:17
:37
trees
k:9 a:12 o:20
e:23 :37 x:41
i
y:17
Folie-533
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanCoding (Fortsetzung)
public class HuffmanCoding
{
private HuffmanTree[] trees;
...
private void insertionSort( int start )
{
for ( int i = start + 1; i < trees.length; i++ )
{
shiftTrees( i );
}
}
...
Folie-534
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanCoding (Fortsetzung)
public class HuffmanCoding
{
private HuffmanTree[] trees;
...
private void shiftTrees( int start )
{
if ( start < trees.length )
{
HuffmanTree toInsert = trees[start];
int i = start;
while ( i > 0 &&
trees[i-1].compareTo( toInsert ) > 0 )
{
trees[i] = trees[i-1];
i–;
}
trees[i] = toInsert;
}
}
…
Folie-535
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Implementierung der Klasse HuffmanCoding (Fortsetzung)
public class HuffmanCoding
{
private HuffmanTree[] trees;
…
public void showCodeTable()
{
trees[trees.length-1].showCodes();
}
}
Nach Ausführung des Konstruktors ist der Huffman-Baum aufgebaut und
die Kodierung ist ermittelt und eingetragen.
Der Baum steht im letzten Element des Feldes trees.
Die Kodierung ist für jedes Zeichen in dem entsprechenden HuffmanTriple-Objekt abgelegt.
Folie-536
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Beispiel
HuffmanTriple[] tokens1 =
{ new HuffmanTriple( ‘a’, 30 ),
new HuffmanTriple( ‘b’, 20 ),
new HuffmanTriple( ‘c’, 10 ),
new HuffmanTriple( ‘d’, 15 ),
new HuffmanTriple( ‘e’, 80 )
};
HuffmanCoding hc = new HuffmanCoding( tokens1 );
hc.showCodeTable();
Folie-537
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Beispiel (Fortsetzung)
HuffmanTriple[] tokens1 =
{ new HuffmanTriple( ‘a’, 30 ),
new HuffmanTriple( ‘b’, 20 ),
new HuffmanTriple( ‘c’, 10 ),
new HuffmanTriple( ‘d’, 15 ),
new HuffmanTriple( ‘e’, 80 )
};
HuffmanCoding hc = new HuffmanCoding( tokens1 );
hc.showCodeTable();
token (quantity: 30): a -> code: 00
token (quantity: 20): b -> code: 010
token (quantity: 10): c -> code: 0110
token (quantity: 15): d -> code: 0111
token (quantity: 80): e -> code: 1
Ausgabe:
Folie-538
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Motivation (Erinnerung – Folie 483)
Ablauf einer Textkompression:
Originaltext
bestimme Zeichen
und Häufigkeiten
bestimme
komprimiere
010110
110011
komprimierte
Information
a:01
b:110
c:111
+
Kodierungsfunktion
Kodierungsfunktion
Originaltext mit
Kodierungsfunktion
Folie-539
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Datenkompression (Huffman-Codierung)
(siehe Folie 470)
Nach Durcharbeiten des Kapitels Datenkompression sollen
die teilnehmenden Studierenden
Datenstrukturen aus Objekten konzipieren und implementieren können,
rekursive Datenstrukturen kennen,
rekursive Datenstrukturen entwerfen und implementieren können,
die Datenstruktur binärer Baum kennen, einsetzen und erweitern können,
den Algorithmus der Huffman-Codierung kennen.
Folie-540
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen, Algorithmen
und Programmierung 1 (DAP 1)
Fakultät für Informatik
Wintersemester 2019/20
Stefan Dissmann
Datenstruktur Binärer Suchbaum
Folie-541
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Datenstruktur Binärer Suchbaum
Nach Durcharbeiten des Kapitels Datenstruktur Binärer Suchbaum sollen
die teilnehmenden Studierenden
die Definition der Datenstruktur binärer Suchbaum kennen,
einen binären Suchbaum aufbauen können,
in einem binären Suchbaum suchen können,
einen binärern Suchbaum durchlaufen können,
einen binären Suchbaum verändern können,
den Aufwand für Operationen auf einem Suchbaum grob abschätzen können,
Algorithmen für Tiefendurchläufe (InOrder, PreOrder, PostOrder) anwenden können,
die Implementierung der Klasse CharacterSearchTree verstehen und erweitern können.
Folie-542
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zählen von Zeichen
Problem:
In einem Text soll die Häufigkeit der vorkommenden Zeichen ermittelt werden. *)
Problemanalyse:
Die Anzahl der verschiedenen Zeichen ist unbekannt.
Das muss die eingesetzte Datenstruktur berücksichtigen.
Tritt ein Zeichen zum ersten Mal auf, muss es in die Datenstruktur aufgenommen werden.
Tritt ein Zeichen erneut auf, muss lediglich seine Häufigkeit erhöht werden.
In beiden Fällen muss das Zeichen gesucht (und gefunden) werden.
Bei einem langen Text muss also sehr häufig gesucht werden. Die Datenstruktur sollte also das
schnelle Suchen (und Finden) unterstützen.
*) Variation der Aufgabenstellung: In einem Bild soll die Pixel-Häufigkeit der vorkommenden Farben ermittelt werden.
Folie-543
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Motivation (Erinnerung – Folie 538)
Ablauf einer Textkompression:
Originaltext
bestimme Zeichen
und Häufigkeiten
komprimiere
010110
110011
komprimierte
Information
a:01
b:110
c:111
+
Kodierungsfunktion
Originaltext mit
Kodierungsfunktion
HuffmanCoding
HuffmanTree
Folie-544
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zählen von Zeichen (Fortsetzung)
Welche Datenstruktur ist geeignet?
Ein Feld ist eher ungeeignet, da
– es eine feste Länge hat
– ungünstig für eine unbekannte Anzahl von verschiedenen Zeichen/Informationen – und
– es bei der Suche sequentiell durchlaufen werden muss.
Eine rekursiv definierte Datenstruktur (binärer Baum) kann bei Bedarf wachsen,
da einfach weitere Knoten angefügt werden können.
Eine solche erweiterbare Datenstruktur heißt auch dynamische Datenstruktur.
(Knoten könnten auch gelöscht werden, so dass eine dynamische Anpassung in beide
Richtungen möglich wäre.)
Folie-545
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zählen von Zeichen (Fortsetzung)
Welche Datenstruktur ist geeignet?
Ein Feld ist eher ungeeignet, da
– es eine feste Länge hat
– ungünstig für eine unbekannte Anzahl von verschiedenen Zeichen/Informationen – und
– es bei der Suche sequentiell durchlaufen werden muss.
Eine rekursiv definierte Datenstruktur (binärer Baum) kann bei Bedarf wachsen,
da einfach weitere Knoten angefügt werden können.
Eine solche erweiterbare Datenstruktur heißt auch dynamische Datenstruktur.
(Knoten könnten auch gelöscht werden, so dass eine dynamische Anpassung in beide
Richtungen möglich wäre.)
Wie könnten die Zeichen im Baum angeordnet werden?
Idee aus QuickSort:
kleine und große Werte voneinander trennen!
Folie-546
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Binärer Suchbaum
Ein binärer Suchbaum
ist ein binärer Baum, für den gilt, dass
die Information in der Wurzel größer ist als jede Information in ihrem linken Teilbaum und
die Information in der Wurzel kleiner ist als jede Information in ihrem rechten Teilbaum und
der linke Teilbaum auch ein binärer Suchbaum ist und
der rechte Teilbaum auch ein binärer Suchbaum ist.
Der leere Baum ist auch ein binärer Suchbaum.
Folie-547
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Binärer Suchbaum (Fortsetzung)
Ein binärer Suchbaum
ist ein binärer Baum, für den gilt, dass
die Information in der Wurzel größer ist als jede Information in ihrem linken Teilbaum und
die Information in der Wurzel kleiner ist als jede Information in ihrem rechten Teilbaum und
der linke Teilbaum auch ein binärer Suchbaum ist und
der rechte Teilbaum auch ein binärer Suchbaum ist.
Konkretisierung:
Die Informationen in einem Baum, in dem nach Zeichen gesucht werden sollen,
sind Zeichen des Typs char.
Die Ordnungsrelation für diesen Baum ergibt sich daher aus der Ordnungsrelation,
die für die Werte des Typs char definiert sind.
Die Häufigkeiten werden zwar mit den Zeichen zusammen abgelegt.
Sie haben aber für die Struktur des Baums keine Bedeutung,
da nicht nach Häufigkeiten gesucht werden soll.
Folie-548
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Binärer Suchbaum (Fortsetzung)
Der Aufbau des binären Suchbaums erfolgt von der Wurzel aus!
Es sollen die Zeichen des folgenden Textes erfasst werden: “halloween”
root
Folie-549
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Binärer Suchbaum (Fortsetzung)
Der Aufbau des binären Suchbaums erfolgt von der Wurzel aus!
Es sollen die Zeichen des folgenden Textes erfasst werden: “halloween”
token: ’h’
quantity: 1
root
Folie-550
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Binärer Suchbaum (Fortsetzung)
Der Aufbau des binären Suchbaums erfolgt von der Wurzel aus!
Es sollen die Zeichen des folgenden Textes erfasst werden: “halloween”
token: ’h’
quantity: 1
root
token: ’h’
quantity: 1
root
token: ’a’
quantity: 1
Folie-551
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Binärer Suchbaum (Fortsetzung)
Der Aufbau des binären Suchbaums erfolgt von der Wurzel aus!
Es sollen die Zeichen des folgenden Textes erfasst werden: “halloween”
token: ’h’
quantity: 1
root
token: ’a’
quantity: 1
token: ’l’
quantity: 1
token: ’h’
quantity: 1
root
token: ’a’
quantity: 1
Folie-552
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root
token: ’a’
quantity: 1
Binärer Suchbaum (Fortsetzung)
Der Aufbau des binären Suchbaums erfolgt von der Wurzel aus!
Es sollen die Zeichen des folgenden Textes erfasst werden: “halloween”
token: ’l’
quantity: 1
token: ’h’
quantity: 1
root
token: ’a’
quantity: 1 ‘l’
Folie-553
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Binärer Suchbaum (Fortsetzung)
Der Aufbau des binären Suchbaums erfolgt von der Wurzel aus!
Es sollen die Zeichen des folgenden Textes erfasst werden: “halloween”
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root
token: ’a’
quantity: 1
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root
token: ’a’
quantity: 1
token: ’e’
quantity: 2
token: ’o’
quantity: 1
token: ’w’
quantity: 1
token: ’n’
quantity: 1
Folie-554
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Binärer Suchbaum (Fortsetzung)
Problemanalyse (Wiederholung von Folie 542):
Tritt ein Zeichen zum ersten Mal auf,
muss es in die Datenstruktur
aufgenommen werden.
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root
token: ’a’
quantity: 1
token: ’e’
quantity: 2
token: ’o’
quantity: 1
token: ’w’
quantity: 1
token: ’n’
quantity: 1
Folie-555
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Binärer Suchbaum (Fortsetzung)
Problemanalyse (Wiederholung von Folie 542):
Tritt ein Zeichen zum ersten Mal auf,
muss es in die Datenstruktur
aufgenommen werden.
Tritt ein Zeichen erneut auf,
muss lediglich seine Häufigkeit
erhöht werden.
Der Aufbau des Baums hängt
von der Reihenfolge der hinzu
gefügten Werte ab:
Die Buchstabenfolge “ahlloween”
führt zu einer anderen Baumstruktur!
Vor dem Einfügen eines neuen Knotens
in den Baum erfolgt immer erst eine Suche,
ob bereits ein passender Knoten existiert.
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root
token: ’a’
quantity: 1
token: ’e’
quantity: 2
token: ’o’
quantity: 1
token: ’w’
quantity: 1
token: ’n’
quantity: 1
Folie-556
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Binärer Suchbaum (Fortsetzung)
Suchvorgang:
In jedem Knoten wird überprüft,
ob das zu suchende Zeichen
kleiner: dann weiter nach links – oder
größer: dann weiter nach rechts – oder
gleich: gefunden!
ist.
Suchgeschwindigkeit:
Die Dauer der Suche wird durch
die Länge des Wegs von der Wurzel
zu dem gesuchten Knoten bestimmt.
Die Dauer der Suche ist also abhängig
von der Struktur des Baums.
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root
token: ’a’
quantity: 1
token: ’e’
quantity: 2
token: ’o’
quantity: 1
token: ’w’
quantity: 1
token: ’n’
quantity: 1
Folie-557
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Binärer Suchbaum (Fortsetzung)
Anmerkungen
Wenn alle Informationen, nach denen gesucht werden soll, mit gleicher Wahrscheinlichkeit
auftreten, dann ist die optimale Struktur für die Suche ein gleichmäßig aufgebauter Baum.
Ein gleichmäßig aufgebauter mit n Knoten besitzt eine Höhe von nur log2(n).
Eine Suche erfordert daher im optimalen Fall bei n Knoten höchstens log2(n) Vergleiche.
n w token: ’o’
quantity: 1
token: ’l’
quantity: 2
root
token: ’e’
quantity: 2
token: ’h’
quantity: 1
token: ’w’
quantity: 1
token: ’a’
quantity: 1
token: ’n’
quantity: 1
1 = 20 Knoten (Ebene 0)
2 = 21 Knoten (Ebene 1)
…
2n Knoten (Ebene n)
Folie-558
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Binärer Suchbaum (Fortsetzung)
Anmerkungen
Eine ungünstige Eingabe kann zu einem Baum mit nur wenigen, sehr langen Ästen führen, im
Extremfall zu einem einzigen Ast, auf dem alle Knoten liegen. Eine Suche erfordert dann für
n Knoten auch bis zu n Vergleiche.
Falls ein Baum beim Aufbau sehr ungleichmäßig wächst, kann er ausgeglichen *) werden.
*) Details hierzu werden in DAP 2 vorgestellt.
n w
token: ’o’
quantity: 1
token: ’l’
quantity: 2
root
token: ’e’
quantity: 2
token: ’h’
quantity: 1
token: ’w’
quantity: 1
token: ’a’
quantity: 1
token: ’n’
quantity: 1
Folie-559
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zählen von Zeichen (Fortsetzung)
public class CharacterSearchTree
{
private HuffmanTriple content;
private CharacterSearchTree leftChild, rightChild;
public CharacterSearchTree()
{
content = null;
leftChild = null;
rightChild = null;
}
…
Die Klasse CharacterSearchTree hat viele Gemeinsamkeiten mit der Klasse HuffmanTree:
Beide Klassen dienen dem Aufbau binärer Bäume.
Die Klassen enthalten Attribute für die gleichen Aufgaben: leftChild und rightChild für die
Konstruktion des Baums, content für den Inhalt eines Knotens
Die Konstruktionsregeln des binären Suchbaums drücken sich nicht in seinen Attributen aus.
Die Konstruktionsregeln werden von Methoden sichergestellt, die einen Baum erzeugen und
diesen verwalten.
Konstruktor:
Attribute für Zeichen,
Häufigkeit (und Kodierung)
Attribute für
Baumstruktur
legt einen leeren Baum an
Folie-560
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zählen von Zeichen (Fortsetzung)
public class CharacterSearchTree
{
…
public HuffmanTriple getContent()
{
if ( !isEmpty() )
{
return content;
} else {
throw new IllegalStateException();
}
}
public boolean isEmpty()
{
return content == null;
}
public boolean isLeaf()
{
return !isEmpty() && leftChild.isEmpty() && rightChild.isEmpty();
}
…
Blatt identifizieren
leeren Baum
identifizieren
Zugriff auf den Inhalt
des Knotens
Folie-561
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zählen von Zeichen (Fortsetzung)
Das Einfügen eines Zeichens in den Baum erfordert
entweder das Anlegen eines neuen Knotens für dieses Zeichen
oder das Erhöhen der Häufigkeit für das schon vorhandenen Zeichen:
public void add( char t )
{
if ( leerer Baum )
{
erzeuge Baum mit Inhalt t
}
else
{
suche, ob bereits ein Knoten mit Inhalt t existiert,
falls dieser gefunden wurde – erhöhe dessen Häufigkeit,
oder – falls Suche endgültig erfolglos – füge neuen Knoten mit t ein
}
}
Folie-562
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zählen von Zeichen (Fortsetzung)
public void add( char t )
{
if ( isEmpty() )
{
content = new HuffmanTriple( t );
leftChild = new CharacterSearchTree();
rightChild = new CharacterSearchTree();
}
else
{
suche, ob bereits ein Knoten mit Inhalt t existiert,
falls dieser gefunden wurde – erhöhe dessen Häufigkeit,
oder – falls Suche endgültig erfolglos – füge neuen Knoten mit t ein
}
}
Der leere Baum wird in ein Blatt umgewandelt, indem
– ein passendes HuffmanTriple-Objekt angelegt wird,
– die Referenzen für die nachfolgenden Teilbäume auf leere Bäume verweisen.
Blatt wird erzeugt.
leerer Baum liegt vor
Folie-563
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zählen von Zeichen (Fortsetzung)
public void add( char t )
{
if ( isEmpty() )
{
content = new HuffmanTriple( t );
leftChild = new CharacterSearchTree();
rightChild = new CharacterSearchTree();
}
else
{
if ( content.getToken() > t )
{
weiteres Einfügen im linken Teilbaum
}
else if ( content.getToken() < t )
{
weiteres Einfügen im rechten Teilbaum
}
else
{
erhöhe die Häufigkeit
}
}
}
Folie-564
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zählen von Zeichen (Fortsetzung)
public void add( char t )
{
if ( isEmpty() )
{
content = new HuffmanTriple( t );
leftChild = new CharacterSearchTree();
rightChild = new CharacterSearchTree();
}
else
{
if ( content.getToken() > t )
{
leftChild.add( t );
}
else if ( content.getToken() < t )
{
rightChild.add( t );
}
else
{
erhöhe die Häufigkeit
}
}
}
Rekursion auf
Teilbaum
Rekursion auf
Teilbaum
Folie-565
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zählen von Zeichen (Fortsetzung)
public void add( char t )
{
if ( isEmpty() )
{
content = new HuffmanTriple( t );
leftChild = new CharacterSearchTree();
rightChild = new CharacterSearchTree();
}
else
{
if ( content.getToken() > t )
{
leftChild.add( t );
}
else if ( content.getToken() < t )
{
rightChild.add( t );
}
else
{
content.incrementQuantity();
}
}
}
Folie-566
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Ausführung von add
public void add( char t )
{
if ( isEmpty() )
{
content = new HuffmanTriple( t );
leftChild = new CharacterSearchTree();
rightChild = new CharacterSearchTree();
}
else
{
if ( content.getToken() > t )
{
leftChild.add( t );
}
else if ( content.getToken() < t )
{
rightChild.add( t );
}
else
{
content.incrementQuantity();
}
}
}
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root.add( ’w’ )
token: ’a’
quantity: 1
token: ’o’
quantity: 1
Folie-567
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Ausführung von add (Fortsetzung)
public void add( char t )
{
if ( isEmpty() )
{
content = new HuffmanTriple( t );
leftChild = new CharacterSearchTree();
rightChild = new CharacterSearchTree();
}
else
{
if ( content.getToken() > t )
{
leftChild.add( t );
}
else if ( content.getToken() < t )
{
rightChild.add( t );
}
else
{
content.incrementQuantity();
}
}
}
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root.add( ’w’ )
token: ’a’
quantity: 1
token: ’o’
quantity: 1
add( ’w’ )
Folie-568
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Ausführung von add (Fortsetzung)
public void add( char t )
{
if ( isEmpty() )
{
content = new HuffmanTriple( t );
leftChild = new CharacterSearchTree();
rightChild = new CharacterSearchTree();
}
else
{
if ( content.getToken() > t )
{
leftChild.add( t );
}
else if ( content.getToken() < t )
{
rightChild.add( t );
}
else
{
content.incrementQuantity();
}
}
}
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root.add( ’w’ )
token: ’a’
quantity: 1
token: ’o’
quantity: 1
add( ’w’ )
add( ’w’ )
Folie-569
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Ausführung von add (Fortsetzung)
public void add( char t )
{
if ( isEmpty() )
{
content = new HuffmanTriple( t );
leftChild = new CharacterSearchTree();
rightChild = new CharacterSearchTree();
}
else
{
if ( content.getToken() > t )
{
leftChild.add( t );
}
else if ( content.getToken() < t )
{
rightChild.add( t );
}
else
{
content.incrementQuantity();
}
}
}
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root.add( ’w’ )
token: ’a’
quantity: 1
token: ’o’
quantity: 1
add( ’w’ )
add( ’w’ )
add( ’w’ )
Folie-570
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Ausführung von add (Fortsetzung)
public void add( char t )
{
if ( isEmpty() )
{
content = new HuffmanTriple( t );
leftChild = new CharacterSearchTree();
rightChild = new CharacterSearchTree();
}
else
{
if ( content.getToken() > t )
{
leftChild.add( t );
}
else if ( content.getToken() < t )
{
rightChild.add( t );
}
else
{
content.incrementQuantity();
}
}
}
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root.add( ’w’ )
token: ’a’
quantity: 1
token: ’o’
quantity: 1
token: ’w’
quantity: 1
add( ’w’ )
add( ’w’ )
add( ’w’ )
Folie-571
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zählen von Zeichen (Fortsetzung)
Das Feststellen der Anzahl der abgelegten, unterschiedlichen Zeichen lässt sich ebenfalls an die
nachfolgenden Teilbäume übertragen und daher rekursiv formulieren:
public int size()
{
if ( isEmpty() )
{
return 0;
}
else
{
return leftChild.size() + rightChild.size() + 1;
}
}
Jeder nicht-leere Teilbaum besteht aus
der Anzahl der Zeichen, die in den Teilbäumen abgelegt sind
leftChild.size() + rightChild.size()
und aus dem einen Zeichen in seiner Wurzel: + 1
leerer Baum:
enthält kein Zeichen
rekursive Aufrufe
Folie-572
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Ausführung von size
public int size()
{
if ( isEmpty() )
{
return 0;
}
else
{
return leftChild.size()
+ rightChild.size()
+ 1;
}
}
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root.size()
token: ’a’
quantity: 1
token: ’e’
quantity: 2
token: ’o’
quantity: 1
token: ’w’
quantity: 1
token: ’n’
quantity: 1
Folie-573
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Ausführung von size (Fortsetzung)
public int size()
{
if ( isEmpty() )
{
return 0;
}
else
{
return leftChild.size()
+ rightChild.size()
+ 1;
}
}
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root.size()
token: ’a’
quantity: 1
token: ’e’
quantity: 2
token: ’o’
quantity: 1
token: ’w’
quantity: 1
token: ’n’
quantity: 1
size()
Folie-574
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Ausführung von size (Fortsetzung)
public int size()
{
if ( isEmpty() )
{
return 0;
}
else
{
return leftChild.size()
+ rightChild.size()
+ 1;
}
}
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root.size()
token: ’a’
quantity: 1
token: ’e’
quantity: 2
token: ’o’
quantity: 1
token: ’w’
quantity: 1
token: ’n’
quantity: 1
size()
size()
Folie-575
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Ausführung von size (Fortsetzung)
public int size()
{
if ( isEmpty() )
{
return 0;
}
else
{
return leftChild.size()
+ rightChild.size()
+ 1;
}
}
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root.size()
token: ’a’
quantity: 1
token: ’e’
quantity: 2
token: ’o’
quantity: 1
token: ’w’
quantity: 1
token: ’n’
quantity: 1
size()
0
Folie-576
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Ausführung von size (Fortsetzung)
public int size()
{
if ( isEmpty() )
{
return 0;
}
else
{
return leftChild.size()
+ rightChild.size()
+ 1;
}
}
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root.size()
token: ’a’
quantity: 1
token: ’e’
quantity: 2
token: ’o’
quantity: 1
token: ’w’
quantity: 1
token: ’n’
quantity: 1
size()
size()
0
Folie-577
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Ausführung von size (Fortsetzung)
public int size()
{
if ( isEmpty() )
{
return 0;
}
else
{
return leftChild.size()
+ rightChild.size()
+ 1;
}
}
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root.size()
token: ’a’
quantity: 1
token: ’e’
quantity: 2
token: ’o’
quantity: 1
token: ’w’
quantity: 1
token: ’n’
quantity: 1
size()
size()
size()
0
Folie-578
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Ausführung von size (Fortsetzung)
public int size()
{
if ( isEmpty() )
{
return 0;
}
else
{
return leftChild.size()
+ rightChild.size()
+ 1;
}
}
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root.size()
token: ’a’
quantity: 1
token: ’e’
quantity: 2
token: ’o’
quantity: 1
token: ’w’
quantity: 1
token: ’n’
quantity: 1
size()
size()
0
0
Folie-579
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Ausführung von size (Fortsetzung)
public int size()
{
if ( isEmpty() )
{
return 0;
}
else
{
return leftChild.size()
+ rightChild.size()
+ 1;
}
}
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root.size()
token: ’a’
quantity: 1
token: ’e’
quantity: 2
token: ’o’
quantity: 1
token: ’w’
quantity: 1
token: ’n’
quantity: 1
size()
size()
size()0
0
Folie-580
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Ausführung von size (Fortsetzung)
public int size()
{
if ( isEmpty() )
{
return 0;
}
else
{
return leftChild.size()
+ rightChild.size()
+ 1;
}
}
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root.size()
token: ’a’
quantity: 1
token: ’e’
quantity: 2
token: ’o’
quantity: 1
token: ’w’
quantity: 1
token: ’n’
quantity: 1
size()
size()
00
0
Folie-581
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Ausführung von size (Fortsetzung)
public int size()
{
if ( isEmpty() )
{
return 0;
}
else
{
return leftChild.size()
+ rightChild.size()
+ 1;
}
}
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root.size()
token: ’a’
quantity: 1
token: ’e’
quantity: 2
token: ’o’
quantity: 1
token: ’w’
quantity: 1
token: ’n’
quantity: 1
size()
size()
0
0 + 0
Folie-582
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Ausführung von size (Fortsetzung)
public int size()
{
if ( isEmpty() )
{
return 0;
}
else
{
return leftChild.size()
+ rightChild.size()
+ 1;
}
}
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root.size()
token: ’a’
quantity: 1
token: ’e’
quantity: 2
token: ’o’
quantity: 1
token: ’w’
quantity: 1
token: ’n’
quantity: 1
size()
0
0 + 1
1
Folie-583
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Ausführung von size (Fortsetzung)
public int size()
{
if ( isEmpty() )
{
return 0;
}
else
{
return leftChild.size()
+ rightChild.size()
+ 1;
}
}
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root.size()
token: ’a’
quantity: 1
token: ’e’
quantity: 2
token: ’o’
quantity: 1
token: ’w’
quantity: 1
token: ’n’
quantity: 1
size()
0
0 + 1
1
Folie-584
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Ausführung von size (Fortsetzung)
public int size()
{
if ( isEmpty() )
{
return 0;
}
else
{
return leftChild.size()
+ rightChild.size()
+ 1;
}
}
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root.size()
token: ’a’
quantity: 1
token: ’e’
quantity: 2
token: ’o’
quantity: 1
token: ’w’
quantity: 1
token: ’n’
quantity: 1
2
1 + 1
Folie-585
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Ausführung von size (Fortsetzung)
public int size()
{
if ( isEmpty() )
{
return 0;
}
else
{
return leftChild.size()
+ rightChild.size()
+ 1;
}
}
2
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root.size()
token: ’a’
quantity: 1
token: ’e’
quantity: 2
token: ’o’
quantity: 1
token: ’w’
quantity: 1
token: ’n’
quantity: 1
size()
und analog fortsetzen für den rechten Teilbaum ...
2
Folie-586
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zählen von Zeichen (Fortsetzung)
Die Ausgabe der abgelegten, unterschiedlichen Zeichen und ihrer Häufigkeiten lässt sich ebenfalls an
die nachfolgenden Teilbäume übertragen und daher rekursiv formulieren:
public void show()
{
if ( !isEmpty() )
{
leftChild.show();
System.out.println( content.toString() );
rightChild.show();
}
}
Abbruchkriterium: Aufruf für den leeren Baum
leerer Baum würde
kein Zeichen enthalten
Folie-587
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zählen von Zeichen (Fortsetzung)
Die Ausgabe der abgelegten, unterschiedlichen Zeichen und ihrer Häufigkeiten lässt sich ebenfalls an
die nachfolgenden Teilbäume übertragen und daher rekursiv formulieren:
public void show()
{
if ( !isEmpty() )
{
leftChild.show();
System.out.println( content.toString() );
rightChild.show();
}
}
Ausgabe des linken Teilbaums durch rekursiven Aufruf der Methode show
Ausgabe des Inhalts der Wurzel
Ausgabe des rechten Teilbaums durch rekursiven Aufruf der Methode show
InOrder-Durchlauf: Die Wurzel wird zwischen (in) den beiden Teilbäumen bearbeitet.
rekursive Aufrufe
Folie-588
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zählen von Zeichen (Fortsetzung)
Die Übergabe der abgelegten, unterschiedlichen Zeichen und ihrer Häufigkeiten an ein Feld
wird als Eingabe für die Klasse HuffmanCoding benötigt.
Das Erzeugen eines solchen Feldes lässt sich ebenfalls über einen InOrder-Durchlauf rekursiv
formulieren.
Die Methode toArray() bereitet den InOrder-Durchlauf vor, indem ein passendes Feld für
HuffmanTriple-Objekte bereitgestellt wird.
Die Anzahl der benötigten Elemente wird durch den Aufruf der Methode size() ermittelt.
public HuffmanTriple[] toArray()
{
if ( !isEmpty() )
{
HuffmanTriple[] collector = new HuffmanTriple[size()];
toArray( collector, 0 );
return collector;
}
return new HuffmanTriple[0];
}
Folie-589
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zählen von Zeichen (Fortsetzung)
Die Methode toArray( HuffmanTriple[] collector, int index ) führt den InOrder-
Durchlauf durch, indem die in den Wurzeln der Teilbäume gefundenen HuffmanTriple-
Objekte in das Feld eingefügt werden.
Die Position für den nächsten Zugriff auf das Feld wird im Parameter index übergeben.
Der Ablauf der Rekursion wird über die besuchten Teilbäume und nicht über die beiden
Parameter der Methode gesteuert.
private int toArray( HuffmanTriple[] collector, int index )
{
if ( !isEmpty() )
{
index = leftChild.toArray( collector, index );
collector[index] = content;
index = rightChild.toArray( collector, index + 1 );
}
return index;
}
nach der Zuweisung
wird index erhöht
Folie-590
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zählen von Zeichen (Fortsetzung)
Anmerkungen:
Der durch die Klasse CharacterSearchTree aufgebaute binäre Baum ist eine
rekursive Datenstruktur.
Rekursive Datenstrukturen lassen sich leicht mit rekursiven Methoden bearbeiten.
Die vorgestellten rekursiven Methoden unterscheiden sich darin, wie die Rekursion eingesetzt
wird:
– Die Methoden size(), show() und toArray nutzen die Rekursion, um alle Teilbäume zu
erreichen.
– Die Methode add() folgt immer nur einem bestimmten, durch die Ergebnisse der
Vergleiche vorgegebenen Pfad von Knoten durch einen Teilbaum.
Daher kann die Methode add() auch iterativ, also durch Nutzung einer Schleife,
formuliert werden.
Folie-591
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zählen von Zeichen (Fortsetzung)
public void iterativeAdd( char t )
{
CharacterSearchTree current = this;
while ( !current.isEmpty() && current.content.getToken() != t )
{
if ( current.content.getToken() > t )
{
current = current.leftChild;
}
else
{
current = current.rightChild;
}
}
if ( current.isEmpty() )
{
current.content = new HuffmanTriple( t );
current.leftChild = new CharacterSearchTree();
current.rightChild = new CharacterSearchTree();
}
else
{
current.content.incrementQuantity();
}
}
Folie-592
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zählen von Zeichen (Fortsetzung)
public void iterativeAdd( char t )
{
CharacterSearchTree current = this;
while ( !current.isEmpty() && current.content.getToken() != t )
{
if ( current.content.getToken() > t )
{
current = current.leftChild;
}
else
{
current = current.rightChild;
}
}
if ( current.isEmpty() )
{
current.content = new HuffmanTriple( t );
current.leftChild = new CharacterSearchTree();
current.rightChild = new CharacterSearchTree();
}
else
{
current.content.incrementQuantity();
}
}
this ist Referenz auf
das ausführende Objekt
Folie-593
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Referenz this
Anmerkungen
Die Referenz this ist für jedes Objekt definiert.
this erlaubt den Zugriff auf das ausführende Objekt:
Methoden werden so in die Lage versetzt, eine Referenz auf das sie ausführende Objekt
zurückzugeben oder das eigene Objekt an andere Methoden als Argument zu übergeben.
this hilft beim Auflösen von Namenskonflikten:
Namenskonflikte zwischen Variablen und Attributen werden von Java immer zugunsten der
Variablen entschieden, da diese immer innerhalb von Methoden und damit «lokaler»
deklariert sind. this bezeichnet das Objekt, this. erlaubt den Zugriff auf verdeckte Attribute.
this
Folie-594
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zählen von Zeichen (Fortsetzung)
public void iterativeAdd( char t )
{
CharacterSearchTree current = this;
while ( !current.isEmpty() && current.content.getToken() != t )
{
if ( current.content.getToken() > t )
{
current = current.leftChild;
}
else
{
current = current.rightChild;
}
}
if ( current.isEmpty() )
{
current.content = new HuffmanTriple( t );
current.leftChild = new CharacterSearchTree();
current.rightChild = new CharacterSearchTree();
}
else
{
current.content.incrementQuantity();
}
}
Schleife bestimmt
Position für Aktion
Folie-595
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zählen von Zeichen (Fortsetzung)
public void iterativeAdd( char t )
{
CharacterSearchTree current = this;
while ( !current.isEmpty() && current.content.getToken() != t )
{
if ( current.content.getToken() > t )
{
current = current.leftChild;
}
else
{
current = current.rightChild;
}
}
if ( current.isEmpty() )
{
current.content = new HuffmanTriple( t );
current.leftChild = new CharacterSearchTree();
current.rightChild = new CharacterSearchTree();
}
else
{
current.content.incrementQuantity();
}
}
neues Zeichen
anlegen
Häufigkeit erhöhen
Folie-596
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse CharacterSearchTree – abschließender Überblick
public class CharacterSearchTree
{
private HuffmanTriple content;
private CharacterSearchTree leftChild, rightChild;
public CharacterSearchTree() { … }
public HuffmanTriple getContent() { … }
public boolean isEmpty() { … }
public boolean isLeaf() { … }
public void add( char t ) { … }
public void iterativeAdd( char t ) { … }
public String getCode( char t ) { … }
public int size() { … }
public void show() { … }
public HuffmanTriple[] toArray() { … }
private int toArray( HuffmanTriple[] collector, int index ) { … }
}
Attribute
Konstruktor
öffentliche Methoden
private Methode
Folie-597
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Motivation (Erinnerung – Folie 483 und Folie 538)
Ablauf einer Textkompression:
HuffmanCoding CharacterSearchTree
HuffmanTree
Originaltext
komprimiere
010110
110011
komprimierte
Information
a:01
b:110
c:111
+
Kodierungsfunktion
Originaltext mit
Kodierungsfunktion
Folie-598
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Beispiele
public static void firstTreeTest()
{
String s = “halloween” ;
CharacterSearchTree hal = new CharacterSearchTree();
for ( int i = 0; i < s.length() ; i++ )
{
hal.add( s.charAt( i ) );
}
System.out.println( "binary tree: " );
System.out.println( "--------------------------" );
hal.show();
}
Einfügen
Ausgeben
Eingabetext
Erzeugen
Folie-599
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Beispiele (Fortsetzung)
public static void firstTreeTest()
{
String s = "halloween" ;
CharacterSearchTree hal = new CharacterSearchTree();
for ( int i = 0; i < s.length() ; i++ )
{
hal.add( s.charAt( i ) );
}
System.out.println( "binary tree: " );
System.out.println( "--------------------------" );
hal.show();
}
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root
token: ’a’
quantity: 1
token: ’e’
quantity: 2
token: ’o’
quantity: 1
token: ’w’
quantity: 1
token: ’n’
quantity: 1
Folie-600
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Beispiele (Fortsetzung)
public static void firstTreeTest()
{
String s = "halloween" ;
CharacterSearchTree hal = new CharacterSearchTree();
for ( int i = 0; i < s.length() ; i++ )
{
hal.add( s.charAt( i ) );
}
System.out.println( "binary tree: " );
System.out.println( "--------------------------" );
hal.show();
}
binary tree:
--------------------------
token (quantity: 1): a -> code:
token (quantity: 2): e -> code:
token (quantity: 1): h -> code:
token (quantity: 2): l -> code:
token (quantity: 1): n -> code:
token (quantity: 1): o -> code:
token (quantity: 1): w -> code:
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root
token: ’a’
quantity: 1
token: ’e’
quantity: 2
token: ’o’
quantity: 1
token: ’w’
quantity: 1
token: ’n’
quantity: 1
Folie-601
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Beispiele (Fortsetzung)
public static void secondTreeTest()
{
String s = “Die Würde des Menschen ist unantastbar. Sie zu achten ” +
“und zu schützen ist Verpflichtung aller staatlichen Gewalt. ” +
“Das Deutsche Volk bekennt sich darum zu unverletzlichen und ” +
“unveräußerlichen Menschenrechten als Grundlage jeder menschlichen ” +
“Gemeinschaft, des Friedens und der Gerechtigkeit in der Welt. “;
CharacterSearchTree gg = new CharacterSearchTree();
for ( int i = 0; i < s.length() ; i++ )
{
gg.add( s.charAt( i ) );
}
System.out.println( "binary tree: " );
System.out.println( "--------------------------" );
gg.show();
}
GG Artikel 1
Folie-602
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Beispiele (Fortsetzung)
Ausgabe:
binary tree:
--------------------------
token (quantity: 41): -> code:
token (quantity: 1): , -> code:
token (quantity: 3): . -> code:
token (quantity: 3): D -> code:
token (quantity: 1): F -> code:
token (quantity: 4): G -> code:
token (quantity: 2): M -> code:
token (quantity: 1): S -> code:
token (quantity: 2): V -> code:
token (quantity: 2): W -> code:
token (quantity: 13): a -> code:
token (quantity: 2): b -> code:
token (quantity: 15): c -> code:
token (quantity: 12): d -> code:
token (quantity: 42): e -> code:
token (quantity: 2): f -> code:
token (quantity: 3): g -> code:
token (quantity: 15): h -> code:
token (quantity: 15): i -> code:
token (quantity: 1): j -> code:
token (quantity: 3): k -> code:
token (quantity: 13): l -> code:
token (quantity: 3): m -> code:
token (quantity: 26): n -> code:
token (quantity: 1): o -> code:
token (quantity: 1): p -> code:
token (quantity: 15): r -> code:
token (quantity: 16): s -> code:
token (quantity: 18): t -> code:
token (quantity: 14): u -> code:
token (quantity: 2): v -> code:
token (quantity: 1): w -> code:
token (quantity: 5): z -> code:
token (quantity: 1): ß -> code:
token (quantity: 1): ä -> code:
token (quantity: 2): ü -> code:
Folie-603
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Komprimierungsvorgang
Problem:
Zu jedem Zeichen des Originaltextes muss die Kodierung ermittelt und in den komprimierten Text
eingetragen werden.
Problemanalyse:
Bei einem langen Text muss also sehr häufig gesucht werden. Die Datenstruktur sollte also das
schnelle Suchen (und Finden) der Kodierung unterstützen.
Die passende Datenstruktur ist schon bekannt:
binärer Suchbaum
Aus dem Huffman-Baum, der die Kodierungen der Zeichen des Originaltextes enthält,
muss also ein binärer Suchbaum abgeleitet werden, der die gleichen Informationen enthält.
Folie-604
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Komprimierungsvorgang
Problem:
Zu jedem Zeichen des Originaltextes muss die Kodierung ermittelt und in den komprimierten Text
eingetragen werden.
Problemanalyse:
Bei einem langen Text muss also sehr häufig gesucht werden. Die Datenstruktur sollte also das
schnelle Suchen (und Finden) der Kodierung unterstützen.
Die passende Datenstruktur ist schon bekannt:
binärer Suchbaum
Aus dem Huffman-Baum, der die Kodierungen der Zeichen des Originaltextes enthält,
muss also ein binärer Suchbaum abgeleitet werden, der die gleichen Informationen enthält.
aber:
– Die im Huffman-Baum abgelegten HuffmanTriple-Objekte werden beim Einfügen in einen
binären Suchbaum erzeugt.
– Auch bei der Übergabe an den Huffman-Baum können die Referenzen im binären Suchbaum
erhalten bleiben.
– Die Kodierung kann nach ihrer Erzeugung durch den Konstruktor der Klasse HuffmanCoding
direkt über den binären Suchbaum abgerufen werden.
Folie-605
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Komprimierungsvorgang (Fortsetzung)
Visualisierung:
hal token: ’h’quantity: 1
code:
token: ’a’
quantity: 1
code:
token: ’l’
quantity: 2
code:
token: ’e’
quantity: 2
code: token: ’o’quantity: 1
code:
token: ’n’
quantity: 1
code:
token: ’w’
quantity: 1
code:binärer Suchbaum
Folie-606
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Komprimierungsvorgang (Fortsetzung)
Visualisierung:
hal token: ’h’quantity: 1
code:
token: ’a’
quantity: 1
code:
token: ’l’
quantity: 2
code:
token: ’e’
quantity: 2
code: token: ’o’quantity: 1
code:
token: ’n’
quantity: 1
code:
token: ’w’
quantity: 1
code:binärer Suchbaum
trees
Folie-607
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Komprimierungsvorgang (Fortsetzung)
Visualisierung:
hal token: ’h’quantity: 1
code:
token: ’a’
quantity: 1
code:
token: ’l’
quantity: 2
code:
token: ’e’
quantity: 2
code: token: ’o’quantity: 1
code:
token: ’n’
quantity: 1
code:
token: ’w’
quantity: 1
code:binärer Suchbaum
Huffman-Baum
trees
Folie-608
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Komprimierungsvorgang (Fortsetzung)
Visualisierung:
hal token: ’h’quantity: 1
code:001
token: ’a’
quantity: 1
code:000
token: ’l’
quantity: 2
code:10
token: ’e’
quantity: 2
code:01 token: ’o’quantity: 1
code:1111
token: ’n’
quantity: 1
code:1110
token: ’w’
quantity: 1
code:110binärer Suchbaum
Huffman-Baum
trees
Kodierung
Folie-609
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Komprimierungsvorgang (Fortsetzung)
Visualisierung:
hal token: ’h’quantity: 1
code:001
token: ’a’
quantity: 1
code:000
token: ’l’
quantity: 2
code:10
token: ’e’
quantity: 2
code:01 token: ’o’quantity: 1
code:1111
token: ’n’
quantity: 1
code:1110
token: ’w’
quantity: 1
code:110binärer Suchbaum
Folie-610
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Komprimierungsvorgang (Fortsetzung)
Benötigt wird eine Methode, die ein Zeichen im binären Suchbaum sucht und die Kodierung
zurückgibt.
public String getCode( char t )
{
if ( !isEmpty() )
{
if ( content.getToken() > t )
{
return leftChild.getCode( t );
} else if ( content.getToken() < t )
{
return rightChild.getCode( t );
} else
{
return content.getCode();
}
} else
{
throw new IllegalStateException();
}
}
Ablauf ist analog
zur Methode add
Rückgabe der gefundenen
Kodierung
Fehler: Kodierung nicht
gefunden
Folie-611
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Komprimierungsvorgang (Fortsetzung)
public static void firstTreeTest()
{
String s = "halloween" ;
CharacterSearchTree hal = new CharacterSearchTree();
for ( int i = 0; i < s.length() ; i++ )
{
hal.add( s.charAt( i ) );
}
HuffmanCoding coding = new HuffmanCoding( hal.toArray() );
String codeOfHal = "";
for ( int i = 0; i < s.length() ; i++ )
{
codeOfHal += hal.getCode( s.charAt( i ) );
}
System.out.println( "bit code: " );
System.out.println( "--------------------------" );
System.out.println( codeOfHal );
}
Einfügen
Kodierung generieren
Komprimieren
Ausgabe
Folie-612
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Komprimierungsvorgang (Fortsetzung)
public static void firstTreeTest()
{
String s = "halloween" ;
CharacterSearchTree hal = new CharacterSearchTree();
for ( int i = 0; i < s.length() ; i++ )
{
hal.add( s.charAt( i ) );
}
HuffmanCoding coding = new HuffmanCoding( hal.toArray() );
String codeOfHal = "";
for ( int i = 0; i < s.length() ; i++ )
{
codeOfHal += hal.getCode( s.charAt( i ) );
}
System.out.println( "code for halloween: " );
System.out.println( "--------------------------" );
System.out.println( codeOfHal );
}
binary tree with codes:
--------------------------
token (quantity: 1): a -> code: 000
token (quantity: 2): e -> code: 01
token (quantity: 1): h -> code: 001
token (quantity: 2): l -> code: 10
token (quantity: 1): n -> code: 1110
token (quantity: 1): o -> code: 1111
token (quantity: 1): w -> code: 110
Folie-613
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Komprimierungsvorgang (Fortsetzung)
public static void firstTreeTest()
{
String s = “halloween” ;
CharacterSearchTree hal = new CharacterSearchTree();
for ( int i = 0; i < s.length() ; i++ )
{
hal.add( s.charAt( i ) );
}
HuffmanCoding coding = new HuffmanCoding( hal.toArray() );
String codeOfHal = "";
for ( int i = 0; i < s.length() ; i++ )
{
codeOfHal += hal.getCode( s.charAt( i ) );
}
System.out.println( "code for halloween: " );
System.out.println( "--------------------------" );
System.out.println( codeOfHal );
}
binary tree with codes:
--------------------------
token (quantity: 1): a -> code: 000
token (quantity: 2): e -> code: 01
token (quantity: 1): h -> code: 001
token (quantity: 2): l -> code: 10
token (quantity: 1): n -> code: 1110
token (quantity: 1): o -> code: 1111
token (quantity: 1): w -> code: 110
bit code:
————————–
0010001010111111001011110
Folie-614
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Komprimierungsvorgang (Fortsetzung)
public static void firstTreeTest()
{
String s = “halloween” ;
CharacterSearchTree hal = new CharacterSearchTree();
for ( int i = 0; i < s.length() ; i++ )
{
hal.add( s.charAt( i ) );
}
HuffmanCoding coding = new HuffmanCoding( hal.toArray() );
String codeOfHal = "";
for ( int i = 0; i < s.length() ; i++ )
{
codeOfHal += hal.getCode( s.charAt( i ) );
}
System.out.println( "code for halloween: " );
System.out.println( "--------------------------" );
System.out.println( codeOfHal );
}
binary tree with codes:
--------------------------
token (quantity: 1): a -> code: 000
token (quantity: 2): e -> code: 01
token (quantity: 1): h -> code: 001
token (quantity: 2): l -> code: 10
token (quantity: 1): n -> code: 1110
token (quantity: 1): o -> code: 1111
token (quantity: 1): w -> code: 110
bit code:
————————–
0010001010111111001011110
Folie-615
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Komprimierungsvorgang (Fortsetzung)
public static void secondTreeTest()
{
String s = “Die Würde ………”;
CharacterSearchTree gg = new CharacterSearchTree();
for ( int i = 0; i < s.length() ; i++ )
{
gg.add( s.charAt( i ) );
}
HuffmanCoding coding = new HuffmanCoding( gg.toArray() );
String codeOfGG = "";
for ( int i = 0; i < s.length() ; i++ )
{
codeOfGG += gg.getCode( s.charAt( i ) );
}
System.out.println( "bit code: " );
System.out.println( "--------------------------" );
for ( int i = 0; i < codeOfGG.length() ; i++ )
{
System.out.print( codeOfGG.charAt( i ) );
// Formatierung fehlt hier
}
}
Folie-616
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Komprimierungsvorgang (Fortsetzung)
binary tree with codes:
--------------------------
token (quantity: 41): -> code: 100
token (quantity: 1): , -> code: 01011100
token (quantity: 3): . -> code: 1101011
token (quantity: 3): D -> code: 1101000
token (quantity: 1): F -> code: 01011101
token (quantity: 4): G -> code: 010101
token (quantity: 2): M -> code: 0101111
token (quantity: 1): S -> code: 01010010
token (quantity: 2): V -> code: 0101100
token (quantity: 2): W -> code: 0101101
token (quantity: 13): a -> code: 11100
token (quantity: 2): b -> code: 1100010
token (quantity: 15): c -> code: 0001
token (quantity: 12): d -> code: 11011
token (quantity: 42): e -> code: 101
token (quantity: 2): f -> code: 1100011
token (quantity: 3): g -> code: 1101001
token (quantity: 15): h -> code: 0010
token (quantity: 15): i -> code: 0011
token (quantity: 1): j -> code: 01010011
token (quantity: 3): k -> code: 1100110
token (quantity: 13): l -> code: 11101
token (quantity: 3): m -> code: 1100111
token (quantity: 26): n -> code: 1111
token (quantity: 1): o -> code: 01010000
token (quantity: 1): p -> code: 01010001
token (quantity: 15): r -> code: 0100
token (quantity: 16): s -> code: 0110
token (quantity: 18): t -> code: 0111
token (quantity: 14): u -> code: 0000
token (quantity: 2): v -> code: 1100000
token (quantity: 1): w -> code: 110101010
token (quantity: 5): z -> code: 110010
token (quantity: 1): ß -> code: 110101011
token (quantity: 1): ä -> code: 11010100
token (quantity: 2): ü -> code: 1100001
Folie-617
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Komprimierungsvorgang (Fortsetzung)
Ausgabe:
bit code:
————————–
11010000011101100010110111000010100110111011001101110101101000101111101111101100
00100101011111100001101100111100000011111110011110111111000110011111000101110001
00110101110001010010001110110011001000001001110000010010011110111111000000111111
01110011001000001000110000100101100001011111001010111111000011011001111000101100
10101000101000111000111110100110001001001110000111111010011001110011101111011010
10010001100111111001110001111110100110001001010111111000101011011101010101110011
10101111101011100110100011100011010011010001010000011101100001001010110001011000
10100001110111001101001100010101110011010111111111011110001100011000100101001101
11110001000000110011110011001000001000000111111000001010100111011010111110010111
01001100010010101111110000001111110111000000111111000001010100110101000000110101
01110101001110100110001001010111111000101111101111101100001001010111110100101000
10010011110111111001110011101011010001010101000000111111011111011110011010011011
00010100111011101110101001001100111101111101100001001011101001100010010101111110
00101011011100111101001111110110000100101110011000110111010111001001101110101101
00010111010100001110111011101111101101000000111111011100110111010100100010101101
01001010001001001110011110100111001101010011011110000111111100110111010100100010
11011011110101111101011100
input chars: 302
input bits: 2416
output bits: 1306
Folie-618
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenkompression – Motivation (Erinnerung – Folie 483, Folie 538 und Folie 597)
Ablauf einer Textkompression:
HuffmanCoding
CharacterSearchTree
HuffmanTree
Originaltext
010110
110011
komprimierte
Information
a:01
b:110
c:111
+
Kodierungsfunktion
Folie-619
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Analyse des InOrder-Durchlaufs für einen binären Suchbaum
Fragestellung:
In welcher Reihenfolge liefert ein InOrder-Durchlauf die Werte
aus dem binären Suchbaum?
Folie-620
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Analyse des InOrder-Durchlaufs für einen binären Suchbaum (Fortsetzung)
Fragestellung:
In welcher Reihenfolge liefert ein InOrder-Durchlauf die Werte
aus dem binären Suchbaum?
Antworthinweis:
Test mit InOrder-Durchlauf der show-Methode!
public void show()
{
if ( !isEmpty() )
{
leftChild.show();
System.out.println( content.toString() );
rightChild.show();
}
}
Folie-621
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Analyse des InOrder-Durchlaufs für einen binären Suchbaum (Fortsetzung)
=> aufsteigende Sortierung?
token (quantity: 15): i -> code: 0011
token (quantity: 1): j -> code: 01010011
token (quantity: 3): k -> code: 1100110
token (quantity: 13): l -> code: 11101
token (quantity: 3): m -> code: 1100111
token (quantity: 26): n -> code: 1111
token (quantity: 1): o -> code: 01010000
token (quantity: 1): p -> code: 01010001
token (quantity: 15): r -> code: 0100
token (quantity: 16): s -> code: 0110
token (quantity: 18): t -> code: 0111
token (quantity: 14): u -> code: 0000
token (quantity: 2): v -> code: 1100000
token (quantity: 1): w -> code: 110101010
token (quantity: 5): z -> code: 110010
token (quantity: 1): ß -> code: 110101011
token (quantity: 1): ä -> code: 11010100
token (quantity: 2): ü -> code: 1100001
binary tree with codes:
————————–
token (quantity: 41): -> code: 100
token (quantity: 1): , -> code: 01011100
token (quantity: 3): . -> code: 1101011
token (quantity: 3): D -> code: 1101000
token (quantity: 1): F -> code: 01011101
token (quantity: 4): G -> code: 010101
token (quantity: 2): M -> code: 0101111
token (quantity: 1): S -> code: 01010010
token (quantity: 2): V -> code: 0101100
token (quantity: 2): W -> code: 0101101
token (quantity: 13): a -> code: 11100
token (quantity: 2): b -> code: 1100010
token (quantity: 15): c -> code: 0001
token (quantity: 12): d -> code: 11011
token (quantity: 42): e -> code: 101
token (quantity: 2): f -> code: 1100011
token (quantity: 3): g -> code: 1101001
token (quantity: 15): h -> code: 0010
Buchstaben werden
in alphabetischer
Reihenfolge ausgegeben!
Folie-622
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Analyse des InOrder-Durchlaufs für einen binären Suchbaum (Fortsetzung)
Ablauf eines InOrder-Durchlaufs für jeden Teilbaum:
linken Teilbaum durchlaufen
Bearbeitung für die Wurzel (des Teilbaums)
rechten Teilbaum durchlaufen
Plausibilitätsbetrachtung:
Da alle Werte im linken Teilbaum kleiner sind als der Wert der Wurzel und
alle Werte im rechten Teilbaum größer sind als der Wert der Wurzel,
teilt die Wurzel den Durchlauf genau in den Durchlauf der kleineren und den Durchlauf der
größeren Werte.
Da diese Eigenschaft für jeden Teilbaum gilt,
werden die Knoten in aufsteigendender Reihenfolge besucht.
Folie-623
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Analyse des InOrder-Durchlaufs für einen binären Suchbaum (Fortsetzung)
Satz:
Der InOrder-Durchlauf besucht die Knoten des binären Suchbaums in aufsteigender Reihenfolge
bezüglich der für den Baum geltenden Ordnungsrelation.
Beweis:
Der Beweis erfolgt durch vollständige Induktion über die Höhe des Baums.
Die Höhe eines Baumes ist definiert als die Anzahl der Knoten auf dem längsten Pfad von der
Wurzel bis zu einem Blatt.
Folie-624
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Analyse des InOrder-Durchlaufs für einen binären Suchbaum (Fortsetzung)
Satz:
Der InOrder-Durchlauf besucht die Knoten des binären Suchbaums in aufsteigender Reihenfolge
bezüglich der für den Baum geltenden Ordnungsrelation.
Beweis:
Induktionsanfang: Für den leeren Baum mit der Höhe 0 gilt die Aussage.
Induktionsvoraussetzung:
Induktionsschritt:
Folie-625
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Analyse des InOrder-Durchlaufs für einen binären Suchbaum (Fortsetzung)
Satz:
Der InOrder-Durchlauf besucht die Knoten des binären Suchbaums in aufsteigender Reihenfolge
bezüglich der für den Baum geltenden Ordnungsrelation.
Beweis:
Induktionsanfang: Für den leeren Baum mit der Höhe 0 gilt die Aussage.
Induktionsvoraussetzung: Die Aussage des Satzes gilt für Bäume bis zur Höhe n.
Induktionsschritt:
Folie-626
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Analyse des InOrder-Durchlaufs für einen binären Suchbaum (Fortsetzung)
Satz:
Der InOrder-Durchlauf besucht die Knoten des binären Suchbaums in aufsteigender Reihenfolge
bezüglich der für den Baum geltenden Ordnungsrelation.
Beweis:
Induktionsanfang: Für den leeren Baum mit der Höhe 0 gilt die Aussage.
Induktionsvoraussetzung: Die Aussage des Satzes gilt für Bäume bis zur Höhe n.
Induktionsschritt: Sei ein Baum T der Höhe n+1 gegeben.
T besteht aus der Wurzel w und dem linken Teilbaum Tl und rechten
Teilbaum Tr.
Für Tl und Tr gilt, dass sie höchstens eine Höhe n besitzen, so dass der
InOrder-Durchlauf für sie gemäß der Induktionsvoraussetzung jeweils die
Knoten in aufsteigender Reihenfolge besucht.
Da in Tl alle Werte kleiner als der Wert von w sind und Tl vor w besucht
wird und in Tr alle Werte größer als der Wert von w sind und Tr nach w
besucht wird, werden die Knoten von T in aufsteigender Folge besucht.
Folie-627
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Analyse des InOrder-Durchlaufs für einen binären Suchbaum (Fortsetzung)
Konsequenzen:
Ein binärer Suchbaum kann zum Sortieren eingesetzt werden.
Für eine Abschätzung des notwendigen Aufwands müssen die Aufwände für das Einfügen der
Werte (bzw. Knoten) und den InOrder-Durchlauf zusammengerechnet werden.
Für jeden der n abgelegten Werte verhält sich der Aufwand zum Einfügen im günstigen Fall
proportional zu log2(n), der Gesamtaufwand also proportional zu n
. log2(n).
Beim InOrder-Durchlauf wird jedes Blatt einmal, jeder innere Knoten bis zu drei Mal besucht.
Der Aufwand für einen InOrder-Durchlauf verhält sich also proportional zu n.
Bei einer ungünstigen Eingabefolge kann sich der Aufwand zum Einfügen allerdings
proportional zu n entwickeln, der Gesamtaufwand also proportional zu n2.
Folie-628
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
PostOrder-Durchlauf für einen Baum
Ablauf eines PostOrder-Durchlaufs (analog zu InOrder-Durchlauf):
linken Teilbaum durchlaufen
rechten Teilbaum durchlaufen
Bearbeitung für die Wurzel
bekanntes Beispiel (aus der Klasse CharacterSearchTree):
public int size()
{
if ( isEmpty() )
{
return 0;
}
else
{
return leftChild.size() + rightChild.size() + 1;
}
}
letzte Operation für einen Knoten erfolgt
nach dem Durchlaufen beider Teilbäume
Folie-629
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
PreOrder-Durchlauf für einen Baum
Ablauf eines PreOrder-Durchlaufs (analog zu InOrder-Durchlauf):
Bearbeitung für die Wurzel
linken Teilbaum durchlaufen
rechten Teilbaum durchlaufen
bekanntes Beispiel (aus der Klasse HuffmanTree):
public void generateCodes()
{
if ( !isEmpty() && !isLeaf() )
{
leftChild.content.setCode( content.getCode() + “0” );
rightChild.content.setCode( content.getCode() + “1” );
leftChild.generateCodes();
rightChild.generateCodes();
}
}
letzte Operation für einen Knoten erfolgt
vor dem Durchlaufen der beiden Teilbäume
Folie-630
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Tiefendurchläufe durch binäre Bäume
Die Algorithmen
InOrder,
PostOrder und
PreOrder
werden auch unter dem Begriff Tiefendurchlauf zusammengefasst,
da immer ein Teilbaum bis zu seinen Blättern in die Tiefe bearbeitet wird,
bevor zum anderen Teilbaum gewechselt wird.
Knoten, die auf der gleichen Ebene im Baum liegen wie der aktuell betrachtete Knoten,
werden dabei immer später behandelt als Knoten,
die in den Teilbäumen des aktuell betrachteten Knotens weiter unten liegen.
Folie-631
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Datenstruktur Binärer Suchbaum
(siehe Folie 541)
Nach Durcharbeiten des Kapitels Datenstruktur Binärer Suchbaum sollen
die teilnehmenden Studierenden
die Definition der Datenstruktur binärer Suchbaum kennen,
einen binären Suchbaum aufbauen können,
in einem binären Suchbaum suchen können,
einen binärern Suchbaum durchlaufen können,
einen binären Suchbaum verändern können,
den Aufwand für Operationen auf einem Suchbaum grob abschätzen können,
Algorithmen für Tiefendurchläufe (InOrder, PreOrder, PostOrder) anwenden können,
die Implementierung der Klasse CharacterSearchTree verstehen und erweitern können.
Folie-632
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen, Algorithmen
und Programmierung 1 (DAP 1)
Fakultät für Informatik
Wintersemester 2019/20
Stefan Dissmann
Zwischenstand – weitere Ziele
Folie-633
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zwischenstand
bisher kennengelernte Datentypen:
primitive Typen:
– Zahlen (int, long, float, double)
– Zeichen (char)
– Wahrheitswerte (boolean)
Felder (mehrdimensionale Felder in der Übung)
Klassen
– Attribute
– Methoden
– Konstruktoren
– Zugriffsrechte
– Referenzvariablen
– Klasse String
bisher kennengelernte Ausdrücke und Anweisungen:
verschiedene Operatoren
Schleifen (while, for, for-each)
bedingte Anweisungen (if, if-else)
Folie-634
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zwischenstand (Fortsetzung)
bisher kennengelernte Datenstrukturen:
binäre Bäume
– Huffman-Baum (für Kodierung)
– binärer Suchbaum
dynamische Datenstrukturen auf Basis rekursiver Deklarationen
bisher kennengelernte Algorithmen:
Sortieralgorithmen
– SelectionSort
– InsertionSort
– QuickSort
rekursive Algorithmen
– für Berechnungen
– für Lösungssuche (Backtracking)
– für die Bearbeitung von rekursiven Datenstrukturen (InOrder)
Folie-635
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zwischenstand (Fortsetzung)
Alle bisher vorgestellten Implementierungen sind spezialisiert und
arbeiten nur für einen Problembereich
Viele der vorgestellten Algorithmen lösen aber allgemeine Problemstellungen:
– Die Sortieralgorithmen lassen sich auf beliebige Daten anwenden,
sofern eine Ordnung für die Daten definiert ist.
– Ein binärer Suchbaum kann zur Ablage beliebiger Daten eingesetzt werden,
sofern eine Ordnung für die Daten definiert ist.
Bisher sind Algorithmen und Datenstrukturen gegebenenfalls
durch Copy-and-paste voneinander abgeleitet worden.
Dieses Vorgehen führt aber – gerade auch in der Praxis – zu einigem Aufwand:
– Jede Anpassung erfordert Editierarbeiten und kann zu Fehlern an eigentlich nicht betroffenen
Abschnitten des Programmtextes führen.
– Jede Variante muss daher vollständig überprüft werden.
– Der historische Zusammenhang zwischen den Varianten muss dokumentiert werden, um
später erkannte Fehler auch in allen abgeleiteten Varianten beseitigen zu können.
Folie-636
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
weitere Ziele
Vorstellung von Konzepten in der Programmiersprache Java,
die die Implementierung von allgemein einsetzbaren Klassen (und damit Datenstrukturen)
ermöglichen:
Vererbung und Polymorphie
Vorstellung von allgemeinen Konzepten für die Konstruktion,
die eine flexible Anpassung von Algorithmen und Datenstrukturen ermöglichen:
Entwurfsmuster
Konstruktion allgemein einsetzbarer Datenstrukturen
Folie-637
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen, Algorithmen
und Programmierung 1 (DAP 1)
Fakultät für Informatik
Wintersemester 2019/20
Stefan Dissmann
Vererbung und Polymorphie
Folie-638
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Vererbung und Polymorphie
Nach Durcharbeiten des Kapitels Vererbung und Polymorphie sollen
die teilnehmenden Studierenden
das Konzept der Vererbung kennen und einsetzen können,
das Konzept polymorpher Methoden kennen und einsetzen können,
Klassenhierarchien gestalten und implementieren können,
die eine ist-ein-Beziehung umsetzen,
den Laufzeittyp und den statischen Typ von Referenzvariablen unterscheiden und bestimmen
können.
Folie-639
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Erinnerung: einfache Klassen
Beispiel
public class Person
{
private String firstName;
private String familyName;
private String cityOfResidence;
private int yearOfBirth;
public Person( String fi, String fa, String c, int y )
{
firstName = fi;
familyName = fa;
cityOfResidence = c;
yearOfBirth = y;
}
public String getFirstName() …
public String getFamilyName() …
public String getCity() …
public void setCity( String c ) …
public int getYearOfBirth() …
Attribute
Konstruktor
einfache Methoden
Folie-640
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Erinnerung: einfache Klassen (Fortsetzung)
Beispiel
public String toString()
{
return “family name: ” + familyName + “, first name: ” + firstName +
“, born in ” + yearOfBirth + “, living in: ” + cityOfResidence;
}
public boolean isEqualTo( Person p )
{
return ( familyName.compareTo( p.familyName ) == 0 )
&& ( firstName.compareTo( p.firstName ) == 0 )
&& yearOfBirth == p.yearOfBirth;
}
public int compareTo( Person p )
{
int compFamilyName = familyName.compareTo( p.familyName );
if ( compFamilyName != 0 ) {
return compFamilyName;
} else {
return firstName.compareTo( p.firstName );
}
}
alle Attributwerte als Text
«sinnvoller» Vergleich
compareTo über
lexikographischen
Namensvergleich:
compareTo aus der
Klasse String
Folie-641
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Erinnerung: einfache Klassen (Fortsetzung)
Beispiel
public class Student
{
private String name;
private String subject;
private int registrationNo;
…
Studierende haben wie Personen einen Namen.
Streng genommen haben Studierende auch
einen Vornamen, ein Geburtsjahr und einen Wohnort.
Studierende besitzen also auch alle Eigenschaften, die Personen haben,
da Studierende ja immer auch Personen sind.
Folie-642
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vererbung
Idee:
Ein Student ist eine spezielle Person,
die alle Eigenschaften einer Person besitzt
und zusätzliche Eigenschaften hinzu bekommt, die spezifisch für Studenten sind.
Folie-643
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vererbung (Fortsetzung)
Idee:
Ein Student ist eine spezielle Person,
die alle Eigenschaften einer Person besitzt
und zusätzliche Eigenschaften hinzu bekommt, die spezifisch für Studenten sind.
Umsetzung in Java:
Die Klasse Student erbt von der Klasse Person.
Person ist dann die Oberklasse von Student.
Student ist eine Unterklasse von Person.
Folie-644
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vererbung (Fortsetzung)
Idee:
Ein Student ist eine spezielle Person,
die alle Eigenschaften einer Person besitzt
und zusätzliche Eigenschaften hinzu bekommt, die spezifisch für Studenten sind.
Umsetzung in Java:
Die Klasse Student erbt von der Klasse Person.
Person ist dann die Oberklasse von Student.
Student ist eine Unterklasse von Person.
weitere Terminologie:
Die Klasse Student erweitert die Klasse Person.
Die Klasse Student spezialisiert die Klasse Person.
Eine Oberklasse wird auch Superklasse bezeichnet.
Eine Unterklasse wird auch Subklasse oder abgeleitete Klasse bezeichnet.
Folie-645
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vererbung (Fortsetzung)
Umsetzung in Java
public class Student extends Person
{
private String subject;
private int registrationNo;
…
Die Klasse Student erweitert die Klasse Person.
Die Klasse Student besitzt jetzt alle Attribute der Klasse Person:
– firstName, familyName, cityOfResidence, yearOfBirth
Die Klasse Student stellt auch alle Methoden der Klasse Person bereit:
– getFirstName, getFamilyName, getCity, …, compareTo
Der Konstruktor der Oberklasse wird nicht vererbt:
Die Klasse Person besitzt einen Konstruktor mit vier Parametern,
die Klasse Student besitzt (zunächst) keinen Konstruktor.
Die Details der Vererbung werden auf den folgenden Folien geklärt.
Schlüsselwort, hinter dem die Oberklasse folgt
eigene Attribut-Deklarationen
Folie-646
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Syntaxdiagramm zu Klasse
Bezeichner
{
Klasse
Klassenrumpf
class
}
Modifiziererliste
extends Bezeichner
Folie-647
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Visualisierung der Klassen
Student
Person
Spezialisierung (Vererbung)
(dargestellt in UML-Notation)
Folie-648
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Visualisierung der Klassen
Student
Person
mit den Attributen:
firstName, familyName, cityOfResidence, yearOfBirth
mit den Attributen:
firstName, familyName, cityOfResidence, yearOfBirth (geerbt)
subject, registrationNo
Folie-649
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vererbung (Fortsetzung)
Umsetzung in Java – Deklaration eines Konstruktors
public class Student extends Person
{
private String subject;
private int registrationNo;
public Student( String sub, int no )
{
subject = sub;
registrationNo = no;
}
Fehlermeldung des Compilers:
constructor Person in class Person cannot be applied to given types;
Erklärung:
Da jedes Objekt der Klasse Student alle Attribute der Klasse Person enthält, versucht der
Konstruktor der Klasse Student zunächst, diese geerbten Attribute anzulegen und zu
initialisieren.
Und dafür nutzt der Konstruktor der Klasse Student einen Konstruktor der Klasse Person.
Ist – wie hier – kein anderer Konstruktor explizit angegeben, so wird der Standardkonstruktor
(siehe Folie 264) benutzt, den es aber für die Klasse Person nicht gibt.
} Versuch, die geerbten Attribute erst einmal
zu ignorieren und gar nicht zu setzen
Konstruktor-Deklaration
Folie-650
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vererbung (Fortsetzung)
Umsetzung in Java – Deklaration eines Konstruktors
public class Student extends Person
{
private String subject;
private int registrationNo;
public Student( String fi, String fa, String c, int y, String sub, int no )
{
firstName = fi;
familyName = fa;
cityOfResidence = c;
yearOfbirth = y;
subject = sub;
registrationNo = no;
}
Fehlermeldung des Compilers:
constructor Person in class Person cannot be applied to given types;
Auch in dieser Implementierung wird versucht, den Standardkonstruktor zu nutzen,
den es aber für die Klasse Person nicht gibt.
} Versuch, alle geerbten Attribute zu setzen
Konstruktor-Deklaration
Folie-651
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vererbung (Fortsetzung)
Umsetzung in Java – Deklaration eines Konstruktors
public class Student extends Person
{
private String subject;
private int registrationNo;
public Student( String fi, String fa, String c, int y, String sub, int no )
{
firstName = fi;
familyName = fa;
cityOfResidence = c;
yearOfbirth = y;
subject = sub;
registrationNo = no;
}
Fehlermeldung des Compilers:
firstName has private access in Person;
Der Konstruktor der Klasse Student kann – wie auch alle anderen Methoden aus Student
nicht auf die privaten Attribute der Oberklasse Person zugreifen:
Mit dem Zugriffsrecht private gekennzeichnete Attribute oder Methoden der
Klasse Person sind immer nur in der Deklaration der Klasse Person sichtbar.
public class Person
{
public Person(){}
…
}
} Zugriff auf geerbte Attribute nicht möglich,da in Person als privat deklariert
Standardkonstruktor
ergänzt:
Folie-652
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vererbung (Fortsetzung)
Umsetzung in Java – Versuch der Deklaration eines Konstruktors
public class Student extends Person
{
private String subject;
private int registrationNo;
public Student( String fi, String fa, String c, int y, String sub, int no )
{
super( fi, fa, c, y );
subject = sub;
registrationNo = no;
}
In der Klasse Person hat der Konstruktor den Namen Person.
In seinen direkten Unterklassen kann er über das Schlüsselwort super aufgerufen werden.
Die erste Anweisung eines Konstruktors ist immer ein Aufruf eines Konstruktors der
Oberklasse:
Explizit durch Angabe von super gefolgt von einer Parameterliste oder
implizit – dann ergänzt der Compiler den Aufruf des Standardkonstruktors durch super().
Die implizite Form ist nur möglich, wenn die Oberklasse auch einen Standardkonstruktor bereit
stellt. (Das ist für die Klasse Person nicht der Fall.)
expliziter Aufruf des
Konstruktors der Oberklasse
Folie-653
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vererbung (Fortsetzung)
Umsetzung in Java – Versuch der Deklaration eines Konstruktors
public class Student extends Person
{
private String subject;
private int registrationNo;
public Student( String fi, String fa, String c, int y, String sub, int no )
{
super( fi, fa, c, y );
subject = sub;
registrationNo = no;
}
Der Konstruktor der Oberklasse ist ein Teil der Oberklasse.
Der Konstruktor der Oberklasse kann auf die privaten Attribute der Oberklasse zugreifen.
Durch die Übergabe von Argumenten an den Konstruktor der Oberklasse ist es daher möglich,
die privaten Attribute der Oberklasse mit Werten zu belegen.
expliziter Aufruf des
Konstruktors der Oberklasse
Folie-654
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vererbung (Fortsetzung)
Umsetzung in Java – Methoden in der Klasse Student
public String getSubject()
{
return subject;
}
public int getRegistrationNo()
{
return registrationNo;
}
public boolean hasGreaterNumber( Student s )
{
return getRegistrationNo() > s.getRegistrationNo();
}
public boolean hasEqualNumber( Student s )
{
return getRegistrationNo() == s.getRegistrationNo();
}
Diese Methoden greifen nur auf Attribute zu, die in der Klasse Student deklariert sind.
Das ist problemlos möglich.
Folie-655
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vererbung (Fortsetzung)
Umsetzung in Java – Methoden in der Klasse Student
Implementierung einer toString-Methode
public String toString()
{
return “family name: ” + getFamilyName() + “, first name: ” + getFirstName() +
“, born in ” + getYearOfBirth() + “, living in: ” + getCity() +
“, registration number: ” + getRegistrationNo() +
“(” + getSubject() + “)”;
}
Ausgabe:
family name: Miller, first name: Eva, born in 1979, living in: Bochum,
registration number: 171564(Math)
Die Werte der geerbten Attribute können über die geerbten öffentlichen Methoden abgerufen
werden.
Die Implementierung scheint aber etwas aufwändig, da ein Teil der Ausgabe bereits in der
toString-Methode der Klasse Person implementiert wurde.
Folie-656
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vererbung (Fortsetzung)
Umsetzung in Java – Methoden in der Klasse Student
Implementierung einer toString-Methode
public class Student extends Person
{
…
public String toString() {
return toString() +
“, registration number: ” + getRegistrationNo() + “(” + getSubject() + “)”;
}
}
Der Compiler erlaubt diese Implementierung.
Die Ausführung ist aber nicht erfolgreich:
toString() ist jetzt eine rekursive Methode ohne Abbruch-Kriterium,
da return toString() + …
sich auf die eigene Deklaration in der Klasse Student bezieht.
Folie-657
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vererbung (Fortsetzung)
Umsetzung in Java – Methoden in der Klasse Student
Implementierung einer toString-Methode
Student
Person
mit den Attributen:
firstName, familyName, cityOfResidence, yearOfBirth
mit den Attributen:
firstName, familyName, cityOfResidence, yearOfBirth (geerbt)
subject, registrationNo
mit den Methoden:
toString()
mit den Methoden:
toString() und geerbt, aber verdeckt: toString()
…
…
Folie-658
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vererbung (Fortsetzung)
Umsetzung in Java – Methoden in der Klasse Student
Implementierung einer toString-Methode
public String toString() {
return super.toString() + “, registration number: ”
+ getRegistrationNo() + “(” + getSubject() + “)”;
}
Methoden der Oberklasse können überschrieben werden:
toString() ist dann für die Klasse Student die in Student deklarierte Methode
und nicht die aus der Klasse Person geerbte Methode.
Das Überschreiben der Methode verhindert den Zugriff auf die geerbte Methode.
Der Zugriff mit super. erlaubt den expliziten Zugriff auf die (überschriebene) Methode der
direkten Oberklasse.
Das Schlüsselwort super hat also zwei Bedeutungen:
– super( … ) bezeichnet immer den Aufruf eines Konstruktors der Oberklasse und
ist darf nur als erste Anweisung eines eigenen Konstruktors verwandt werden.
– super. ist der Zugriff auf ein Element aus der direkten Oberklasse.
verweist auf die Methode der Oberklasse
Folie-659
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vererbung (Fortsetzung)
Umsetzung in Java – Methoden in der Klasse Student
Implementierung einer toString-Methode
Student
Person
mit den Attributen:
firstName, familyName, cityOfResidence, yearOfBirth
mit den Attributen:
firstName, familyName, cityOfResidence, yearOfBirth (geerbt)
subject, registrationNo
mit den Methoden:
toString()
mit den Methoden:
toString() und geerbt, aber überschrieben: toString()
…
…
super.toString()
Folie-660
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vererbung (Fortsetzung)
Umsetzung in Java – Methoden in der Klasse Student
Implementierung von Methoden zum Vergleichen von Objekten
public boolean hasGreaterName( Student s )
{
return compareTo( ? ) > 0;
}
public boolean hasEqualName( Student s )
{
return compareTo( ? ) == 0;
}
Die geerbte Methode compareTo eignet sich gut für die einfache Implementierung von
Vergleichsmethoden in der Klasse Student.
aber:
Die geerbte Methode compareTo erwartet eine Referenz auf Person als Argument,
hasGreaterName und hasEqualName sollen aber Student-Objekte miteinander vergleichen.
geerbte Methode erwartet
Referenz auf Person
Folie-661
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vererbung (Fortsetzung)
Umsetzung in Java – Methoden in der Klasse Student
Implementierung von Methoden zum Vergleichen von Objekten (Fortsetzung)
public boolean hasGreaterName( Student s )
{
return compareTo( s ) > 0;
}
public boolean hasEqualName( Student s )
{
return compareTo( s ) == 0;
}
Da die Klasse Student von der Klasse Person erbt,
kann ein Objekt der Klasse Student auf alle Methodenaufrufe reagieren,
die an ein Objekt der Klasse Person gestellt werden können.
Jedes Objekt der Klasse Student ist daher typkompatibel mit der Klasse Person.
Ein Objekt einer Unterklasse kann also ein Objekt der Oberklasse ersetzen.
Daher darf eine Referenzvariable, die als deklarierten Typ die Oberklasse besitzt,
zur Laufzeit auf ein Objekt der Unterklasse – das ist dann der Laufzeittyp – verweisen.
Das Student-Objekt an der
Referenz s ist kompatibel
zur Klasse Person
Folie-662
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vererbung (Fortsetzung)
Beispiele:
Person x = new Student( “Tina”, “Mueller”, “Bonn”, 1999, M, 190184 );
public class Person
{
…
public int compareTo( Person p ) { … }
}
public class Student extends Person
{
…
public boolean hasGreaterName( Student s )
{
return compareTo( s ) > 0;
}
}
deklarierter Typ von p
ist Person
Laufzeittyp von p
ist Student
Laufzeittyp von x ist Student
deklarierter Typ von x ist Person
Folie-663
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vererbung (Fortsetzung)
Umsetzung in Java – Methoden in der Klasse Student
public boolean isEqualTo( Student s )
{
return super.isEqualTo( s )
&& getRegistrationNo() == s.getRegistrationNo();
}
Es liegt kein Überschreiben der geerbten isEqualTo-Methode vor:
– Geerbt aus Person wird eine Methode mit der Signatur isEqualTo( Person ),
– neu definiert in Student wird eine Methode mit der Signatur isEqualTo( Student ).
Die Namensgleichheit der beiden Methoden zusammen mit der Vererbungsbeziehung
zwischen den Klassen Student und Person machen diese Konstruktion möglich.
Die geerbte Methode isEqualTo( Person ) lässt auch die Klasse Student als Laufzeittyp
für das übergebene Argument zu, da Student von Person erbt.
Die Verwendung von super. ist notwendig, da der Compiler sonst wieder von der Deklaration
einer rekursiven Methode ausgehen würde.
Folie-664
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen
Eine Referenzvariable, deren deklarierter Typ eine Oberklasse ist,
darf als Laufzeittyp auch auf Objekte der Unterklassen verweisen.
Da Objekte der Unterklasse alle Eigenschaften der Oberklasse erben,
kann ein Objekt der Unterklasse wie ein Objekt der Oberklasse behandelt werden.
Alle Methoden, die für ein Objekt der Oberklasse aufgerufen werden dürfen,
sind also auch für ein Objekt der Unterklasse verfügbar und
können für dieses aufgerufen werden.
Methoden können in Unterklassen überschrieben werden.
Beim Aufruf stehen verschiedene Versionen der gleichen Methode zur Verfügung:
– in der Oberklasse: Hier erfolgt eine Deklaration der Methode.
– in der Unterklasse: Hier sind die geerbte – aber nicht mehr sichtbare – Version
und die im Rahmen des Überschreibens vorgenommene eigene
Deklaration der Methode verfügbar.
Folie-665
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen (Fortsetzung)
Eine Referenzvariable, deren deklarierter Typ eine Oberklasse ist,
darf als Laufzeittyp auch auf Objekte der Unterklassen verweisen.
Da Objekte der Unterklasse alle Eigenschaften der Oberklasse erben,
kann ein Objekt der Unterklasse wie ein Objekt der Oberklasse behandelt werden.
Alle Methoden, die für ein Objekt der Oberklasse aufgerufen werden dürfen,
sind also auch für ein Objekt der Unterklasse verfügbar und
können für dieses aufgerufen werden.
Methoden können in Unterklassen überschrieben werden.
Beim Aufruf stehen verschiedene Versionen der gleichen Methode zur Verfügung:
– in der Oberklasse: Hier erfolgt eine Deklaration der Methode.
– in der Unterklasse: Hier sind die geerbte – aber nicht mehr sichtbare – Version
und die im Rahmen des Überschreibens vorgenommene eigene
Deklaration der Methode verfügbar.
Eine Verallgemeinerung von Algorithmen und Datenstrukturen ist also folgendermaßen möglich:
Lege eine Vererbungsstruktur aus Oberklasse und Unterklassen an.
Implementiere gemeinsame Algorithmen und Datenstrukturen für die Oberklasse.
Überschreibe einzelne Methoden in einzelnen Unterklassen,
um das Verhalten der zugehörigen Objekte anzupassen.
Folie-666
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen (Fortsetzung)
Eine Referenzvariable, deren deklarierter Typ eine Oberklasse ist,
darf als Laufzeittyp auch auf Objekte der Unterklassen verweisen.
Da Objekte der Unterklasse alle Eigenschaften der Oberklasse erben,
kann ein Objekt der Unterklasse wie ein Objekt der Oberklasse behandelt werden.
Alle Methoden, die für ein Objekt der Oberklasse aufgerufen werden dürfen,
sind also auch für ein Objekt der Unterklasse verfügbar und
können für dieses aufgerufen werden.
Methoden können in Unterklassen überschrieben werden.
Beim Aufruf stehen verschiedene Versionen der gleichen Methode zur Verfügung:
– in der Oberklasse: Hier erfolgt eine Deklaration der Methode.
– in der Unterklasse: Hier sind die geerbte – aber nicht mehr sichtbare – Version
und die im Rahmen des Überschreibens vorgenommene eigene
Deklaration der Methode verfügbar.
Eine Verallgemeinerung von Algorithmen und Datenstrukturen ist also folgendermaßen möglich:
Lege eine Vererbungsstruktur aus Oberklasse und Unterklassen an.
Implementiere gemeinsame Algorithmen und Datenstrukturen für die Oberklasse.
Überschreibe einzelne Methoden in einzelnen Unterklassen,
um das Verhalten der zugehörigen Objekte anzupassen.
Für Unterklassen stellt sich noch die Frage: Welche Version der Methode wird ausgeführt?
Folie-667
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen – Experimente
Person p = new Student( “S”, “S”, “S”, 1, “S”, 1 );
System.out.println( p.toString() );
Ausgabe:
family name: S, first name: S, born in 1, living in: S, registration number: 1(S)
Ein Student-Objekt an einer Person-Referenzvariablen ruft toString von Student auf:
– deklarierter Typ von p: Person
– Laufzeittyp des von p referenzierten Objekts: Student
Annahme aufgrund des Experiments:
Es wird die passende Methode des Laufzeittyps ausgewählt.
Folie-668
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
toString() ist eine parameterlose Methode,
Namensgleichheit und Überschreiben fallen immer zusammen.
Was geschieht, wenn namensgleiche Methoden mit unterschiedlichen Signaturen
(d.h. unterschiedlichen Parameterlisten) auftreten:
– die Typen der Parameter sind inkompatibel:
Compiler überprüft anhand der übergebenen Argumente die Signatur und
wählt die passende Methode aus.
– die Typen der Parameter sind kompatibel:
Beispiel: Methoden isEqualTo( Person p ) und isEqualTo( Student s )
Ein Objekt der Klasse Student kann
über eine Referenzvariable sowohl der Klasse Person
als auch der Klasse Student als Argument übergeben werden.
Welche Methode wird wann aufgerufen? Experiment
Folie-669
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
in der Klasse Person ergänzt:
public void whichMethod( Person p )
{
System.out.println( “Person” );
}
in der Klasse Student ergänzt:
public void whichMethod( Student p )
{
System.out.println( “Student” );
}
Die Methoden sind namensgleich, haben Parameterlisten gleicher Länge,
die Parameter besitzen unterschiedlich deklarierte Typen,
die aber durch Vererbung zueinander kompatibel sind.
Die Methoden geben den Namen der Klasse aus, in der sie deklariert sind.
Folie-670
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
Student
Person mit Methode whichMethod( Person p )
mit Methoden whichMethod( Person p ) (geerbt)
und whichMethod( Student s )
deklarierte Typen der
Parameter sind zueinander
kompatible Klassen
Folie-671
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
Experimentierumgebung
private static void display( String opt, String ort, String pdt, String prt )
{
System.out.print( opt + “\t\t” + ort + “\t\t” + pdt + “\t\t” + prt + “\t\t” );
}
public static void testTypeCombinations()
{
Person pWithP = new Person( “P”, “P”, “C”, 1 );
Student sWithS = new Student( “S”, “S”, “C”, 1, “S”, 1 );
Person pWithS = sWithS;
System.out.println( “calling object\t\targument” );
System.out.println( “declared type\truntime type\tdeclared type\truntime type\tmethod from” );
System.out.println( “————————————————————————” );
display( “Person”, “Person”, “Person”, “Person” ); pWithP.whichMethod( pWithP );
display( “Person”, “Person”, “Person”, “Student” ); pWithP.whichMethod( pWithS );
display( “Person”, “Person”, “Student”, “Student” ); pWithP.whichMethod( sWithS );
display( “Person”, “Student”, “Person”, “Person” ); pWithS.whichMethod( pWithP );
display( “Person”, “Student”, “Person”, “Student” ); pWithS.whichMethod( pWithS );
display( “Person”, “Student”, “Student”, “Student” ); pWithS.whichMethod( sWithS );
display( “Student”, “Student”, “Person”, “Person” ); sWithS.whichMethod( pWithP );
display( “Student”, “Student”, “Person”, “Student” ); sWithS.whichMethod( pWithS );
display( “Student”, “Student”, “Student”, “Student” ); sWithS.whichMethod( sWithS );
}
Folie-672
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
Experimentierumgebung
public static void testTypeCombinations()
{
Person pWithP = new Person( “P”, “P”, “C”, 1 );
Student sWithS = new Student( “S”, “S”, “C”, 1, “S”, 1 );
Person pWithS = sWithS;
…
}
Es werden drei Referenzvariablen angelegt:
– Person pWithP verweist auf ein Person-Objekt
– Person pWithS verweist auf ein Student-Objekt
– Student sWithS verweist auf ein Student-Objekt (– geht auch nicht anders)
Über jede der Referenzvariablen wird der Aufruf vorgenommen.
Jede der Referenzvariablen wird als Argument übergeben.
Referenzen und Objekte anlegen
Person
4 Attribute
Student
6 AttributepWithP
pWithS
sWithS
Folie-673
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
Experimentierumgebung
System.out.println( “calling object\t\targument” );
System.out.println( “declared type\truntime type\tdeclared type\truntime type\tmethod from” );
System.out.println( “————————————————————————” );
display( “Person”, “Person”, “Person”, “Person” ); pWithP.whichMethod( pWithP );
display( “Person”, “Person”, “Person”, “Student” ); pWithP.whichMethod( pWithS );
display( “Person”, “Person”, “Student”, “Student” ); pWithP.whichMethod( sWithS );
display( “Person”, “Student”, “Person”, “Person” ); pWithS.whichMethod( pWithP );
display( “Person”, “Student”, “Person”, “Student” ); pWithS.whichMethod( pWithS );
display( “Person”, “Student”, “Student”, “Student” ); pWithS.whichMethod( sWithS );
display( “Student”, “Student”, “Person”, “Person” ); sWithS.whichMethod( pWithP );
display( “Student”, “Student”, “Person”, “Student” ); sWithS.whichMethod( pWithS );
display( “Student”, “Student”, “Student”, “Student” ); sWithS.whichMethod( sWithS );
Die neun möglichen Kombinationen werden aufgerufen
und das Ergebnis wird tabellarisch ausgegeben.
‘\t’ ist ein Zeichen des Typs char, das Tabulator-Zeichen.
manchmal auch hilfreich: ‘\n’ für einen Zeilenumbruch.
formatierte Ausgabe
Folie-674
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
Ausgabe:
calling reference argument
declared type runtime type declared type runtime type method from
——————————————————————————-
Person Person Person Person Person
Person Person Person Student Person
Person Person Student Student Person
Person Student Person Person Person
Person Student Person Student Person
Person Student Student Student Person
Student Student Person Person Person
Student Student Person Student Person
Student Student Student Student Student
Nur bei einer Kombination wird die Methode der Klasse Student aufgerufen.
Warum?
Folie-675
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
Ausgabe:
calling reference argument
declared type runtime type declared type runtime type method from
——————————————————————————-
Person Person Person Person Person
Person Person Person Student Person
Person Person Student Student Person
…
Der Compiler kennt als Eigenschaft der Referenzvariablen:
und wählt zur Ausführung die Methode: whichMethod( Person p )
Person mit Methode whichMethod( Person p )
Folie-676
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
Ausgabe:
calling reference argument
declared type runtime type declared type runtime type method from
——————————————————————————-
Person Person Person Person Person
Person Person Person Student Person
Person Person Student Student Person
Person Student Person Person Person
Person Student Person Student Person
Person Student Student Student Person
Student Student Person Person Person
Student Student Person Student Person
Student Student Student Student Student
Die Referenzvariable, über die der Aufruf erfolgt, ist für die Klasse Person deklariert.
In der Klasse Person ist eine Methode whichMethod mit Parameter Person bekannt.
Der Compiler nimmt eine statische Analyse anhand der deklarierten Typen vor.
Der Compiler sieht für die Ausführung die Methode whichMethod( Person ) vor.
Das Objekt der Klasse Person führt die Methode whichMethod( Person ) aus.
Folie-677
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
Ausgabe:
calling reference argument
declared type runtime type declared type runtime type method from
——————————————————————————-
…
Person Student Person Person Person
Person Student Person Student Person
Person Student Student Student Person
…
Der Compiler kennt als Eigenschaft der Referenzvariablen:
und wählt zur Ausführung die Methode: whichMethod( Person p )
Person mit Methode whichMethod( Person p )
Folie-678
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
Ausgabe:
calling reference argument
declared type runtime type declared type runtime type method from
——————————————————————————-
Person Person Person Person Person
Person Person Person Student Person
Person Person Student Student Person
Person Student Person Person Person
Person Student Person Student Person
Person Student Student Student Person
Student Student Person Person Person
Student Student Person Student Person
Student Student Student Student Student
Die Referenzvariable, über die der Aufruf erfolgt, ist für die Klasse Person deklariert.
In der Klasse Person ist eine Methode whichMethod mit Parameter Person bekannt.
Der Compiler nimmt eine statische Analyse anhand der deklarierten Typen vor.
Der Compiler sieht für die Ausführung die Methode whichMethod( Person ) vor.
Die Klasse Student hat die Methode whichMethod( Person ) von Person geerbt.
Das Objekt der Klasse Student führt die Methode whichMethod( Person ) aus.
Folie-679
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
Ausgabe:
calling reference argument
declared type runtime type declared type runtime type method from
——————————————————————————-
…
Student Student Person Person Person
Student Student Person Student Person
…
Der Compiler kennt als Eigenschaft der Referenzvariablen:
und wählt zur Ausführung die Methode: whichMethod( Person p )
Student mit Methoden whichMethod( Person p ) (geerbt)
und whichMethod( Student s )
Folie-680
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
Ausgabe:
calling reference argument
declared type runtime type declared type runtime type method from
——————————————————————————-
Person Person Person Person Person
Person Person Person Student Person
Person Person Student Student Person
Person Student Person Person Person
Person Student Person Student Person
Person Student Student Student Person
Student Student Person Person Person
Student Student Person Student Person
Student Student Student Student Student
Die Referenzvariable, über die der Aufruf erfolgt, ist für die Klasse Student deklariert,
das Argument ist eine Referenz auf Person.
In Student ist nur eine Methode whichMethod bekannt mit Parameter Person.
Der Compiler nimmt eine statische Analyse anhand der deklarierten Typen vor und sieht für
die Ausführung die Methode whichMethod( Person ) vor.
Die Klasse Student hat die Methode whichMethod( Person ) geerbt.
Das Objekt der Klasse Student führt die Methode whichMethod( Person ) aus.
Folie-681
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
Ausgabe:
calling reference argument
declared type runtime type declared type runtime type method from
——————————————————————————-
…
Student Student Student Student Student
Der Compiler kennt als Eigenschaft der Referenzvariablen:
und wählt zur Ausführung die Methode: whichMethod( Student s )
Student mit Methoden whichMethod( Person p ) (geerbt)
und whichMethod( Student s )
Folie-682
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
Ausgabe:
calling reference argument
declared type runtime type declared type runtime type method from
——————————————————————————-
Person Person Person Person Person
Person Person Person Student Person
Person Person Student Student Person
Person Student Person Person Person
Person Student Person Student Person
Person Student Student Student Person
Student Student Person Person Person
Student Student Person Student Person
Student Student Student Student Student
Die Referenzvariable, über die der Aufruf erfolgt, ist für die Klasse Student deklariert,
das Argument ist eine Referenz auf Student.
In Student ist nur eine Methode whichMethod bekannt mit Parameter Student.
Der Compiler nimmt eine statische Analyse anhand der deklarierten Typen vor.
Der Compiler sieht für die Ausführung die Methode whichMethod( Student ) vor.
Das Objekt der Klasse Student führt die Methode whichMethod( Student ) aus.
Folie-683
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
Jetzt wird zusätzlich in Student ergänzt:
public void whichMethod( Person p )
{
System.out.println( “overridden in Student” );
}
Die Klasse Student deklariert jetzt zwei Methoden mit gleichem Namen,
die unterschiedliche Signaturen besitzen:
– whichMethod( Person p )
– whichMethod( Student p )
Die neu hinzugekommene Methode überschreibt die Methode mit der gleichen Signatur,
die von der Klasse Person geerbt wird, gibt aber den Text “overridden in Student” zurück.
Folie-684
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
Student
Person mit Methode whichMethod( Person p )
mit Methoden whichMethod( Person p )
und whichMethod( Student s )
deklarierte Typen der
Parameter sind
kompatible Klassen
und geerbt,
aber überschrieben: whichMethod( Person p )
Folie-685
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
Ausgabe:
calling reference argument
declared type runtime type declared type runtime type method from
——————————————————————————-
Person Person Person Person Person
Person Person Person Student Person
Person Person Student Student Person
Person Student Person Person overridden in Student
Person Student Person Student overridden in Student
Person Student Student Student overridden in Student
Student Student Person Person overridden in Student
Student Student Person Student overridden in Student
Student Student Student Student Student
Beim Aufruf der bekannten Methode wird nun häufig die überschriebene Methode
aus der Klasse Student aufgerufen.
Warum?
Folie-686
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Person mit Methode whichMethod( Person p )
Student
mit Methoden whichMethod( Person p )
und whichMethod( Student s )
und geerbt,
aber überschrieben: whichMethod( Person p )
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
Ausgabe:
calling reference argument
declared type runtime type declared type runtime type method from
——————————————————————————-
…
Person Student Person Person overridden in Student
Person Student Person Student overridden in Student
Person Student Student Student overridden in Student
…
Folie-687
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
Ausgabe:
calling reference argument
declared type runtime type declared type runtime type method from
——————————————————————————-
Person Person Person Person Person
Person Person Person Student Person
Person Person Student Student Person
Person Student Person Person overridden in Student
Person Student Person Student overridden in Student
Person Student Student Student overridden in Student
Student Student Person Person overridden in Student
Student Student Person Student overridden in Student
Student Student Student Student Student
Da die Referenz für die Klasse Person deklariert ist, wählt der Compiler die einzige dort
bekannte Methode mit der Signatur whichMethod( Person ) aus.
Der Laufzeittyp der Referenz ist gegeben durch ein Objekt der Klasse Student mit der
überschriebenen Methode, so dass das Laufzeitsystem für die Ausführung diese
Implementierung der Methode whichMethod( Person ) auswählt.
Folie-688
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Person mit Methode whichMethod( Person p )
Student
mit Methoden whichMethod( Person p )
und whichMethod( Student s )
und geerbt,
aber überschrieben: whichMethod( Person p )
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
Ausgabe:
calling reference argument
declared type runtime type declared type runtime type method from
——————————————————————————-
…
Student Student Person Person overridden in Student
Student Student Person Student overridden in Student
…
Folie-689
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
Ausgabe:
calling reference argument
declared type runtime type declared type runtime type method from
——————————————————————————-
Person Person Person Person Person
Person Person Person Student Person
Person Person Student Student Person
Person Student Person Person overridden in Student
Person Student Person Student overridden in Student
Person Student Student Student overridden in Student
Student Student Person Person overridden in Student
Student Student Person Student overridden in Student
Student Student Student Student Student
Da die Referenz für die Klasse Student deklariert ist und das Argument eine Referenz
auf Person ist, wählt der Compiler die dort deklarierte Methode mit der Signatur
whichMethod( Person ) aus.
Der Laufzeittyp der Referenz ist gegeben durch ein Objekt der Klasse Student mit der
überschriebenen Methode, so dass das Laufzeitsystem für die Ausführung diese
Implementierung der Methode whichMethod( Person ) auswählt.
Folie-690
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
Ergebnis der Experimente:
In Java bestimmt der Compiler ausgehend vom deklarierten Typ der Referenz immer eindeutig
die Signatur der Methode, die zur Laufzeit ausgeführt wird:
– Der Compiler richtet sich nach den ihm zur Verfügung stehenden Informationen, also den
Angaben, die durch eine statische Analyse aus dem Programmtext abgeleitet werden können.
– Der Compiler wählt daher nie eine Methodensignatur aus, die für den deklarierten Typ der
Referenz nicht deklariert ist.
– Der Compiler wählt die Signatur aus, die mit den Typen ihrer Parameter am besten zu den
deklarierten Typen der übergebenen Argumente passt.
Der Compiler berücksichtigt bei seiner Entscheidung nie den Laufzeittyp, also die Klasse eines
Objekts, auf das eine Referenz verweist.
Bei der Ausführung wird in dem Objekt, das die Ausführung vornimmt, die passende Methode
zu der vom Compiler festgelegten Signatur gesucht und ausgeführt. Hierdurch erfolgt dann eine
spezifische Anpassung der Ausführung an den Laufzeittyp.
Folie-691
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kompatibilität von Referenzvariablen und Klassen – Experimente (Fortsetzung)
Ergebnis der Experimente:
In Java bestimmt der Compiler ausgehend vom deklarierten Typ der Referenz immer eindeutig
die Signatur der Methode, die zur Laufzeit ausgeführt wird:
– Der Compiler richtet sich nach den ihm zur Verfügung stehenden Informationen, also den
Angaben, die durch eine statische Analyse aus dem Programmtext abgeleitet werden können.
– Der Compiler wählt daher nie eine Methodensignatur aus, die für den deklarierten Typ der
Referenz nicht deklariert ist.
– Der Compiler wählt die Signatur aus, die mit den Typen ihrer Parameter am besten zu den
deklarierten Typen der übergebenen Argumente passt.
Der Compiler berücksichtigt bei seiner Entscheidung nie den Laufzeittyp, also die Klasse eines
Objekts, auf das eine Referenz verweist.
Bei der Ausführung wird in dem Objekt, das die Ausführung vornimmt, die passende Methode
zu der vom Compiler festgelegten Signatur gesucht und ausgeführt. Hierdurch erfolgt dann eine
spezifische Anpassung der Ausführung an den Laufzeittyp.
Um ein verständliches Verhalten von Programmen sicherzustellen,
sollten daher keine Methoden mit unterschiedlichen, aber zueinander
kompatiblen Signaturen deklariert werden.
Folie-692
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Überschreiben von Methoden – Absicherung
Überschreiben in der Klasse Student:
@Override
public void whichMethod( Person p )
{
System.out.println( “overridden in Student” );
}
Die Annotation @Override zeigt an, dass die Methode whichMethod( Person )
eine Methode mit der gleichen Signatur aus der Oberklasse überschreiben soll.
Gibt es in der Oberklasse keine Methode mit der gleichen Signatur, meldet der Compiler bei
der Verwendung der @Override-Annotation einen Fehler.
Durch die Verwendung von @Override-Annotationen können also in Unterklassen
Flüchtigkeitsfehler beim Deklarieren von Methoden vermieden werden.
Die @Override-Annotation muss immer unmittelbar vor der Methodendeklaration stehen,
die ein Überschreiben vornimmt.
Annotation
Folie-693
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Anmerkungen
Vererbung erfolgt transitiv,
auch geerbte Eigenschaften werden von Klassen an ihre Unterklassen weitergegeben.
Auch die auf Vererbung basierende Kompatibilität von Klassen wird auf diese Weise transitiv
weitergegeben:
– Da eine Klasse K alle von ihrer Oberklasse O geerbten Eigenschaften an ihre Unterklasse U
weitervererbt, besitzt U alle Eigenschaften von O.
– Referenzen, deren deklarierter Typ die Klasse O ist, können daher als Laufzeittyp die
Klasse U besitzen, also auf Objekte der Klasse U verweisen.
Auf diese Weise entstehen Klassen- bzw. Vererbungshierarchien.
Jede Klasse in Java hat aber immer nur genau eine Oberklasse.
Jede Klasse kann viele Unterklassen haben.
Die Möglichkeit, dass in einer Klassenhierarchie durch Überschreiben
unterschiedliche Implementierungen zu der gleichen Signatur auftreten dürfen,
wird als Polymorphie (= Vielgestaltigkeit) bezeichnet.
Folie-694
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vorteile der Vererbung
Welche Vorteile bringt das Konzept der Vererbung?
Es wird die Möglichkeit geschaffen, Hierarchien von zueinander kompatiblen Klassen
anzulegen.
Die Klassen in solchen Hierarchien können dazu genutzt werden,
allgemein einsetzbare Algorithmen und Datenstrukturen zu implementieren.
Innerhalb dieser Hierarchien ist eine gewisse Gleichförmigkeit der Signaturen notwendig,
damit der Mechanismus der polymorphen Auswahl von Methoden gezielt eingesetzt werden
kann. Diese Gleichförmigkeit verbessert auch die Verständlichkeit der Software.
Der Aufwand zum Erstellen und Ändern in diesen Hierarchien wird vermindert,
da geerbte Eigenschaften nicht wiederholt aufgeschrieben werden müssen.
Die Implementierung von speziellen Varianten von Datenstrukturen oder Algorithmen kann in
Unterklassen ausgelagert werden.
Die Leistungsfähigkeit einer Klasse kann durch das Ableiten einer geeigneten Unterklasse
verbessert werden, ohne dass an der Oberklasse Veränderungen vorgenommen werden müssen.
Folie-695
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Deklaration von Konstruktoren
Rückblick auf Folie 652:
…
Die erste Anweisung eines Konstruktors ist immer ein Aufruf eines Konstruktors der
Oberklasse:
Explizit durch Angabe von super gefolgt von einer Parameterliste oder
implizit – dann ergänzt der Compiler den Aufruf des Standardkonstruktors durch super().
Was ist mit der Klasse Person, für die keine Oberklasse angegeben ist?
In Java existiert eine Klasse Object, von der alle Klassen erben,
für die keine Oberklasse explizit durch extends angegeben ist.
Bei diesen Klassen wird automatisch ein extends Object verwendet.
Daraus folgt:
– Die Klasse Object ist die (indirekte) Oberklasse aller anderen Klassen in Java.
– Referenzen auf Object können auf beliebige Objekte verweisen.
– Alle Klassen bieten die Methoden der Klasse Object an,
da jede Klasse diese Methoden direkt oder indirekt erbt.
Object ist also die Klasse,
auf deren Grundlage beliebig allgemeine Klassen erstellt werden können.
Folie-696
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse Object
Object()
boolean equals( Object obj )
String toString()
int hashCode()
…
Konstruktor
vergleicht zwei Objekte
liefert Text zu einem Objekt
wird später in DAP 1 behandelt
(werden nicht in DAP 1 betrachtet)
Folie-697
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse Object (Fortsetzung)
Anmerkungen
Der Konstruktor Object() stellt sicher, dass der Konstruktor jeder deklarierten Klasse einen
Aufruf des (Standard-)Konstruktors seiner Oberklasse tätigen kann.
Folie-698
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse Object (Fortsetzung)
Anmerkungen
Die in Object definierte Form der Methode equals entspricht:
x == y (Identität)
Diese Form der Gleichheit ist in vielen Situationen zu streng.
Daher wird die Methode equals in der Regel spezifisch für die Aufgabe einer Klasse
überschrieben.
Die Methode equals sollte aber immer die folgenden Bedingungen einhalten:
– Es sollte eine Äquivalenzrelation definiert werden: reflexiv, symmetrisch, transitiv
– Verschiedene Aufrufe von equals mit den gleichen beiden Objekten sollten das gleiche
Ergebnis liefern, solange nicht eines der Objekte geändert wurde (Konsistenz).
– Für jede Referenz x auf ein Objekt soll gelten: x.equals( null ) == false
– Das Ergebnis von equals muss konsistent zum Ergebnis
der – noch unbekannten – Methode hashCode() sein:
a.equals(b) a.hashCode() == b.hashCode()
Folie-699
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse Object (Fortsetzung)
Anmerkungen
Die Methode equals besitzt die folgende Signatur: boolean equals( Object obj )
– Ein Überschreiben erfolgt nur dann, wenn in einer Klasse die Methode equals auch genau
mit dem Parametertyp Object überschrieben wird: Verwendung von @Override.
– Beim Überschreiben der Methode equals muss also immer ein Vergleich mit jedem
beliebigen Objekt implementiert werden, da ein Parameter des Typs Object beliebige
Klassen als Laufzeittypen für das übergebene Argument akzeptiert.
Die Methode toString soll eine Textrepräsentation des Objekts zurückgeben.
Die in Object definierte Form von toString liefert Klassenname@hashCode.
Die toString-Methode eines Objekts wird auch immer dann implizit aufgerufen,
wenn ein String-Operand erwartet wird:
String s = “!” + new Object();
erzeugt den Text:
!java.lang.Object@5b77ee02
Folie-700
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Nutzung von Vererbung (Fortsetzung)
Wie kann Vererbung genutzt werden, um allgemein einsetzbare Klassen zu gestalten?
Lösungsansatz:
public class CharacterSearchTree
extends BinarySearchTree
{
private HuffmanTriple content;
…
public class StudentSearchTree
extends BinarySearchTree
{
private Student content;
…
public class BinarySearchTree
{
private BinarySearchTree leftChild,
rightChild;
…
Gemeinsamkeiten in Oberklasse zusammenfassen
und durch Vererbung weitergeben
Folie-701
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
StudentSearchTreeCharacterSearchTree FractionSearchTree
BinarySearchTree
Spezialisierung (Vererbung)
(dargestellt in UML-Notation)
Nutzung von Vererbung (Fortsetzung)
Wie kann Vererbung genutzt werden, um allgemein einsetzbare Klassen zu gestalten?
Lösungsansatz:
Student FractionHuffmanTriple
Folie-702
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
komplizierte Lösung, für jeden Inhalt muss ein neuer Baum implementiert werden
StudentSearchTreeCharacterSearchTree FractionSearchTree
Nutzung von Vererbung (Fortsetzung)
Wie kann Vererbung genutzt werden, um allgemein einsetzbare Klassen zu gestalten?
Lösungsansatz:
HuffmanTriple Student Fraction
BinarySearchTree
Folie-703
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Nutzung von Vererbung (Fortsetzung)
neuer Lösungsansatz:
nur eine Sorte von Knoten, die flexibel zur Datenhaltung benutzt werden können
public class BinarySearchTree
{
private Object content;
private BinarySearchTree leftChild, rightChild;
…
Referenz auf Object:
kann auf jedes Objekt
verweisen
BinarySearchTree
Student Fraction
Object
aber: Object besitzt keine Ordnungsrelation
HuffmanTriple
Folie-704
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Nutzung von Vererbung (Fortsetzung)
neuer Lösungsansatz:
nur eine Sorte von Knoten, die flexibel zur Datenhaltung benutzt werden können
public class BinarySearchTree
{
private X content;
private BinarySearchTree leftChild, rightChild;
…
Die Klasse X muss eine
Ordnungsrelation garantieren
BinarySearchTree
Student Fraction
X
HuffmanTriple
Folie-705
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Nutzung von Vererbung (Fortsetzung)
vor der Umgestaltung des Suchbaums ein einfacheres Beispiel,
das keine Anforderungen an die abgelegten Inhalte stellt:
doppelt verkettete Liste
Eine Liste ist eine Datenstruktur,
in der (beliebige) Inhalte sequentiell nacheinander abgelegt werden können,
die einen Anfang hat,
die ein Ende hat,
die sequentiell durchlaufen werden kann,
in die Daten eingefügt werden können,
aus der Daten entfernt werden können.
Folie-706
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Vererbung und Polymorphie
(siehe Folie 638)
Nach Durcharbeiten des Kapitels Vererbung und Polymorphie sollen
die teilnehmenden Studierenden
das Konzept der Vererbung kennen und einsetzen können,
das Konzept polymorpher Methoden kennen und einsetzen können,
Klassenhierarchien gestalten und implementieren können,
die eine ist-ein-Beziehung umsetzen,
den Laufzeittyp und den statischen Typ von Referenzvariablen unterscheiden und bestimmen
können.
Folie-707
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen, Algorithmen
und Programmierung 1 (DAP 1)
Fakultät für Informatik
Wintersemester 2019/20
Stefan Dissmann
Datenstruktur Doppelt verkettete Liste
Folie-708
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Datenstruktur Doppelt verkettete Liste
Nach Durcharbeiten des Kapitels Doppelt verkettete Liste sollen
die teilnehmenden Studierenden
die Datenstruktur der doppelt verketteten Liste kennen,
die Klasse Element einsetzen können,
die Klasse DoublyLinkedList erweitern können,
Wrapper-Klassen kennen und einsetzen können
die Konzepte Boxing und Unboxing kennen und einsetzen können,
das Konzept des Type-Casts kennen und einsetzen können.
Folie-709
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Idee der Datenstruktur Liste
Die Liste dient dem Abspeichern von vielen Werten.
Die Werte werden nacheinander – also in einer Sequenz – abgelegt.
Diese Anforderungen ähneln den Möglichkeiten von Feldern.
Die Anzahl der abgelegten Werte soll variabel und vorab nicht festgelegt sein.
Werte sollen an beliebigen Stellen der Sequenz ergänzt werden können.
Werte sollen an beliebigen Stellen der Sequenz gelöscht werden können.
Diese Anforderungen lassen sich für Felder nicht oder nur umständlich umsetzen.
Folie-710
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Idee der Datenstruktur Liste (Fortsetzung)
Visualisierung
liste
Hinzunehmen und Löschen von Elementen:
content
succ
content
succ
content
succ
content
succ
– Elemente erzeugen
– Referenzen umsetzen
Elemente
null
succ = successor (Nachfolger)
Folie-711
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Idee der Datenstruktur Liste (Fortsetzung)
Visualisierung
liste
Hinzunehmen und Löschen von Elementen:
content
succ
content
succ
content
succ
content
succ
– Elemente erzeugen
– Referenzen umsetzen
aber:
– Methoden umständlich (z.B. Setzen von Referenzen beim Löschen)
– Ausführung langsam (z.B. Anhängen am Ende erfordert kompletten Durchlauf)
null
Folie-712
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Idee der Datenstruktur Liste (Fortsetzung)
Visualisierung
null
liste
Ergänzungen:
content
succ
content
succ
content
succ
content
succ
– Nutzung von zwei Klassen (Verwaltung eines Elements, Verwaltung der ganzen Liste)
– Elemente in beide Richtungen verbinden, um in beide Richtungen navigieren zu können
first
last
size 4
pred pred pred pred
null
pred = predecessor (Vorgänger)
Folie-713
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Aufbau der Datenstruktur
Die Klasse Element repräsentiert ein einzelnes Element der Liste.
– Jedes Element kann einen beliebigen Inhalt haben.
– Jedes Element kann sich mit seinem Vorgänger in der Liste verbinden.
– Jedes Element kann sich mit seinem Nachfolger in der Liste verbinden.
Die Klasse DoublyLinkedList organisiert aus Objekten der Klasse Element eine Liste.
– Die Liste ist leer oder hat ein Anfangs- und ein Endelement.
Das Anfangselement hat keinen Vorgänger, das Endelement keinen Nachfolger.
– Die Elemente der Liste sind so verbunden, dass vom Anfangselement ausgehend
alle Elemente erreicht werden können.
– Die Elemente der Liste sind so verbunden, dass vom Endelement ausgehend
alle Elemente erreicht werden können.
Folie-714
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Aufbau der Datenstruktur (Fortsetzung)
public class Element
{
private Object content;
private Element pred, succ;
…
}
public class DoublyLinkedList
{
private Element first, last;
private int size;
…
}
Die Attribute der Klasse Element ähneln denen der Klasse BinarySearchTree:
Erst die gezielte Verwendung der Attribute pred und succ in den Methoden führt zu der
andersartigen Datenstruktur.
Auch die Liste ist eine rekursiv deklarierte Datenstruktur,
da die Element-Objekte Referenzen auf den eigenen Typ enthalten.
beliebiger Inhalt
Verkettung der Elemente
Anfangs- und Endelement
Anzahl der Elemente
Folie-715
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Aufbau der Datenstruktur (Fortsetzung)
Beispiel: Objekte einer Liste mit vier Elementen
ElementElementElementElement
DoublyLinkedList
null
content
succ
content
succ
content
succ
content
succ
first
last
size 4
pred pred pred pred
null
Folie-716
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse Element
public class Element
{
private Object content;
private Element pred, succ;
public Element( Object c )
{
content = c;
pred = succ = null;
}
public Object getContent()
{
return content;
}
public void setContent( Object c )
{
content = c;
}
…
beliebiger Inhalt
Verkettung der Elemente
Konstruktor
einfache Methoden
Folie-717
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse Element (Fortsetzung)
…
public boolean hasSucc()
{
return succ != null;
}
public Element getSucc()
{
return succ;
}
…
Methoden, die sich
Existenz
Zugriff
mit dem Nachfolger
beschäftigen
ElementElement
content
succ
content
succ
pred pred
…
…
Folie-718
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse Element (Fortsetzung)
Die beiden Referenzen succ und pred müssen nach der Ausführung einer Methode
der Klasse Element immer die folgenden Bedingungen einhalten, die die Verbindung von
Vorgänger und Nachfolger in beide Richtungen sicherstellen:
succ == null || succ.pred == this
pred == null || pred.succ == this
Solche Bedingungen werden auch als Invariante bezeichnet, da sie für jedes Element einer
beliebigen Liste unabhängig von deren Inhalt und deren Anzahl immer gelten.
Daraus lassen sich die Implementierungen der Methoden zum Verknüpfen und Trennen von
Elementen ableiten.
Folie-719
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse Element (Fortsetzung)
…
public void disconnectSucc()
{
if ( hasSucc() )
{
succ.pred = null;
succ = null;
}
}
…
ElementElement
content
succ
content
succ
pred pred
Abtrennen, falls vorhanden
(Einhalten der Invariante)
…
…
Folie-720
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse Element (Fortsetzung)
…
public void disconnectSucc()
{
if ( hasSucc() )
{
succ.pred = null;
succ = null;
}
} Beispielaufruf: x.disconnectSucc();
…
ElementElement
content
succ
content
succ
pred pred
x
Abtrennen, falls vorhanden
(Einhalten der Invariante)
…
…
Folie-721
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse Element (Fortsetzung)
…
public void disconnectSucc()
{
if ( hasSucc() )
{
succ.pred = null;
succ = null;
}
} Beispielaufruf: x.disconnectSucc();
…
Abtrennen, falls vorhanden
ElementElement
content
succ
content
succ
pred pred
null
null
(Einhalten der Invariante)
x
…
…
Folie-722
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse Element (Fortsetzung)
…
public void connectAsSucc( Element e )
{
disconnectSucc();
if ( e != null )
{
e.disconnectPred();
e.pred = this;
}
succ = e;
}
…
Hinzufügen (Einhalten der Invariante)
content
succ
pred
y
…
…
ElementElement
content
succ
content
succ
pred pred
…
…
Folie-723
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse Element (Fortsetzung)
…
public void connectAsSucc( Element e )
{
disconnectSucc();
if ( e != null )
{
e.disconnectPred();
e.pred = this;
}
succ = e; Beispielaufruf: x.connectAsSucc( y );
}
…
Einhalten der Invariante
content
succ
pred
y
…
…
ElementElement
content
succ
content
succ
pred pred
x
…
…
Folie-724
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse Element (Fortsetzung)
…
public void connectAsSucc( Element e )
{
disconnectSucc();
if ( e != null )
{
e.disconnectPred();
e.pred = this;
}
succ = e; Beispielaufruf: x.connectAsSucc( y );
}
…
e
content
succ
pred
y
…
…
ElementElement
content
succ
content
succ
pred pred
x
…
…
Einhalten der Invariante
Folie-725
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse Element (Fortsetzung)
…
public void connectAsSucc( Element e )
{
disconnectSucc();
if ( e != null )
{
e.disconnectPred();
e.pred = this;
}
succ = e; Beispielaufruf: x.connectAsSucc( y );
}
…
e
null
null
content
succ
pred
y
…
…
ElementElement
content
succ
content
succ
pred pred
x
…
…
Einhalten der Invariante
Folie-726
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse Element (Fortsetzung)
…
public void connectAsSucc( Element e )
{
disconnectSucc();
if ( e != null )
{
e.disconnectPred();
e.pred = this;
}
succ = e; Beispielaufruf: x.connectAsSucc( y );
}
…
e
null
content
succ
pred
y
…
ElementElement
content
succ
content
succ
pred pred
x
…
…
Einhalten der Invariante
null
Folie-727
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse Element (Fortsetzung)
…
public void connectAsSucc( Element e )
{
disconnectSucc();
if ( e != null )
{
e.disconnectPred();
e.pred = this;
}
succ = e; Beispielaufruf: x.connectAsSucc( y );
}
…
e
null
content
succ
pred
y
…
ElementElement
content
succ
content
succ
pred pred
x
…
…
Einhalten der Invariante
Folie-728
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse Element (Fortsetzung)
…
public void connectAsSucc( Element e )
{
disconnectSucc();
if ( e != null )
{
e.disconnectPred();
e.pred = this;
}
succ = e; Beispielaufruf: x.connectAsSucc( y );
}
…
content
succ
pred
y
…
content
succ
pred
x
…
Einhalten der Invariante
Folie-729
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse Element (Fortsetzung)
public boolean hasPred() {
return pred != null;
}
public Element getPred() {
return pred;
}
public void disconnectPred() {
if ( hasPred() ) {
pred.succ = null;
pred = null;
}
}
public void connectAsPred( Element e ) {
disconnectPred();
if ( e != null ) {
e.disconnectSucc();
e.succ = this;
}
pred = e;
}
}
analoge Methoden,
Existenz
Zugriff
Hinzufügen (Einhalten der Invariante)
die sich mit dem
Abtrennen (Einhalten der Invariante)
Vorgänger beschäftigen
Folie-730
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
ElementElementElement
DoublyLinkedList
null
content
succ
content
succ
content
succ
first
last
size 3
pred pred pred
null
Erinnerung: Aufbau der Datenstruktur (Fortsetzung)
Klasse DoublyLinkedList
Folie-731
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse DoublyLinkedList
public class DoublyLinkedList
{
private Element first, last;
private int size;
public DoublyLinkedList()
{
first = last = null;
size = 0;
}
public int size()
{
return size;
}
public boolean isEmpty()
{
return size == 0;
}
…
Das Attribut size muss beim Hinzufügen zu oder Löschen in der Liste korrigiert werden.
Dann liefert die Methode size() die Anzahl der Elemente.
Anfangs- und Endelement
Anzahl der Elemente
Konstruktor für leere Liste
Anzahl der Elemente
= Länge der Liste
leere Liste identifizieren
Folie-732
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse DoublyLinkedList (Fortsetzung)
…
public void add( Object content )
{
Element e = new Element( content );
if ( isEmpty() )
{
first = last = e;
}
else
{
last.connectAsSucc( e );
last = e;
}
size++;
}
…
Die Methode add ergänzt ein Element am Ende der Liste,
dessen Inhalt das als Argument übergebene Objekt wird.
Liste ist leer:
das einzige Element wird ergänzt
size wird korrigiert
das Element wird angehängt
last wird korrigiert
Folie-733
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse DoublyLinkedList (Fortsetzung)
Beispiel für Aufruf: dll.add( o );
o
ElementElementElement
DoublyLinkedList
content
succ
content
succ
content
succ
first
last
size 3
pred pred pred
null
dll
null
Folie-734
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
ElementElementElementElement
nullcontent
succ
content
succ
content
succ
content
succ
pred pred pred pred
null
Klasse DoublyLinkedList (Fortsetzung)
Beispiel für Aufruf: dll.add( o ); Element e = new Element( content );
DoublyLinkedList
first
last
size 3
dll
o
null
null
e
Folie-735
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
ElementElementElementElement
content
succ
content
succ
content
succ
content
succ
pred pred pred pred
null
Klasse DoublyLinkedList (Fortsetzung)
Beispiel für Aufruf: dll.add( o ); last.connectAsSucc( e );
DoublyLinkedList
first
last
size 3
dll
o
null
e
Folie-736
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
ElementElementElementElement
content
succ
content
succ
content
succ
content
succ
pred pred pred pred
null
Klasse DoublyLinkedList (Fortsetzung)
Beispiel für Aufruf: dll.add( o ); last = e;
DoublyLinkedList
first
last
size 3
dll
o
null
e
Folie-737
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
ElementElementElementElement
content
succ
content
succ
content
succ
content
succ
pred pred pred pred
null
Klasse DoublyLinkedList (Fortsetzung)
Beispiel für Aufruf: dll.add( o ); size++;
DoublyLinkedList
first
last
size 4
dll
o
e
null
Folie-738
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse DoublyLinkedList (Fortsetzung)
…
public void addFirst( Object content )
{
Element e = new Element( content );
if ( isEmpty() )
{
first = last = e;
}
else
{
first.connectAsPred( e );
first = e;
}
size++;
}
…
Die Methode addFirst ergänzt ein Element am Anfang der Liste,
dessen Inhalt das als Argument übergebene Objekt wird.
Liste ist leer:
das einzige Element wird ergänzt
size wird korrigiert
das Element wird angebunden
first wird korrigiert
Folie-739
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Element ElementElementElement
content
succ
content
succ
content
succ
content
succ
pred pred predpred
Klasse DoublyLinkedList (Fortsetzung)
Beispiel für Aufruf: dll.addFirst( o );
DoublyLinkedList
first
last
size 4
dll
o
e
null
Folie-740
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse DoublyLinkedList (Fortsetzung)
…
public Object getFirst()
{
if ( !isEmpty() )
{
return first.getContent();
}
else
{
throw new IllegalStateException();
}
}
…
Die Methode getFirst gibt eine Referenz auf den Inhalt des ersten Elements der Liste zurück,
falls die Liste mindestens ein Element enthält.
Die Liste wird dabei nicht verändert.
Liste ist leer:
Abbruch
Liste ist nicht leer:
Inhalt des ersten Elements
wird zurückgegeben
Folie-741
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse DoublyLinkedList (Fortsetzung)
…
public Object get( int index )
{
if ( index >= 0 && index < size )
{
Element current = first;
for ( int i = 0; i < index; i++ )
{
current = current.getSucc();
}
return current.getContent();
}
else
{
throw new IllegalStateException();
}
}
...
Jeder Aufruf von get führt die Suche vom Anfang der Liste aus durch.
sucht Element in Liste
prüft index auf Gültigkeit
Folie-742
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse DoublyLinkedList (Fortsetzung)
public Object removeFirst()
{
if ( !isEmpty() )
{
Object result = first.getContent();
if ( first.hasSucc() )
{
first = first.getSucc();
first.disconnectPred();
} else {
first = last = null;
}
size--;
return result;
} else {
throw new IllegalStateException();
}
}
Die Methode removeFirst gibt eine Referenz auf den Inhalt des ersten Elements zurück und
löscht das Objekt aus der Liste.
Liste ist nach Löschen leer:
last korrigieren
Liste ist nicht leer:
Inhalt des ersten Elements merken
first korrigieren = Löschen
Liste ist nach Löschen nicht leer:
neues erstes Element korrigieren
size korrigieren
Folie-743
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse DoublyLinkedList (Fortsetzung)
...
public void showAll()
{
Element current = first;
while ( current != null )
{
System.out.print( current.getContent().toString() );
if ( current != last )
{
System.out.print(", ");
}
current = current.getSucc();
}
System.out.println();
}
}
Die Methode showAll gibt die Inhalte aller Element der Liste aus.
toString ist für jedes Objekt
verfügbar
Folie-744
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse DoublyLinkedList – Beispiel (Fortsetzung)
DoublyLinkedList students = new DoublyLinkedList();
students.add( new Student( "A", "Inf", 123433 ) );
students.add( new Student( "B", "Inf", 123456 ) );
students.add( new Student( "C", "Inf", 123457 ) );
students.add( new Student( "D", "Inf", 123458 ) );
students.showAll();
students.addFirst( new Student( "X", "Inf", 123461 ) );
students.showAll();
System.out.println( students.get(2).toString() );
System.out.println( students.removeFirst().toString() );
System.out.println( students.getFirst().toString() );
Ausgabe:
student: A, registration number: 123433(Inf), student: B, registration number: ...
student: X, registration number: 123461(Inf), student: A, registration number: ...
student: B, registration number: 123456(Inf)
student: X, registration number: 123461(Inf)
student: A, registration number: 123433(Inf)
eine Liste mit Student-Objekten
toString wird in Student
überschrieben
Folie-745
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse DoublyLinkedList – Beispiel (Fortsetzung)
DoublyLinkedList numbers = new DoublyLinkedList();
numbers.add( new Fraction( 2, 3 ) );
numbers.add( new Fraction( 1, 7 ) );
numbers.add( new Fraction( 3, 12 ) );
numbers.add( new Fraction( 8 ) );
numbers.showAll();
System.out.println( numbers.removeFirst().toString() );
numbers.showAll();
System.out.println( numbers.getFirst().toString() );
Ausgabe:
2 / 3, 1 / 7, 1 / 4, 8 / 1
2 / 3
1 / 7, 1 / 4, 8 / 1
1 / 7
eine Liste mit Fraction-Objekten
toString wird in Fraction
überschrieben
Folie-746
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse DoublyLinkedList – Beispiel (Fortsetzung)
DoublyLinkedList list = new DoublyLinkedList();
list.add( new Student( "A", "Inf", 123433 ) );
list.add( new Fraction( 3, 7 ) );
list.showAll();
Ausgabe:
student: A, registration number: 123433(Inf), 3 / 7
Da die Referenz content auf beliebige Objekte verweisen kann,
können in jeder Liste Objekte verschiedener Klassen eingefügt werden.
Eine Liste der Klasse DoublyLinkedList besitzt also keinen einheitlichen Grundtyp.
eine Liste
toString wird in Student und
Fraction überschrieben
Folie-747
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse DoublyLinkedList – Beispiel (Fortsetzung)
Die Methode get erlaubt es, eine Ausgabe analog zu der der Methode showAll auch außerhalb der
Klasse DoublyLinkedList durch eine Schleife zu erzeugen:
for ( int i = 0; i < students.size(); i++ )
{
System.out.print( students.get(i) );
if ( i != students.size()-1 )
{
System.out.print( ", " );
}
}
Da jeder Aufruf von get die Liste von vorne durchläuft, ist diese Form sehr ineffizient.
Die Ausgabe mit showAll ist sehr viel effizienter.
Folie-748
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse DoublyLinkedList (Fortsetzung)
Zusammenfassung der Experimente
Die Datenstruktur DoublyLinkedList lässt sich universell verwenden:
Eine Liste von Student-Objekten konnte ohne Änderungen an den Klassen
Student oder DoublyLinkedList angelegt werden.
Eine Liste von Fraction-Objekten konnte ohne Änderungen an den Klassen
Fraction oder DoublyLinkedList angelegt werden.
Die Verfügbarkeit der Methode toString ermöglicht es,
eine Methode showAll zur Ausgabe in der Klasse DoublyLinkedList ohne Kenntnis der
tatsächlich abgelegten Objekte zu implementieren.
aber: Lässt sich auch eine Liste von int-Werten anlegen?
int ist keine Klasse, Referenzen auf Object können nicht auf einfache Typen wie
int, double, boolean, char, ... verweisen.
Folie-749
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Wrapper-Klassen
Klasse Integer
Java stellt Klassen (Wrapper) bereit, die die einfachen Typen in einem Objekt einpacken, das jeweils
nichts anderes enthält als genau einen Wert eines einfachen Typs:
Double (einfacher Typ: double)
Integer (einfacher Typ: int)
Float (einfacher Typ: float)
Long (einfacher Typ: long)
deren gemeinsame Oberklasse Number
Boolean (einfacher Typ: boolean)
Character (einfacher Typ: char)
Als Beispiel wird der Einsatz der Klasse Integer gezeigt.
Folie-750
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Wrapper-Klassen (Fortsetzung)
Klasse Integer
public Integer( int value )
public int compareTo( Integer anotherInteger )
public boolean equals( Object obj )
public int intValue()
public double doubleValue()
public String toString()
Mit der Klasse können Objekte angelegt werden, die einen int-Wert enthalten:
Die Klasse besitzt keine Methode zum Ändern des Werts eines Objekts!
DoublyLinkedList ints = new DoublyLinkedList();
ints.add( new Integer( 4 ) );
ints.add( new Integer( 3 ) );
Konstruktor
liefert Wert als int
liefert Wert als double
Folie-751
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Wrapper-Klassen (Fortsetzung)
Klasse Integer
Da die Klasse Integer fest in Java integriert ist, sind zusätzlich möglich:
Boxing
ist die Zuweisung eines int-Wertes an eine Integer-Referenz.
Es wird implizit der Konstruktor aufgerufen. («Der int-Wert wird einpackt.»)
Integer ref = 5; entspricht Integer ref = new Integer( 5 ) ;
Unboxing
ist die Zuweisung einer Integer-Referenz an eine int-Variable.
Es wird implizit die intValue-Methode aufgerufen. («Der int-Wert wird ausgepackt.»)
int i = ref; entspricht int i = ref.intValue();
Der Gebrauch von Objekten/Werten der Typen Integer und int kann also einfach gemischt
werden.
Folie-752
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Wrapper-Klassen (Fortsetzung)
Klasse Integer
Durch die Kompatibilität von Integer und int ist auch folgender Quelltext möglich:
DoublyLinkedList ints = new DoublyLinkedList();
ints.add( 5 );
ints.add( 6 );
Der Parameter der Methode add hat den (deklarierten) Typ Object.
Java erkennt, dass Boxing des int-Wertes ein zu Object kompatibles Integer-Objekt
erzeugen würde und verpackt daher den int-Wert in ein Objekt der Klasse Integer und
übergibt eine Referenz auf dieses Objekt als Argument.
Das Programm ist daher compilierbar und ausführbar.
Die universell deklarierte Liste kann also auch mit einfachen Typen verwendet werden.
Folie-753
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Abfragen von Objekten aus der Liste
Experiment: Lesen von Werten aus der Liste
DoublyLinkedList ints = new DoublyLinkedList();
ints.add( new Integer( 5 ) );
ints.add( new Integer( 6 ) );
Integer i = ints.get( 1 );
Erinnerung:
Der Compiler prüft den Programmtext statisch und führt diesen nicht aus:
Die Methode get hat als Typ für die Rückgabe Object deklariert,
die Klasse Object ist aber Oberklasse von Integer, so dass der Compiler nicht garantieren
kann, dass das zurückgegebene Objekt tatsächlich zu Integer kompatibel ist.
Ebenso scheitert:
int i = ints.get( 1 );
Object ist grundsätzlich nicht kompatibel zum Typ int.
Der Compiler könnte nur dann ein Unboxing vorsehen, wenn er sicher wäre, dass
ints.get( 1 ) ein Integer-Objekt liefern würde.
Compiler meldet: incompatible types
Folie-754
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Abfragen von Objekten aus der Liste (Fortsetzung)
Lösung des Problems (1)
Der Compiler akzeptiert nur eine einzige Zuweisung:
Object ref = ints.get( 1 );
Dabei sind der Typ der Referenz und der Typ der Rückgabe gemäß der Deklaration der
Methode get identisch.
Bei der Ausführung wird dann in der Methode get das zweite in der Liste abgelegte
Integer-Objekt ermittelt und eine Referenz auf dieses Objekt zurückgegeben.
Die Zuweisung an eine Object-Referenz ist möglich, da Object als Oberklasse auf Objekte
eine seiner Unterklassen – hier also Integer – verweisen kann.
Allerdings können über die Referenz ref nur solche Methoden aufgerufen werden, die in der
Klasse Object deklariert sind. Insbesondere kann nicht auf den im Integer-Objekt abgelegten
int-Wert zugegriffen werden.
Diese Lösung hilft also nicht recht weiter.
Folie-755
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Abfragen von Objekten aus der Liste (Fortsetzung)
Lösung des Problems (2)
Der Compiler vertraut aber dem Entwickler. Dieser kann durch eine explizite Typangabe
(Type-Cast) versichern, dass das zugewiesene Objekt kompatibel zum Typ Integer ist. *)
Integer ref = (Integer)ints.get( 1 );
Der Compiler kann die Richtigkeit der durch den Type-Cast geschaffenen Typkompatibilität
nicht überprüfen.
Liefert die Methode get bei der Ausführung kein zu Integer kompatibles Objekt,
tritt ein Laufzeitfehler auf: ClassCastException
Allerdings können auch bei einem Type-Cast die Vorteile des Boxing und Unboxing für die
vordefinierten Wrapper-Klassen genutzt werden. Möglich sind:
int i = (Integer)ints.get( 1 );
int k = (int)ints.get( 1 );
Integer ref = (int)ints.get( 1 );
*) Der Type-Cast für Objekte erzeugt kein neues Objekt, sondern gibt nur einen Hinweis zur Typkompatibilität zur Laufzeit.
Folie-756
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse Element – abschließender Überblick
public class Element
{
private Object content;
private Element pred, succ;
public Element( Object c ) { ... }
public void setContent( Object c ) { ... }
public boolean hasSucc() { ... }
public Element getSucc() { ... }
public void connectAsSucc( Element e) { ... }
public void disconnectSucc() { ... }
public boolean hasPred() { ... }
public Element getPred() { ... }
public void connectAsPred( Element e ) { ... }
public void disconnectPred() { ... }
}
Attribute
Konstruktor
öffentliche Methoden
Folie-757
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse DoublyLinkedList – abschließender Überblick
public class DoublyLinkedList
{
private Element first, last;
private int size;
public DoublyLinkedList() { ... }
public int size() { ... }
public boolean isEmpty() { ... }
public void add( Object content ) { ... }
public Object getFirst() { ... }
public Object get( int index ) { ... }
public Object removeFirst() { ... }
public void showAll() { ... }
}
Attribute
Konstruktor
öffentliche Methoden
Folie-758
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
nicht vorhersehbare Operationen auf der Liste
Die Klasse DoublyLinkedList enthält nur Methoden, die für jeden Inhalt ausführbar sind.
In DoublyLinkedList können keine Annahmen über die in den Elementen gespeicherten
Inhalte getroffen werden.
Schon eine einfache Aufgabenstellung wie das Berechnen der Summe aller in einer Liste von
Integer-Objekten abgelegten Werte muss über das sehr ineffiziente vielfache Aufrufen
der get-Methode erfolgen, die bei jedem Aufruf eine Suche vom Anfang der Liste aus beginnt.
Auch das Verdoppeln aller in der Liste abgelegten Werte ist nur umständlich zu lösen.
Da die Klasse Integer keine Methode zum Ändern ihres int-Wertes anbietet, reicht es nicht,
die Integer-Objekte mit der get-Methode auszulesen.
Zusätzlich müssten Werte ausgetauscht oder die Liste ab- und wieder aufgebaut werden.
Lösungsansatz:
Es muss eine Möglichkeit geschaffen werden, die Liste mit Unterbrechungen – in denen
weitere Methoden aufgerufen werden können – zu durchlaufen, ohne bei der Fortsetzung
des Durchlaufs jeweils wieder mit dem Anfang der Liste beginnen zu müssen.
Folie-759
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Datenstruktur Doppelt verkettete Liste
(siehe Folie 708)
Nach Durcharbeiten des Kapitels Doppelt verkettete Liste sollen
die teilnehmenden Studierenden
die Datenstruktur der doppelt verketteten Liste kennen,
die Klasse Element einsetzen können,
die Klasse DoublyLinkedList erweitern können,
Wrapper-Klassen kennen und einsetzen können
die Konzepte Boxing und Unboxing kennen und einsetzen können,
das Konzept des Type-Casts kennen und einsetzen können.
Folie-760
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen, Algorithmen
und Programmierung 1 (DAP 1)
Fakultät für Informatik
Wintersemester 2019/20
Stefan Dissmann
Entwurfsmuster Iterator
Folie-761
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Entwurfsmuster Iterator
Nach Durcharbeiten des Kapitels Entwurfsmuster Iterator sollen
die teilnehmenden Studierenden
Pakete anlegen und nutzen können,
abstrakte Klassen kennen und einsetzen können,
innere Klassen kennen und einsetzen können,
das Entwurfsmuster Iterator kennen,
die Implementierung mit den Klassen ListIterator, ForwardIterator und ReverseIterator
verstehen und einsetzen können,
das Entwurfsmuster Iterator in anderen Kontexten einsetzen können.
Folie-762
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Wiederholung (Folie 758): nicht vorhersehbare Operationen auf der Liste
Die Klasse DoublyLinkedList enthält nur Methoden, die für jeden Inhalt ausführbar sind.
In DoublyLinkedList können keine Annahmen über die in den Elementen gespeicherten
Inhalte getroffen werden.
Schon eine einfache Aufgabenstellung wie das Berechnen der Summe aller in einer Liste von
Integer-Objekten abgelegten Werte muss über das sehr ineffiziente vielfache Aufrufen
der get-Methode erfolgen, die bei jedem Aufruf eine Suche vom Anfang der Liste aus beginnt.
Auch das Verdoppeln aller in der Liste abgelegten Werte ist nur umständlich zu lösen.
Da die Klasse Integer keine Methode zum Ändern ihres int-Wertes anbietet, reicht es nicht,
die Integer-Objekte mit der get-Methode auszulesen.
Zusätzlich müssten Werte ausgetauscht oder die Liste ab- und wieder aufgebaut werden.
Warum wird die Klasse DoublyLinkedList nicht für jeden Spezialfall ergänzt?
Folie-763
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Wiederholung (Folie 758): nicht vorhersehbare Operationen auf der Liste (Fortsetzung)
Die Klasse DoublyLinkedList enthält nur Methoden, die für jeden Inhalt ausführbar sind.
In DoublyLinkedList können keine Annahmen über die in den Elementen gespeicherten
Inhalte getroffen werden.
Schon eine einfache Aufgabenstellung wie das Berechnen der Summe aller in einer Liste von
Integer-Objekten abgelegten Werte muss über das sehr ineffiziente vielfache Aufrufen
der get-Methode erfolgen, die bei jedem Aufruf eine Suche vom Anfang der Liste aus beginnt.
Auch das Verdoppeln aller in der Liste abgelegten Werte ist nur umständlich zu lösen.
Da die Klasse Integer keine Methode zum Ändern ihres int-Wertes anbietet, reicht es nicht,
die Integer-Objekte mit der get-Methode auszulesen.
Zusätzlich müssten Werte ausgetauscht oder die Liste ab- und wieder aufgebaut werden.
Warum wird die Klasse DoublyLinkedList nicht für jeden Spezialfall ergänzt?
– Für jede Ergänzung muss der Programmtext von DoublyLinkedList verstanden werden.
– Nach jeder Ergänzung muss der Programmtext von DoublyLinkedList erneut getestet werden.
– Nach jeder Ergänzung müssen andere Klassen, die DoublyLinkedList benutzen, erneut
getestet werden.
Folie-764
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Wiederholung (Folie 758): nicht vorhersehbare Operationen auf der Liste (Fortsetzung)
Die Klasse DoublyLinkedList enthält nur Methoden, die für jeden Inhalt ausführbar sind.
In DoublyLinkedList können keine Annahmen über die in den Elementen gespeicherten
Inhalte getroffen werden.
Schon eine einfache Aufgabenstellung wie das Berechnen der Summe aller in einer Liste von
Integer-Objekten abgelegten Werte muss über das sehr ineffiziente vielfache Aufrufen
der get-Methode erfolgen, die bei jedem Aufruf eine Suche vom Anfang der Liste aus beginnt.
Auch das Verdoppeln aller in der Liste abgelegten Werte ist nur umständlich zu lösen.
Da die Klasse Integer keine Methode zum Ändern ihres int-Wertes anbietet, reicht es nicht,
die Integer-Objekte mit der get-Methode auszulesen.
Zusätzlich müssten Werte ausgetauscht oder die Liste ab- und wieder aufgebaut werden.
Lösungsansatz, um ohne Ergänzung der Klasse DoublyLinkedList flexibel zu sein:
Es muss eine Möglichkeit geschaffen werden, die Liste mit Unterbrechungen – in denen
weitere Methoden aufgerufen werden können – zu durchlaufen, ohne bei der Fortsetzung
des Durchlaufs jeweils wieder mit dem Anfang der Liste beginnen zu müssen.
Folie-765
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Iterator
Lösungsidee – Konkretisierung:
Eine zusätzliche Referenz auf Objekte der Klasse Element wird angelegt.
Wenn ein Durchlauf beginnt, wird diese Referenz auf das erste Element der Liste gesetzt.
Wenn ein Inhalt abgerufen wird, wird er von dem Element bezogen, auf das die Referenz
verweist. Gleichzeitig wird die Referenz auf das nachfolgende Element gesetzt.
Der letzte Schritt kann nun wiederholt und die Liste so elementweise durchlaufen werden.
Voraussetzung ist, dass
– die Referenz dauerhaft erhalten bleibt und
– erkannt werden kann, wann ein ein neuer Durchlauf beginnt.
null
content
succ
content
succ
content
succ
content
succ
first
last
size 4
pred pred pred pred
null
Folie-766
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Iterator (Fortsetzung)
Wie und wo wird die zusätzliche Referenz deklariert?
Vorschlag 1: als Attribut in der Klasse DoublyLinkedList
– Dort ist das private Attribut first bekannt, das für den Start des Durchlaufs benötigt wird.
– Methoden übernehmen das Initialisieren und Weitersetzen.
null
content
succ
content
succ
content
succ
content
succ
pred pred pred pred
null
first
last
size 4
Folie-767
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Iterator (Fortsetzung)
Wie und wo wird die zusätzliche Referenz deklariert?
Vorschlag 1: als Attribut in der Klasse DoublyLinkedList
– Dort ist das private Attribut first bekannt, das für den Start des Durchlaufs benötigt wird.
– Methoden übernehmen das Initialisieren und Weitersetzen.
– aber: Es kann immer nur genau ein Durchlauf zu einem Zeitpunkt erfolgen, da bei dieser
Lösung für jede Liste auch nur eine Referenz zur Verfügung steht.
Bei großen Softwaresystemen kann diese Randbedingung aber nur schwer
überprüft und sichergestellt werden.
null
content
succ
content
succ
content
succ
content
succ
pred pred pred pred
null
first
last
size 4
Folie-768
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Iterator (Fortsetzung)
Wie und wo wird die zusätzliche Referenz deklariert?
Vorschlag 2: als Attribut einer speziellen Klasse
– Objekte dieser Klasse werden erzeugt, um genau einen Durchlauf zu unterstützen.
– Sollen an verschiedenen Stellen in einem Softwaresystem Durchläufe durch die gleiche Liste
erfolgen, so wird jeweils ein eigenes Objekt erzeugt.
null
content
succ
content
succ
content
succ
content
succ
pred pred pred pred
null
first
last
size 4
Folie-769
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Iterator (Fortsetzung)
Wie und wo wird die zusätzliche Referenz deklariert?
Vorschlag 2: als Attribut einer speziellen Klasse
– Objekte dieser Klasse werden erzeugt, um genau einen Durchlauf zu unterstützen.
– Sollen an verschiedenen Stellen in einem Softwaresystem Durchläufe durch die gleiche Liste
erfolgen, so wird jeweils ein eigenes Objekt erzeugt.
– Wie kann auf das private Attribut first zugegriffen werden?
Die Klasse DoublyLinkedList übernimmt in einer Methode das Initialisieren des Objekts.
null
content
succ
content
succ
content
succ
content
succ
pred pred pred pred
null
first
last
size 4
Folie-770
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Iterator (Fortsetzung)
Entwurf der Klasse ForwardIterator:
Es wird ein Attribut current als Referenz auf die Klasse Element deklariert,
in dem die Position für einen Durchlauf gemerkt wird.
Es wird ein Konstruktor deklariert, der die Referenz current initialisiert.
Es wird eine Methode next() deklariert, die den Inhalt eines Elements liefert
und die Referenz current zum nächsten Element bewegt.
Es wird eine Methode hasNext() deklariert, die anzeigt, ob es ein weiteres,
noch nicht besuchtes Element gibt.
Die Klasse ForwardIterator ist also sehr einfach gestaltet.
Folie-771
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Iterator (Fortsetzung)
Implementierung der Klasse ForwardIterator
public class ForwardIterator
{
private Element current;
public ForwardIterator( Element elem )
{
current = elem;
}
public boolean hasNext()
{
return current != null;
}
...
Referenz, die die Position merkt
Konstruktor, erhält Referenz auf
Anfangsobjekt als Parameter
next verweist auf das Objekt,
das vom nächsten Aufruf von
next() geliefert wird
Folie-772
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Iterator (Fortsetzung)
Implementierung der Klasse ForwardIterator
public Object next()
{
if ( hasNext() ) {
Object content = current.getContent();
current = current.getSucc();
return content;
} else {
throw new IllegalStateException();
}
}
current
null
content
succ
content
succ
content
succ
content
succ
pred pred pred pred
null
ForwardIterator
Folie-773
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Iterator (Fortsetzung)
Implementierung der Klasse ForwardIterator
public Object next()
{
if ( hasNext() ) {
Object content = current.getContent();
current = current.getSucc();
return content;
} else {
throw new IllegalStateException();
}
}
current
null
content
succ
content
succ
content
succ
content
succ
pred pred pred pred
null
content
Folie-774
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Iterator (Fortsetzung)
Implementierung der Klasse ForwardIterator
public Object next()
{
if ( hasNext() ) {
Object content = current.getContent();
current = current.getSucc();
return content;
} else {
throw new IllegalStateException();
}
}
current
null
content
succ
content
succ
content
succ
content
succ
pred pred pred pred
null
content
Folie-775
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Iterator (Fortsetzung)
Ergänzung in der Klasse DoublyLinkedList
public ForwardIterator iterator()
{
return new ForwardIterator( first );
}
Die Methode iterator() gibt ein Objekt der Klasse ForwardIterator zurück, dessen
Attribut current auf das erste Element der Liste verweist.
Innerhalb von DoublyLinkedList kann auf das private Attribut first zugegriffen werden!
Durchlauf beginnt bei first
current
null
content
succ
content
succ
content
succ
content
succ
pred pred pred pred
null
erzeugt
Folie-776
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Iterator (Fortsetzung)
Beispiel für den Einsatz eines Iterators
Nun kann die Summe der Werte einer Liste von Integer-Werten in einer einfachen Schleife
berechnet werden.
DoublyLinkedList ints = new DoublyLinkedList();
...
int sum = 0;
ForwardIterator intsIterator = ints.iterator();
while ( intsIterator.hasNext() )
{
sum += (int)intsIterator.next();
}
Folie-777
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Iterator (Fortsetzung)
weitere Beispiele für den Einsatz eines Iterators
Summe der Quadrate aller Werte von ints:
int sum = 0;
int value = 0;
ForwardIterator intsIterator = ints.iterator();
while ( intsIterator.hasNext() )
{
value = (int)intsIterator.next();
sum += value * value;
}
Summe der bis zu 10 ersten Werte von ints:
int sum = 0;
int count = 0;
ForwardIterator intsIterator = ints.iterator();
while ( count < 10 && intsIterator.hasNext() )
{
sum += (int)intsIterator.next();
count++;
}
Vorsicht: next() setzt weiter!
Folie-778
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Iterator (Fortsetzung)
weitere Beispiele für den Einsatz eines Iterators
Summe der bis zu 10 letzten Werte von ints:
Mit ForwardIterator etwas umständlich zu lösen.
Aber mit zusätzlicher Deklaration einer Klasse ReverseIterator mit gleicher Schleife:
public class ReverseIterator {
private Element current;
public ReverseIterator( Element elem ) {
current = elem;
}
public boolean hasNext() {
return current != null;
}
public Object next() {
if ( hasNext() ) {
Object content = current.getContent();
current = current.getPred();
return content;
} else {
throw new IllegalStateException();
}
}
}
current wandert nach vorne
Folie-779
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Iterator (Fortsetzung)
Ergänzung in der Klasse DoublyLinkedList
public ReverseIterator reverseIterator()
{
return new ReverseIterator( last );
}
Die Methode reverseIterator() gibt ein Objekt der Klasse ReverseIterator zurück,
dessen Attribut current auf das letzte Element der Liste verweist.
Innerhalb von DoublyLinkedList kann auf das private Attribut last zugegriffen werden!
Die Implementierung der Klassen ForwardIterator und ReverseIterator weisen
Gemeinsamkeiten auf, die nun in einer Klasse ListIterator zusammengefasst werden,
von der die Klassen ForwardIterator und ReverseIterator erben.
Vorteile:
– Es kann der gleiche Programmtext mit verschiedenen Iteratoren ausgeführt werden,
wenn der Iterator unter einer Referenz des Typs ListIterator abgelegt wird.
– Der Schreibaufwand wird vermindert.
Durchlauf beginnt bei last
Folie-780
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klassenhierarchie für Iteratoren
public class ListIterator
{
private Element current;
public ListIterator( Element elem )
{
current = elem;
}
public boolean hasNext()
{
return current != null;
}
public Object next()
{
throw new IllegalStateException();
}
}
identisch übernommen aus den
beiden bekannten Klassen
ForwardIterator und
ReverseIterator
Folie-781
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klassenhierarchie für Iteratoren (Fortsetzung)
public class ListIterator
{
private Element current;
public ListIterator( Element elem )
{
current = elem;
}
public boolean hasNext()
{
return current != null;
}
public Object next()
{
throw new IllegalStateException();
}
}
Problem 1:
private verhindert einen
Zugriff in den Unterklassen
Folie-782
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klassenhierarchie für Iteratoren (Fortsetzung)
public class ListIterator
{
private Element current;
public ListIterator( Element elem )
{
current = elem;
}
public boolean hasNext()
{
return current != null;
}
public Object next()
{
throw new IllegalStateException();
}
}
Beide Probleme werden nun gelöst.
Signatur muss in der Oberklasse
für eine Nutzung bekannt sein,
aber so ist der Rumpf sinnlos
Problem 1:
private verhindert einen
Zugriff in den Unterklassen
Problem 2:
Folie-783
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klassenhierarchie für Iteratoren (Fortsetzung)
public abstract class ListIterator
{
Element current;
public ListIterator( Element elem )
{
current = elem;
}
public boolean hasNext()
{
return current != null;
}
public abstract Object next();
}
Zugriffsrecht: package
Folie-784
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zugriffsrecht package
Das Zugriffsrecht package für Attribute oder Methoden erlaubt den Zugriff
– in der Klasse, in der das Attribut oder die Methode deklariert wurde, und
– in dem Paket, dem die Klasse zugoerdnet ist.
Durch package werden also die Zugriffsmöglichkeiten gegenüber public beschränkt.
Der Zugriff ist in ausgewählten Klassen möglich und damit weiter gefasst als bei private.
Die Klassen im Paket werden dadurch «besser gestellt» als außerhalb liegende Klassen.
Anmerkung:
Für das Zugriffsrecht package existiert kein Schlüsselwort.
Das Fehlen einer Angabe zum Zugriffsrecht für ein Attribut oder eine Methode deklariert das
Zugriffsrecht package.
Folie-785
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Paket
Bisher bekannte strukturierende Einheiten in Java sind Klassen und Methoden.
Diese Strukturierungsmöglichkeiten sind für große Projekte nicht ausreichend,
da getrennte Namensräume nur über das Einrichten von Klassen geschaffen werden können.
Die konzeptionelle Aufgabe einer Klasse ist aber die Typisierung von Objekten und nicht das
Schaffen eines Namensraums.
Daher bietet Java mit dem Konzept Paket eine zusätzliche Strukturierungseinheit,
mit dem ein Namensraum abgegrenzt werden kann.
Pakete besitzen in der Regel kleingeschriebene Namen.
Pakete können geschachtelt werden.
Paketschachtelungen entsprechen in der Regel Verzeichnisstrukturen.
Folie-786
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Pakete (Fortsetzung)
Zuordnung einer Klasse zu einem Paket:
Die Datei mit der Klasse muss im Betriebssytem in dem Verzeichnis abgelegt werden,
das dem Paket entspricht.
Die Datei mit dem Programmtext der Klasse muss als ersten Eintrag eine package-Deklaration
enthalten:
package dap1list;
public class DoublyLinkedList
{ ... }
Jede Datei kann nur höchstens einem Paket zugeordnet werden,
also höchstens eine package-Deklaration enthalten.
Enthält eine Datei keine package-Deklaration, so wird sie implizit dem default package
zugeordnet. Somit gehört jede Datei zu einem Paket.
Die Struktur geschachtelter Pakete wird durch eine .-Notation beschrieben.
dap1list Klassen des Pakets liegen im Verzeichnis dap1list
dap1.trees Klassen des Pakets liegen im Verzeichnis trees
innerhalb des Verzeichnis dap1
Folie-787
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Pakete (Fortsetzung)
Nutzung von Klassen aus anderen Paketen:
Um eine Klasse aus einem anderen Paket zu nutzen, muss deren Name mit der Angabe des
zugehörigen Pakets kombiniert werden.
Eine Klasse des Pakets dap1list kann also eine Liste folgendermaßen genutzt werden:
dap1list.DoublyLinkedList allPersons =
new dap1list.DoublyLinkedList();
Klassen aus dem default package können nicht importiert werden,
da das default package nicht über eine solche Angabe angesprochen werden kann.
Folie-788
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Pakete (Fortsetzung)
Nutzung von Klassen aus anderen Paketen:
Da diese Schreibweise bei häufiger Nutzung aus anderen Paketen etwas aufwändig ist, kann
abkürzend eine import-Anweisung erfolgen.
Diese steht am Anfang einer Datei – aber hinter der Paketzuordnung mit package. Nach dem
Importieren kann eine Klasse so genutzt werden, als wäre sie innerhalb des importierenden Pakets
deklariert, also ohne die vollständige Qualifikation.
import dap1list.DoublyLinkedList;
...
DoublyLinkedList allPersons = new DoublyLinkedList();
Auch ein Import aller Klassen eines Pakets ist möglich:
import dap1list.*;
Treten durch das Importieren von Klassen Namenskonflikte mit Klassen aus dem importierenden
Paket auf, so müssen diese durch vollständige Angabe des Pakets gelöst werden.
Folie-789
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klassenhierarchie für Iteratoren (Fortsetzung)
package dap1list;
public abstract class ListIterator
{
Element current;
public ListIterator( Element elem )
{
current = elem;
}
public boolean hasNext()
{
return current != null;
}
public abstract Object next();
}
Modifizierer abstract
Folie-790
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Abstrakte Klasse
Eine abstrakte Klasse wird durch den Modifizierer abstract deklariert.
Eine abstrakte Klasse wird ausschließlich deshalb deklariert,
um in Vererbungsstrukturen als Oberklasse zu dienen.
Objekte einer abstrakten Klasse können nicht erzeugt werden,
der new-Operator kann nicht angewandt werden (Compiler-Fehler).
Eine abstrakte Klasse kann aber Konstruktoren besitzen, die dann in den Konstruktoren von
Unterklassen über super( ... ) angesprochen werden können.
Besitzt eine abstrakte Klasse keinen Standardkonstruktor,
müssen die Unterklassen eigene Konstruktoren implementieren.
Folie-791
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klassenhierarchie für Iteratoren (Fortsetzung)
package dap1list;
public abstract class ListIterator
{
Element current;
public ListIterator( Element elem )
{
current = elem;
}
public boolean hasNext()
{
return current != null;
}
public abstract Object next();
}
Modifizierer abstract
Modifizierer abstract
kein Methodenrumpf notwendig
ist Voraussetzung für
Folie-792
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Abstrakte Methode
Eine abstrakte Klasse kann – muss aber nicht – abstrakte Methoden besitzen.
Eine abstrakte Methode wird durch den Modifizierer abstract deklariert.
Eine abstrakte Methode besteht nur aus einer Signatur,
die durch ; abgeschlossen wird.
Eine abstrakte Methode stellt eine Vorgabe für ihre Unterklassen dar:
In Unterklassen müssen entweder
– alle abstrakten Methoden implementiert werden oder
– die Unterklasse muss auch wieder als abstrakte Klasse deklariert werden:
Dann wird eine Implementierung auf tiefer liegende Unterklassen verschoben.
Die Klasse ListIterator sorgt also dafür,
dass jede ihrer nicht abstrakten Unterklassen
– einen Konstruktor und
– eine Methode mit der folgenden Signatur implementieren muss:
public Object next()
Folie-793
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Syntaxdiagramm zu Modifizierern
private
Modifizierer
Modifiziererliste
public
static
Modifizierer
abstract
Folie-794
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klassenhierarchie für Iteratoren (Fortsetzung)
package dap1list;
public class ForwardIterator extends ListIterator
{
public ForwardIterator( Element elem )
{
super( elem );
}
public Object next()
{
if ( hasNext() )
{
Object content = current.getContent();
current = current.getSucc();
return content;
}
else
{
throw new IllegalStateException();
}
}
}
spezialisiert abstrakte Oberklasse
notwendig, da kein Standard-
konstruktor in der Oberklasse
notwendig, da Signatur in
Oberklasse vorgegeben
Folie-795
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klassenhierarchie für Iteratoren (Fortsetzung)
package dap1list;
public class ForwardIterator extends ListIterator
{
public ForwardIterator( Element elem )
{
super( elem );
}
public Object next()
{
if ( hasNext() )
{
Object content = current.getContent();
current = current.getSucc();
return content;
}
else
{
throw new IllegalStateException();
}
}
}
package dap1list;
public class ReverseIterator extends ListIterator
{
public ReverseIterator( Element elem )
{
super( elem );
}
public Object next()
{
if ( hasNext() )
{
Object content = current.getContent();
current = current.getPred();
return content;
}
else
{
throw new IllegalStateException();
}
}
}
spezialisiert abstrakte Klasse
notwendig, da kein Standard-
konstruktor in der Oberklasse
notwendig, da Signatur in
Oberklasse vorgegeben
Folie-796
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klassenhierarchie für Iteratoren (Fortsetzung)
(im Paket dap1list)
Element
ForwardIterator ReverseIterator
ListIteratorDoublyLinkedList
«abstract»
kennt Klasse als Typ
Folie-797
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Iterator
Hier vorgestellt wurde als Beispiel ein Iterator für eine doppelt verkettete Liste.
Allgemein bietet das Muster Iterator eine Lösung an,
wie auf Elemente einer zusammengesetzten Struktur
sequenziell zugegriffen werden kann,
ohne die technischen Details der Struktur zu enthüllen und
ohne einen Zugriff von außen auf die Struktur zu erlauben.
Das Muster Iterator schlägt dazu vor,
spezielle Klassen anzulegen, deren Objekte nur dazu dienen,
die Daten einer Struktur genau einmal zu durchlaufen.
Genau so sind die hier vorgestellten Iteratoren aufgebaut.
Ein besonderes Problem beim Einsatz von Iteratoren ist das Ändern der Inhalte
der durchlaufenen Datenstruktur und insbesondere das Löschen von Elementen
während des Durchlaufs.
Es ist zulässig, sich darum – mit geeigneter Dokumentation – nicht zu kümmern.
Die hier vorgestellten Iteratoren arbeiten fehlerhaft,
wenn das Element aus der Liste gelöscht wird, auf das current verweist.
Folie-798
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster
Ein Entwurfsmuster (design pattern) ist ein geeigneter Lösungsansatz für ein in der
Softwareentwicklung wiederkehrendes Problem.
Entwurfsmuster sind aus praktischen Erfahrungen abgeleitet und
1995 erstmals vorgestellt worden. *)
Entwurfsmuster bieten nur einen Ansatz,
der für jede konkret gegebene Situation geeignet realisiert werden muss.
Das Muster Iterator ist ein Verhaltensmuster,
da ein bestimmter Ablauf vorgeschlagen wird.
Das Entwurfmuster Iterator gibt eine Lösungsidee vor,
wie beliebige Datenstrukturen gleichförmig durchlaufen werden können.
Das Entwurfsmuster Iterator ist in seinen Einsatzmöglichkeiten nicht auf Listen beschränkt:
Beispielsweise lassen sich auch binäre Bäume sequentiell durchlaufen.
Strukturelle Änderungen können als zusätzliche Methoden durch einen Iterator angeboten
werden. Die wesentliche Aufgabe des Iterators bleibt aber das Durchlaufen der Daten.
*) E. Gamma, R. Helm, R. Johnson, J. Vlissides: Design Patterns. Elements of Reusable Object-Oriented Software.
Addison Wesley, 1995 (Das Buch ist sehr schwer zu lesen.)
Folie-799
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klassenhierarchie für Iteratoren – weitere Abstraktionen
package dap1list;
public class ForwardIterator extends ListIterator
{
public ForwardIterator( Element elem )
{
super( elem );
}
public Object next()
{
if ( hasNext() )
{
Object content = current.getContent();
current = current.getSucc();
return content;
}
else
{
throw new IllegalStateException();
}
}
}
package dap1list;
public class ReverseIterator extends ListIterator
{
public ReverseIterator( Element elem )
{
super( elem );
}
public Object next()
{
if ( hasNext() )
{
Object content = current.getContent();
current = current.getPred();
return content;
}
else
{
throw new IllegalStateException();
}
}
}
nur eine Zuweisung
unterscheidet sich
Folie-800
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klassenhierarchie für Iteratoren – weitere Abstraktionen (Fortsetzung)
Analyse:
Die Implementierungen der Methode next() in den beiden Unterklassen
unterscheiden sich nur in einer Zuweisung.
Ziel:
Die Klassenhierarchie wird derart umgestaltet, dass
der Ablauf der Methode next() in der Oberklasse ListIterator formuliert werden kann.
Folie-801
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klassenhierarchie für Iteratoren – weitere Abstraktionen (Fortsetzung)
Analyse:
Die Implementierungen der Methode next() in den beiden Unterklassen
unterscheiden sich nur in einer Zuweisung.
Ziel:
Die Klassenhierarchie wird derart umgestaltet, dass
der Ablauf der Methode next() in der Oberklasse ListIterator formuliert werden kann.
Lösungsansatz:
Die Bestimmung des nächsten Elements wird in eine eigene Methode step() ausgelagert.
Die Methode step() wird in der Klasse ListIterator als abstrakte Methode deklariert.
In der Klasse ListIterator ist also noch nicht festgelegt, was step() tun wird.
Die Methode step() kann aber in der Klasse ListIterator bereits verwendet werden.
Ein Objekt, für das die Methode next() aufgerufen werden kann, setzt voraus, dass
alle abstrakten Methoden – also auch step() implementiert sind.
Während der Ausführung wird dann die zum Objekt gehörende Implementierung
von step() ausgeführt.
Folie-802
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klassenhierarchie für Iteratoren – weitere Abstraktionen (Fortsetzung)
package dap1list;
public abstract class ListIterator
{
Element current;
ListIterator( Element elem ) { current = elem; }
public boolean hasNext() { return current != null; }
public Object next()
{
if ( hasNext() )
{
Object content = current.getContent();
current = step();
return content;
}
else
{
throw new IllegalStateException();
}
}
abstract Element step();
}
abstrakte Deklaration
Aufruf von step()
bereits bekannt
von step()
Folie-803
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klassenhierarchie für Iteratoren – weitere Abstraktionen (Fortsetzung)
package dap1list;
public class ForwardIterator extends ListIterator
{
public ForwardIterator( Element elem ) { super( elem ); }
Element step()
{
return current.getSucc();
}
}
package dap1list;
public class ReverseIterator extends ListIterator
{
public ReverseIterator( Element elem ) { super( elem ); }
Element step()
{
return current.getPred();
}
}
Implementierung
in den Unterklassen
Folie-804
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Innere Klasse
Die Klassen für die beiden Iteratoren und die Elemente der Liste sind öffentlich.
Allerdings können diese Klassen sinnvoll nur im Zusammenhang mit der
Klasse DoublyLinkedList benutzt werden, für die sie gestaltet worden sind.
Die Benutzbarkeit der Klasse DoublyLinkedList kann verbessert werden,
wenn diese Klassen gar nicht öffentlich verfügbar sind.
Folie-805
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Innere Klasse (Fortsetzung)
Die Klassen für die beiden Iteratoren und die Elemente der Liste sind im Paket dap1list
enthalten. Da sie nur innerhalb des Pakets genutzt werden, können sie mit dem Zugriffsrecht
package deklariert werden.
Die Benutzbarkeit der Klasse DoublyLinkedList kann weiter verbessert werden,
wenn diese Klassen gar nicht einzeln verfügbar sind.
Java bietet die Möglichkeit, die Deklaration von Klassen innerhalb von anderen Klassen
vorzunehmen. Solche Klassen werden als innere Klassen bezeichnet.
Innere Klassen können mit Zugriffsrechten versehen werden.
Innere Klassen haben Zugriff auf Attribute und Methoden der sie umgebenden Klasse.
Die umgebende Klasse hat keinen besonderen Zugriff auf die Inhalte der inneren Klasse.
Innere Klassen treten auf als:
– statische innere Klasse
– Die innere Klasse steht gemeinsam mit der umgebenden Klasse zur Verfügung.
– Ein Objekt der umgebenden Klasse muss nicht erzeugt werden.
– Instanzklasse
– Die innere Klasse ist nur über ein Objekt der umgebenden Klasse verfügbar.
– Für jedes Objekt wird eine eigene innere Klasse angelegt, was gelegentlich zu
Kompatibilitätsproblemen führen kann.
Folie-806
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Innere Klasse (Fortsetzung)
Um die Implementierung der inneren Klassen vollständig verbergen zu können, wird eine
öffentliche, abstrakte Klasse Iterator angelegt, die lediglich zwei abstrakte Methoden
vorschreibt.
Referenzen auf Iterator können dann auf beliebige Iteratoren verweisen,
wenn alle Iteratoren als Unterklasse von Iterator vereinbart werden.
public abstract class Iterator
{
public abstract boolean hasNext();
public abstract Object next();
}
IteratorDoublyLinkedList
kennt Klasse als Typ
«abstract»
gibt zwei Methoden vor
Folie-807
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Innere Klasse (Fortsetzung)
public class DoublyLinkedList
{
private Element first, last;
private int size;
...
private abstract class ListIterator extends Iterator
{
Element current;
public boolean hasNext() { ... }
public Object next() { ... }
abstract Element step();
}
Die Klasse ListIterator wird außerhalb der Klasse DoublyLinkedList nicht benötigt,
da der Zugriff auf die Iteratoren ausschließlich über Referenzen auf die abstrakte Klasse
Iterator erfolgen.
Daher kann die Klasse ListIterator mit dem Zugriffsrecht private versehen werden.
Zugriffsrecht package
um Spezialisierung
zu ermöglichen
stellt Typkompatibilität her
public um Nutzung von
außen zu ermöglichen
step() in Unterklassen
Folie-808
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Innere Klasse (Fortsetzung)
...
private class ForwardIterator extends ListIterator
{
public ForwardIterator()
{
current = first;
}
Element step()
{
return current.getSucc();
}
}
...
Die Instanzklasse ForwardIterator kann auf das (Instanz-)Attribut first der umgebenden
Klasse DoublyLinkedList zugreifen.
Folie-809
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Innere Klasse (Fortsetzung)
...
public Iterator iterator()
{
return new ForwardIterator();
}
...
private class Element
{
private Object content;
private Element pred, succ;
...
}
}
auch die Klasse Element kann
nun verborgen werden
Folie-810
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Innere Klasse (Fortsetzung)
von außen sichtbare und
benutzbare Klassenstruktur:
interner Aufbau der Klasse DoublyLinkedList:
public class DoublyLinkedList
{
...
private abstract class ListIterator extends Iterator
{
...
}
private class ForwardIterator extends ListIterator
{
...
}
private class Element
{
...
}
}
IteratorDoublyLinkedList «abstract»
Folie-811
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Entwurfsmuster Iterator
(siehe Folie 761)
Nach Durcharbeiten des Kapitels Entwurfsmuster Iterator sollen
die teilnehmenden Studierenden
Pakete anlegen und nutzen können,
abstrakte Klassen kennen und einsetzen können,
innere Klassen kennen und einsetzen können,
das Entwurfsmuster Iterator kennen,
die Implementierung mit den Klassen ListIterator, ForwardIterator und
ReverseIterator verstehen und einsetzen können,
das Entwurfsmuster Iterator in anderen Kontexten einsetzen können.
Folie-812
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen, Algorithmen
und Programmierung 1 (DAP 1)
Fakultät für Informatik
Wintersemester 2019/20
Stefan Dissmann
Entwurfsmuster Strategie
Folie-813
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Entwurfsmuster Strategie
Nach Durcharbeiten des Kapitels Entwurfsmuster Strategie sollen
die teilnehmenden Studierenden
das Entwurfsmuster Strategie kennen,
Beispiele für Strategien kennen,
eigene Strategien für vorhandene Strategieklassen implementieren können,
eigene Strategieklassen implementieren können,
den Einsatzbereich des Entwurfsmusters Strategie gegen den des Entwurfsmusters Iterator
abgrenzen können.
Folie-814
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie
Der vorgestellte Iterator besitzt noch einige Nachteile:
– Es ist mit dem Iterator nicht möglich, strukturelle Änderungen an der Liste vorzunehmen:
– Der über den Iterator gefundene Inhalt kann geändert, aber nicht ausgetauscht werden.
– Das über den Iterator erreichte Element kann nicht entfernt werden.
– Die Nutzung des Iterators benötigt immer eine durch hasnext()-next()-Aufrufe kontrollierte
Schleife.
Wie kann eine Lösung aussehen, die diese Nachteile vermeidet?
Strukturelle Änderungen müssen innerhalb der Klasse DoublyLinkedList ausgeführt
werden, da nur dort die Klasse Element bekannt ist.
Die Art der Änderung soll jedoch flexibel außerhalb der Klasse DoublyLinkedList
deklariert werden können.
Ein innerhalb von DoublyLinkedList deklarierter Ablauf – eine Methode – muss also auf
einen beliebigen außerhalb deklarierten Ablauf – auch eine Methode – zugreifen.
Als Transportbehälter dient dabei ein Objekt einer Klasse, die eine abstrakte Klasse realisiert,
die innerhalb und außerhalb von DoublyLinkedList bekannt ist.
Diese Art des Aufbaus eines Algorithmus ist eine Umsetzung des Entwurfsmusters Strategie.
Folie-815
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie – SubstitutionStrategy
public class DoublyLinkedList
{
...
public static abstract class SubstitutionStrategy
{
public abstract Object substitute( Object ref );
}
...
}
Die abstrakte Klasse SubstitutionStrategy gibt vor, wie die Methoden deklariert werden
können, die der Klasse DoublyLinkedList zur Ausführung übergeben werden können.
Die Signatur der Methode substitute ermöglicht die Rückgabe eines Objekts an die Methode,
die die Methode substitute aufruft.
Daher können nun Änderungen an den Inhalten der Liste vorgenommen werden,
die in der Ausführung von substitute bestimmt werden.
Die Deklaration erfolgt als öffentliche statische innere Klasse – public static, damit
außerhalb von DoublyLinkedList Unterklassen angelegt werden können, ohne zuvor ein
Objekt von DoublyLinkedList angelegt haben zu müssen.
statische Deklaration notwendig
Folie-816
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie – SubstitutionStrategy (Fortsetzung)
public class DoublyLinkedList
{
...
public void substituteAll( SubstitutionStrategy s )
{
Element current = first;
while ( current != null )
{
current.setContent( s.substitute( current.getContent() ) );
current = current.getSucc();
}
}
...
}
Die Methode substituteAll ruft eine Implementierung der Methode substitute
nacheinander für alle Elemente der Liste auf.
Dabei wird substitute der Inhalt eines Elements als Argument übergeben.
substitute liefert ein Objekt zurück, das den Inhalt der Liste an der Position der Referenz
current ersetzt.
Folie-817
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie – SubstitutionStrategy (Fortsetzung)
Beispiel für eine Strategie, mit der der Wert jedes einzelnen Elements einer Liste von
Integer-Objekten verdoppelt werden kann:
public class DoubleIntegersStrategy
extends DoublyLinkedList.SubstitutionStrategy
Element
DoublyLinkedList
SubstitutionStrategy
substituteAll( s )Methode mit
Parameter
«abstract»
Folie-818
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie – SubstitutionStrategy (Fortsetzung)
Beispiel für eine Strategie, mit der der Wert jedes einzelnen Elements einer Liste von
Integer-Objekten verdoppelt werden kann:
public class DoubleIntegersStrategy
extends DoublyLinkedList.SubstitutionStrategy
DoubleIntegersStrategy
Element
DoublyLinkedList
SubstitutionStrategy
substituteAll( s )Methode mit
Parameter
«abstract»
Folie-819
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie – SubstitutionStrategy (Fortsetzung)
Beispiel für eine Strategie, mit der der Wert jedes einzelnen Elements einer Liste von
Integer-Objekten verdoppelt werden kann:
public class DoubleIntegersStrategy
extends DoublyLinkedList.SubstitutionStrategy
Objekt erzeugen und
als Argument übergeben
DoubleIntegersStrategy
Element
DoublyLinkedList
SubstitutionStrategy
substituteAll( s )Methode mit
Parameter
«abstract»
Folie-820
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie – SubstitutionStrategy (Fortsetzung)
Beispiel für eine Strategie, mit der der Wert jedes einzelnen Elements einer Liste von
Integer-Objekten verdoppelt werden kann.
public class DoubleIntegersStrategy
extends DoublyLinkedList.SubstitutionStrategy
{
public Object substitute( Object ref )
{
return 2 * (int)ref;
}
}
Erinnerung:
Aufgrund des Typs Object der Rückgabe wird zu dem in der return-Anweisung berechneten
int-Wert durch Boxing in ein passendes Integer-Objekt erzeugt, das zurückgegeben wird.
Folie-821
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie – SubstitutionStrategy (Fortsetzung)
Nutzung der DoubleIntegersStrategy
DoublyLinkedList ints = new DoublyLinkedList();
ints.add( 5 );
ints.add( 6 );
ints.add( 11 );
ints.add( 2 );
ints.add( 9 );
DoubleIntegersStrategy manip = new DoubleIntegersStrategy();
System.out.print("in: ");
ints.showAll();
ints.substituteAll( manip );
System.out.print("substituted: ");
ints.showAll();
Ausgabe: in: 5, 6, 11, 2, 9
substituted: 10, 12, 22, 4, 18
Folie-822
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie – SubstitutionStrategy (Fortsetzung)
public class AddNStrategy
extends DoublyLinkedList.SubstitutionStrategy
{
private int n;
public AddNStrategy( int increment )
{
n = increment;
}
public Object substitute( Object ref )
{
return (int)ref + n;
}
}
Die Methode substitute erhöht der Wert jedes einzelnen Elements einer Liste von
Integer-Objekten um das im Konstruktor angegebene Inkrement.
Folie-823
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie – InspectionStrategy
Der Aufruf der Methode substitute eines SubstitutionStrategy-Objekts durch die
Methode substituteAll einer Liste führt immer zu einer Zuweisung an den Inhalt eines
Elements der Liste.
Sollen nur die Inhalte betrachtet – aber nicht ersetzt – werden, vermeidet eine
eingeschränkte Strategie unbeabsichtigte Ersetzungen.
Die abstrakte Klasse InspectionStrategy gibt vor, wie die Methoden deklariert werden
können, die der Klasse DoublyLinkedList zur Ausführung übergeben werden können.
Die Signatur der Methode inspect schränkt die Realisierung ein:
Der Parameter ist eine Referenz auf Object, es erfolgt keine Rückgabe,
der Inhalt eines Elements kann also nicht ersetzt werden.
Folie-824
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie – InspectionStrategy
public class DoublyLinkedList
{
...
public static abstract class InspectionStrategy
{
public abstract void inspect( Object ref );
}
...
}
Die abstrakte Klasse InspectionStrategy gibt vor, wie die Methoden deklariert werden
können, die der Klasse DoublyLinkedList zur Ausführung übergeben werden können.
Die Signatur der Methode inspect schränkt die Realisierung ein:
Der Parameter ist eine Referenz auf Object, es erfolgt keine Rückgabe.
Folie-825
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie – InspectionStrategy (Fortsetzung)
public class DoublyLinkedList
{
...
public void inspectAll( InspectionStrategy s )
{
Element current = first;
while ( current != null )
{
s.inspect( current.getContent() );
current = current.getSucc();
}
}
...
}
Die Methode inspectAll ruft eine Implementierung der Methode inspect nacheinander für
alle Elemente der Liste auf.
Dabei wird inspect der Inhalt eines Elements als Argument übergeben.
Das Ergebnis der in der Methode inspect vorgenommenen Untersuchung muss die Methode
selbst in geeigneter Form in einem Objekt ablegen, beispielsweise in ihrem Strategie-Objekt.
Folie-826
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie – InspectionStrategy (Fortsetzung)
Beispiel für eine Strategie, mit der die Summe aller Werte einer Liste von Integer-Objekten
berechnet werden kann:
public class IntegerSummationStrategy
Element
DoublyLinkedList
InspectionStrategy
inspectAll( s )Methode mit
Parameter
«abstract»
Folie-827
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie – InspectionStrategy (Fortsetzung)
Beispiel für eine Strategie, mit der die Summe aller Werte einer Liste von Integer-Objekten
berechnet werden kann:
public class IntegerSummationStrategy
extends InspectionStrategy
IntegerSummationStrategy
Element
DoublyLinkedList
InspectionStrategy
inspectAll( s )Methode mit
Parameter
«abstract»
Folie-828
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie – InspectionStrategy (Fortsetzung)
Beispiel für eine Strategie, mit der die Summe aller Werte einer Liste von Integer-Objekten
berechnet werden kann:
public class IntegerSummationStrategy
extends InspectionStrategy
Objekt erzeugen und
als Argument übergeben
IntegerSummationStrategy
Element
DoublyLinkedList
InspectionStrategy
inspectAll( s )Methode mit
Parameter
«abstract»
Folie-829
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie – InspectionStrategy (Fortsetzung)
Beispiel für eine Strategie, mit der die Summe aller Werte einer Liste von Integer-Objekten
berechnet werden kann.
public class IntegerSummationStrategy
extends DoublyLinkedList.InspectionStrategy
{
private int sum;
public IntegerSummationStrategy() { sum = 0; }
public void inspect( Object ref )
{
sum += (int)ref;
}
public int getSum()
{
return sum;
}
}
Hinweis: Das Attribut sum wird nie auf den Wert 0 zurückgesetzt. Mehrfaches Benutzen eines
IntegerSummationStrategy-Objekts führt daher zu fehlerhaften Ergebnissen.
berechnet die Summe
aller Werte
Attribut sum für
Zwischenergebnisse
Abruf des Ergebnisse
der Summation
Folie-830
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie – InspectionStrategy (Fortsetzung)
Nutzung der IntegerSummationStrategy
DoublyLinkedList ints = new DoublyLinkedList();
ints.add( 5 );
ints.add( 6 );
ints.add( 11 );
ints.add( 2 );
ints.add( 9 );
ints.showAll();
IntegerSummationStrategy sumUp = new IntegerSummationStrategy();
ints.inspectAll( sumUp );
System.out.println( sumUp.getSum() );
Ausgabe: in: 5, 6, 11, 2, 9
sum: 33
Folie-831
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie – InspectionStrategy (Fortsetzung)
Beispiel für eine Strategie, mit der die Anzahl aller Studierenden mit einer Matrikelnummer
größer 100 in einer Liste von Student-Objekten bestimmt werden kann.
public class CountStudentGt100Strategy
extends DoublyLinkedList.InspectionStrategy
{
private int quantity;
public CountStudentGt100Strategy() { quantity = 0; }
public void inspect( Object ref )
{
if ( ((Student)ref).getRegistrationNo() > 100 )
{
quantity++;
}
}
public int getQuantity() { return quantity; }
}
Hinweis: Das Attribut quantity wird nie auf den Wert 0 zurückgesetzt. Mehrfaches Benutzen
eines CountStudentGt100Strategy-Objekts führt daher zu fehlerhaften Ergebnissen.
prüft die Studierenden
und zählt
Attribut quantity für
Zwischenergebnisse
Abruf des Ergebnisse
der Zählung
Folie-832
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie – InspectionStrategy (Fortsetzung)
Nutzung der CountStudentGt100Strategy
DoublyLinkedList students = new DoublyLinkedList();
students.add( new Student( “A”, “Inf”, 45 ) );
students.add( new Student( “B”, “Inf”, 167 ) );
students.add( new Student( “C”, “Inf”, 22 ) );
students.add( new Student( “D”, “Inf”, 124 ) );
students.add( new Student( “E”, “Inf”, 123 ) );
students.add( new Student( “F”, “Inf”, 12 ) );
students.showAll();
CountStudentGt100Strategy counter = new CountStudentGt100Strategy();
students.inspectAll( counter );
System.out.println( counter.getQuantity() );
Ausgabe: in: student: A, registration number: 45(Inf), student: B, …
quantity: 3
Folie-833
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie – DeletionStrategy
public class DoublyLinkedList
{
…
public static abstract class DeletionStrategy
{
public abstract boolean select( Object ref );
}
…
}
Die abstrakte Klasse DeletionStrategy gibt vor, wie die Methoden deklariert werden
können, die der Klasse DoublyLinkedList zur Ausführung übergeben werden können.
Die Signatur der Methode select gibt einen boolean-Wert an die Methode zurück, die die
Methode select aufruft.
Aufgrund des zurückgegebenen Wertes können nun Änderungen an der Struktur der Liste
vorgenommen werden.
Folie-834
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie – DeletionStrategy (Fortsetzung)
public void deleteSelected( DeletionStrategy s )
{
Element current = first;
while ( current != null )
{
Element candidate = current;
current = current.getSucc();
if ( s.select( candidate.getContent() ) )
{
remove( candidate );
}
}
}
Die Methode deleteSelected prüft alle Elemente der Liste durch einen Aufruf der
Methode select.
Liefert select für den Inhalt eines Elements das Ergebnis true, wird das Element (und damit
auch die Referenz auf den Inhalt) aus der Liste gelöscht.
Die Methode deleteSelected nutzt die private Methode remove, die das als Argument über-
gebene Element aus der Liste löscht.
Folie-835
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie – DeletionStrategy (Fortsetzung)
private void remove( Element e )
{
if ( e != null )
{
if ( e.hasSucc() && e.hasPred() )
{
e.getPred().connectAsSucc( e.getSucc() );
} else if ( e == first && e.hasSucc() )
{
first = first.getSucc();
first.disconnectPred();
} else if ( e == last && e.hasPred() )
{
last = last.getPred();
last.disconnectSucc();
} else {
first = last = null;
}
size–;
}
}
letztes, aber nicht
innen liegendes Element
erstes, aber nicht
einziges Element
einziges Element
einziges Element
Folie-836
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie – DeletionStrategy (Fortsetzung)
public class RemoveEvenIntegersStrategy
extends DoublyLinkedList.DeletionStrategy
{
public boolean select( Object ref )
{
return (int)ref % 2 == 0;
}
}
Die Methode select liefert true für jedes Element aus einer Liste von Integer-Objekten,
dessen Inhalt eine gerade Zahl ist.
Im Zusammenwirken mit der Methode deleteSelected werden so genau diese Elemente aus
der Liste gelöscht.
Folie-837
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie
Zusammenfassung:
Das Entwurfsmuster Strategie skizziert einen Lösungsweg,
wie eine «Familie» von Algorithmen implementiert werden kann:
– Ein vorgegebener Rahmen – inspectAll, substituteAll, deleteSelected – wird durch den
Aufruf austauschbarer Methoden – inspect, substitute, select – konkretisiert.
– Der Rahmen bestimmt die «gemeinsamen familiären Eigenschaften».
Die austauschbaren Methoden werden in geeigneten Klassen deklariert und
durch Erzeugen und Übergabe eines Objekts als Argument in den Rahmen eingebracht.
Die Deklarationen von Objekt und austauschbarer Methode erfolgen außerhalb der Klasse,
in der die Methode ihre Wirkung entfalten soll.
Die Implementierung der Methode muss daher ohne Zugriff auf private Inhalte der Klasse
erfolgen.
Die vorgestellten Beispiele zeigen, dass
der Umfang der in einer Familie möglichen Änderungen/Abläufe eingeschränkt werden kann:
– Unterklassen von SubstitutionStrategy können die Inhalte der Elemente ersetzen.
– Unterklassen von InspectionStrategy können die Inhalte der Elemente nur lesen.
– Unterklassen von DeletionStrategy können Elemente löschen.
Folie-838
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Entwurfsmuster Strategie (Fortsetzung)
Vorteile des Einsatzes:
In Klassen festgelegte Rahmen für Abläufe können durch Strategien angepasst werden,
ohne dass ein Zugriff auf die Implementierungen der Klassen erfolgen muss.
Die Implementierungen der den Rahmen bildenden Klassen müssen für Anpassungen nicht
verstanden werden.
Die zum Einsatz kommenden Strategien müssen bei der Implementierung der den
Rahmen bildenden Klassen nicht bekannt sein.
Strategien können während der Ausführung gewechselt werden,
wenn dieses von den Klassen, die den Rahmen bilden, vorgesehen ist:
Dazu muss nur ein neues Strategie-Objekt eingefügt werden.
Folie-839
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Entwurfsmuster Strategie
(siehe Folie 813)
Nach Durcharbeiten des Kapitels Entwurfsmuster Strategie sollen
die teilnehmenden Studierenden
das Entwurfsmuster Strategie kennen,
Beispiele für Strategien kennen,
eigene Strategien für vorhandene Strategieklassen implementieren können,
eigene Strategieklassen implementieren können,
den Einsatzbereich des Entwurfsmusters Strategie gegen den des Entwurfsmusters Iterator
abgrenzen können.
Folie-840
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen, Algorithmen
und Programmierung 1 (DAP 1)
Fakultät für Informatik
Wintersemester 2019/20
Stefan Dissmann
Generische Klassen
Folie-841
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Generische Klassen
Nach Durcharbeiten des Kapitels Generische Klassen sollen
die teilnehmenden Studierenden
die Vorteile generischer Klassen kennen und erklären können,
generische Klassen nutzen können,
generische Klassen erstellen können.
Folie-842
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Allgemeine Implementierungen mit der Klasse Object
Die Klasse DoublyLinkedList kann beliebige Inhalte verwalten.
Die Methoden dieser Klasse können für ihre Inhalte nur die wenigen Methoden
der Klasse Object voraussetzen.
Werden Objekte zurückgegeben, so muss die aufrufende Methode zunächst einen Type-Cast
(Folie 755) vornehmen, um den Compiler davon zu überzeugen, dass das Objekt den erwarteten
Typ hat.
Dieses Vorgehen hat den Nachteil, dass für jeden Inhalt meist Varianten von Methoden
implementiert werden müssen, bei denen eventuell (nur) der Type-Cast ersetzt werden muss.
Da die Klassen beliebige Inhalte verwalten können, können Inhalte auch beliebig gemischt
werden (Folie 746). Alle Beispiele mit Listen, die (ausschließlich) mit Integer-, Person- oder
Fraction-Objekten arbeiten, basieren auf der Disziplin des Entwicklers, immer auch nur
Objekte einer Klasse in einer Liste abzulegen.
Der Compiler kann hierbei keine Unterstützung leisten.
Folie-843
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Allgemeine Implementierungen mit der Klasse Object (Fortsetzung)
Die Klasse DoublyLinkedList kann beliebige Inhalte verwalten.
Die Methoden dieser Klasse können für ihre Inhalte nur die wenigen Methoden
der Klasse Object voraussetzen.
Werden Objekte zurückgegeben, so muss die aufrufende Methode zunächst einen Type-Cast
(Folie 755) vornehmen, um den Compiler davon zu überzeugen, dass das Objekt den erwarteten
Typ hat.
Dieses Vorgehen hat den Nachteil, dass für jeden Inhalt meist Varianten von Methoden
implementiert werden müssen, bei denen eventuell (nur) der Type-Cast ersetzt werden muss.
Da die Klassen beliebige Inhalte verwalten können, können Inhalte auch beliebig gemischt
werden (Folie 746). Alle Beispiele mit Listen, die (ausschließlich) mit Integer-, Person- oder
Fraction-Objekten arbeiten, basieren auf der Disziplin des Entwicklers, immer auch nur
Objekte einer Klasse in einer Liste abzulegen.
Der Compiler kann hierbei keine Unterstützung leisten.
Problem:
Referenzen auf Object bieten keine Möglichkeit, die Überwachung der Typzugehörigkeit durch
den Compiler vornehmen zu lassen.
Eine sicherere Lösung bieten generische Klassen an.
Folie-844
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Grundlegende Idee generischer Klassen
Zuerst wird eine Klasse deklariert, die für verschiedene Inhalte nutzbar ist und die Parameter als
Platzhalter für Typen enthält. Diese Klasse wird als generische Klasse bezeichnet.
Für eine Nutzung wird die generische Klasse durch die Angabe eines (Typ-)Arguments in eine
parametrisierte Klasse transformiert, die nur für den als Argument übergebenen Typ nutzbar ist.
Von dieser parametrisierten Klasse können dann Objekte erzeugt werden, die Attributwerte
speichern und auf denen Methoden ausgeführt werden können.
bisher: jetzt:
generische Klasse
Klasse parametrisierte Klasse
Objekt Objekt
Folie-845
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Deklaration einer generischen Klasse
Die Bezeichner zwischen < ... > werden Typparameter der Klassendeklaration genannt.
In Java werden Typparameter in der Regel als einzelne Großbuchstaben (z.B. T )
deklariert.
Bezeichner
{
generische Klasse
Klassenrumpf
class
}
Modifiziererliste
extends Bezeichner
Bezeichnerliste< >
Folie-846
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel für eine generische Klasse: DoublyLinkedList
public class DoublyLinkedList
{
private Element first, last;
private int size;
… // Methoden der Liste
private class Element
{
private T content;
private Element pred, succ;
… // Methoden der Klasse Element
}
}
T ist Platzhalter für immer den selben Typ.
Typparameter T
Deklaration einer
generischen Klasse
Folie-847
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel für eine generische Klasse: DoublyLinkedList
Beispiel für die Parametrisierung:
public class DoublyLinkedList
Deklaration der Klasse
mit Typparameter T
DoublyLinkedList
generische Klasse
T
Folie-848
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Deklaration der Referenz
mit Typargument
Aufruf des Konstruktors
mit Typargument
Student
DoublyLinkedList
Student
parametrisierte Klasse
DoublyLinkedList
Beispiel für eine generische Klasse: DoublyLinkedList
Beispiel für die Parametrisierung:
public class DoublyLinkedList
Deklaration der Klasse
mit Typparameter T
DoublyLinkedList
generische Klasse
T
Student
Folie-849
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Student
DoublyLinkedList
Student
parametrisierte Klasse
Typargument: Student
DoublyLinkedList
Beispiel für eine generische Klasse: DoublyLinkedList
Beispiel für die Parametrisierung:
public class DoublyLinkedList
DoublyLinkedList
generische Klasse
T
Student
Folie-850
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel für eine generische Klasse: DoublyLinkedList
Beispiel für die Parametrisierung:
public class DoublyLinkedList
Das Erzeugen einer parametrisierten Klasse aus einer generischen Klasse erfolgt durch die
Übergabe von Typargumenten.
Die Übergabe von Typargumenten erfolgt ebenfalls in <...>.
DoublyLinkedList
generische Klasse
T
DoublyLinkedList
Typargument Typargument
Folie-851
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel für eine generische Klasse: DoublyLinkedList
Beispiel für die Parametrisierung:
DoublyLinkedList
DoublyLinkedList
parametrisierte Klasse ab, bei der der Typparameter T durch die als Typargument übergebene
Klasse Student ersetzt wird.
students ist also eine Referenz, die auf Objekte der parametrisierten Klasse verweisen kann.
DoublyLinkedList
DoublyLinkedList
Klasse Student ersetzt wird, so dass das erzeugte Listen-Objekt ausschließlich mit Inhalten der
Klasse Student umgehen kann.
Die Liste students ist dadurch typsicher:
– Es können nur Student-Objekte als Inhalte eingefügt werden.
– Es kann sicher davon ausgegangen werden, dass Student-Objekte zurückgegeben werden.
Deklaration der Referenz
mit Typargument mit Typargument
Aufruf des Konstruktors
Folie-852
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel für eine generische Klasse: DoublyLinkedList
public class DoublyLinkedList
{
private Element first, last;
private int size;
… // Methoden der Liste
private class Element
{
private T content;
private Element pred, succ;
… // Methoden des Elements
}
}
T ist Platzhalter für einen, immer gleichen konkreten Typ.
Typparameter T
Deklaration einer
generischen Klasse
Folie-853
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel für eine generische Klasse: DoublyLinkedList
public class DoublyLinkedList
{
private Element first, last;
private int size;
… // Methoden der Liste
private class Element
{
private T content;
private Element pred, succ;
… // Methoden des Elements
}
}
T ist Platzhalter für einen, immer gleichen konkreten Typ.
Element ist eine innere (Instanz-)Klasse, der Parameter T ist dort sichtbar.
Typparameter T
Nutzung von T
Folie-854
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel für eine generische Klasse: DoublyLinkedList
Methoden der Klasse Element:
public Element( T c )
{
content = c;
pred = succ = null;
}
public T getContent()
{
return content;
}
public void setContent( T c )
{
content = c;
}
Nutzung des Typparameters T in der inneren Klasse Element:
T kann im Programmtext die Angabe einer konkreten Klasse ersetzen.
Parameter des Typs T
Folie-855
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel für eine generische Klasse: DoublyLinkedList
Methoden der Klasse Element:
public Element( T c )
{
content = c;
pred = succ = null;
}
public T getContent()
{
return content;
}
public void setContent( T c )
{
content = c;
}
Nutzung des Typparameters T in der inneren Klasse Element:
T kann im Programmtext die Angabe einer konkreten Klasse ersetzen.
Rückgabe des Typs T
Folie-856
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel für eine generische Klasse: DoublyLinkedList
Methoden der Klasse DoublyLinkedList:
public void add( T content )
{
Element e = new Element( content );
if ( isEmpty() )
{
first = last = e;
} else {
last.connectAsSucc( e );
last = e;
}
size++;
}
public T getFirst()
{
if ( !isEmpty() )
{
return first.getContent();
} else {
throw new IllegalStateException();
}
}
Parameter des Typs T
T ist Rückgabetyp
getContent()
liefert Ergebnis vom Typ T
Folie-857
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel für eine generische Klasse: DoublyLinkedList
Methoden der Klasse DoublyLinkedList:
public class DoublyLinkedList
{
private Element first, last;
private int size;
public DoublyLinkedList()
{
first = last = null;
size = 0;
}
…
}
Der Aufruf des Konstruktors erfolgt aber mit der Angabe eines Typarguments:
Es wird ein Objekt erzeugt, bei dem T durch den als Argument übergebenen Typ ersetzt wird.
… = new DoublyLinkedList
Deklaration des Konstruktor
ohne Typparameter
Folie-858
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel für eine generische Klasse: DoublyLinkedList
Anmerkungen zu Methoden der Klasse Element:
Eine Deklaration der Form public void setContent( Object c )
erlaubt zur Laufzeit die Übergabe eines beliebigen Objekts als Argument.
Eine Deklaration der Form public void setContent( T c )
erlaubt zur Laufzeit nur die Übergabe eines Objekts eines bestimmten Typs als Argument.
Dieser Typ wird während der Übersetzung durch die Übergabe eines Typarguments an T
festgelegt und vom Compiler überprüft.
Eine Deklaration der Form public Object getContent()
erlaubt zur Laufzeit die Übergabe eines beliebigen Objekts als Rückgabewert.
Eine Deklaration der Form public T getContent()
erlaubt zur Laufzeit nur die Rückgabe eines Objekts eines bestimmten Typs.
Dieser Typ wird während der Übersetzung durch die Übergabe eines Typarguments an T
festgelegt und vom Compiler überprüft.
Folie-859
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Typparameter X
Typ der Rückgabe ist beschränkt
auf das an X übergebene Argument
Beispiel für eine generische Klasse: DoublyLinkedList
Die Deklaration der generischen Klasse Iterator
außerhalb der Klasse DoublyLinkedList
da Iteratoren ein Konzept sind, das nicht auf Listen beschränkt ist.
public abstract class Iterator
{
public abstract boolean hasNext();
public abstract X next();
}
Die Deklaration von next() wird angepasst, da die Rückgabe vom Typ der Elemente abhängt,
über die iteriert wird.
Die Deklaration von hasNext() ist nicht betroffen, da die Rückgabe nicht vom Typ der
Elemente abhängt, über die iteriert wird.
Folie-860
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel für eine generische Klasse: DoublyLinkedList
Die generische Fassung der Methode Iterator
public Iterator
{
return new ForwardIterator();
}
private abstract class ListIterator extends Iterator
{
Element current;
public T next() {
if ( hasNext() ) {
T content = current.getContent();
current = step();
return content;
} else {
throw new IllegalStateException();
}
}
…
}
ListIterator ohne Typparameter,
T ist Typargument
wird als Typargument an X übergeben
Der Typparameter T von DoublyLinkedList
da T in (Instanz-)Klasse sichtbar
für externe Klasse
Folie-861
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel für eine generische Klasse: DoublyLinkedList
Die generische Fassung der Klasse Iterator
private class ForwardIterator extends ListIterator {
public ForwardIterator() {
current = first;
}
Element step() {
return current.getSucc();
}
}
private class ReverseIterator extends ListIterator {
public ReverseIterator() {
current = last;
}
Element step() {
return current.getPred();
}
}
bekannt
first ist in innerer (Instanz-)Klasse
bekannt
last ist in innerer (Instanz-)Klasse
Folie-862
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Erinnerung: Grundlegende Idee generischer Klassen
bisher: jetzt:
generische Klasse
Klasse parametrisierte Klasse
Objekt Objekt
Spezialisierung ist möglich in den Formen
generische Klasse erbt von generischer Klasse:
class DoublyLinkedList
class SpecialList
Klasse erbt von parametrisierter Klasse:
class IntegerList extends DoublyLinkedList
Typargumente
Folie-863
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel für eine generische Klasse: DoublyLinkedList
Parametrisierung und Aufruf:
DoublyLinkedList
doubles.add( 14.1 ); doubles.add( 7.4 ); doubles.add( 2.3 ); doubles.add( 5.0 );
Iterator
double sum = 0.0;
while ( it.hasNext() )
{
sum += it.next();
}
System.out.println( “sum: ” + sum );
Die Liste doubles ist jetzt typsicher:
– Es können nur Double-Objekte als Inhalte eingefügt werden.
– Es kann sicher davon ausgegangen werden, dass Double-Objekte zurückgegeben werden.
Deklaration mit Wrapper-Klasse
passende Deklaration:
kein Type Cast nötig:
als Typargument
Konstruktor mit
Typargument
Iterator liefert hier Double-Werte
next() liefert hier Double
Folie-864
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Generische Klassen – Anmerkungen
Nicht möglich ist:
DoublyLinkedList
doubles.add( 14 );
DoublyLinkedList
Klasse Double sind.
14 kann zwar durch Boxing in ein Integer-Objekt überführt werden, aber Integer ist nicht
kompatibel zu Double.
Möglich wäre:
DoublyLinkedList
doubles.add( 14 ); doubles.add( 7.4 );
Number ist die Oberklasse von Double und Integer.
Aber ein Iterator würde jetzt für Number deklariert werden müssen:
Iterator
Folie-865
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Generische Klassen – Anmerkungen (Fortsetzung)
Generische Klassen sind erst in einer späteren Java-Version eingeführt worden.
Bis dahin konnten nur Klassen mit Referenzen auf Object allgemein genutzt werden.
Um bei der Einführung von generischen Klassen keine neue Ausführungsumgebung
(Java Virtual Machine) einführen zu müssen und Kompatibilität zu vorhandenen
JVM-Implementierungen zu bewahren, wurde folgende Umsetzung durch den Compiler
festgelegt:
– Es erfolgt keine spezifische Implementierung für das Typargument,
es wird immer eine allgemeine Implementierung mit
Referenzen auf Object benutzt.
– Der Compiler ergänzt nur passende Type Cast-Operatoren.
– Die geforderte Typsicherheit wird bereits durch die semantischen
Überprüfungen des Compilers sichergestellt.
Konsequenz:
Innerhalb des Quellcodes der generischen Klasse ist T ein Platzhalter,
zur Laufzeit ist aber das Typargument in der Klasse nicht bekannt.
Es können beispielsweise keine Objekte oder Felder von T angelegt werden.
Folie-866
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Generische Klassen – Anmerkungen (Fortsetzung)
Generische Klassen sind erst in einer späteren Java-Version eingeführt worden.
Bis dahin konnten nur Klassen mit Referenzen auf Object allgemein genutzt werden.
Um für bestehende Klassen eine Überführung in eine generische Version zu ermöglichen
und gleichzeitig den Aufruf der generischen Versionen in vorhandenem Programmtext zu
ermöglichen, wurde die folgende Sprachsyntax zusätzlich aufgenommen:
public class DoublyLinkedList
Eine Deklaration einer Referenz oder der Aufruf eines Konstruktors sind auch
ohne Typparameter möglich:
DoublyLinkedList doubles = new DoublyLinkedList();
Es wird dann auf die Generierung von Type Cast-Operatoren verzichtet.
Dieser Typ wird als Raw Type der generischen Klasse bezeichnet.
Da der Raw Type der internen Darstellung entspricht, ist er kompatibel zu allen durch
Parametrisierung festgelegten Typen. Die Benutzung führt in der Regel zu Warnungen,
da typunsichere Zuweisungen erfolgen müssen.
Die Benutzung eines Raw Type sollte immer vermieden werden.
Folie-867
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Generische Klassen – Anmerkungen (Fortsetzung)
Die Klasse Number ist die Oberklasse der Klasse Integer.
DoublyLinkedList
die Oberklasse von DoublyLinkedList
Beide Klassen sind vielmehr parametrisierte Versionen der gleichen generischen Klasse.
Überlegung (Nachweis einer sinnvollen Regel durch Widerspruch)
Falls DoublyLinkedList
würde folgender Programmtext erlaubt sein:
DoublyLinkedList
x = new DoublyLinkedList
x.add( 3.8 );
Der double-Wert 3.8 wäre zwar kompatibel zu der mit Number parametrisierten Deklaration
der Methode add, nicht aber zu dem mit Integer parametrisierten Listen-Objekt.
Fehlermeldung
Folie-868
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Generische Klassen – Anmerkungen (Fortsetzung)
Verkürzende Schreibweise:
<>-Operator (diamond operator) bestimmt – soweit möglich – den benötigten Typ beim
Aufruf eines Konstruktors aus der Deklaration der
Referenz, zu der eine Zuweisung erfolgt.
Beispiel:
DoublyLinkedList
leitet den Typ Double ab und ergänzt ihn implizit
Folie-869
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel für eine generische Klasse: DoublyLinkedList
Generische statische öffentliche innere Klasse SubstitutionStrategy
für den Einsatz des Strategiemusters für die Klasse DoublyLinkedList
Die Methode substituteAll arbeitet mit einem Objekt von SubstitutionStrategy.
Daher gehört die Klasse SubstitutionStrategy zu der Klasse DoublyLinkedList
Unterklassen zu SubstitutionStrategy sollen unabhängig von einer bestimmten Liste
deklariert werden können. Daher wird SubstitutionStrategy als statische Klasse deklariert.
Um Typsicherheit zu gewährleisten, muss SubstitutionStrategy als generische Klasse
deklariert werden.
public static abstract class SubstitutionStrategy
{
public abstract E substitute( E ref );
}
public void substituteAll( SubstitutionStrategy
{
Element current = first;
while ( current != null ) {
current.setContent( s.substitute( current.getContent() ) );
current = current.getSucc();
}
}
Folie-870
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel für eine generische Klasse: DoublyLinkedList
Generische statische öffentliche innere Klasse SubstitutionStrategy
für den Einsatz des Strategiemusters für die Klasse DoublyLinkedList
Die Methode substituteAll arbeitet mit einem Objekt von SubstitutionStrategy.
Daher gehört die Klasse SubstitutionStrategy zu der Klasse DoublyLinkedList
Unterklassen zu SubstitutionStrategy sollen unabhängig von einer bestimmten Liste
deklariert werden können. Daher wird SubstitutionStrategy als statische Klasse deklariert.
Um Typsicherheit zu gewährleisten, muss SubstitutionStrategy dann aber
als generische Klasse deklariert werden.
public static abstract class SubstitutionStrategy
{
public abstract E substitute( E ref );
}
public void substituteAll( SubstitutionStrategy
{
Element current = first;
while ( current != null ) {
current.setContent( s.substitute( current.getContent() ) );
current = current.getSucc();
}
}
Typparameter E
Folie-871
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel für eine generische Klasse: DoublyLinkedList
Generische statische öffentliche innere Klasse SubstitutionStrategy
für den Einsatz des Strategiemusters für die Klasse DoublyLinkedList
Die Methode substituteAll arbeitet mit einem Objekt von SubstitutionStrategy.
Daher gehört die Klasse SubstitutionStrategy zu der Klasse DoublyLinkedList
Unterklassen zu SubstitutionStrategy sollen unabhängig von einer bestimmten Liste
deklariert werden können. Daher wird SubstitutionStrategy als statische Klasse deklariert.
Um Typsicherheit zu gewährleisten, muss SubstitutionStrategy dann aber
als generische Klasse deklariert werden.
public static abstract class SubstitutionStrategy
{
public abstract E substitute( E ref );
}
public void substituteAll( SubstitutionStrategy
{
Element current = first;
while ( current != null ) {
current.setContent( s.substitute( current.getContent() ) );
current = current.getSucc();
}
}
Typargument T garantiert
Kompatibilität zum
ausführenden Objekt
Folie-872
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Typargumente müssen
kompatibel sein
Beispiel für eine generische Klasse: DoublyLinkedList
Generische statische öffentliche innere Klasse SubstitutionStrategy
für den Einsatz des Strategiemusters für die Klasse DoublyLinkedList
Deklaration einer Strategie:
public class DoubleIntegersStrategy
extends DoublyLinkedList.SubstitutionStrategy
{
public Integer substitute( Integer ref ) {
return 2 * ref;
}
}
Benutzung dieser Strategie:
DoublyLinkedList
…
DoubleIntegersStrategy manip = new DoubleIntegersStrategy();
ints.substituteAll( manip );
Folie-873
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Generische Klassen
(siehe Folie 841)
Nach Durcharbeiten des Kapitels Generische Klassen sollen
die teilnehmenden Studierenden
die Vorteile generischer Klassen kennen und erklären können,
generische Klassen nutzen können,
generische Klassen erstellen können.
Folie-874
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen, Algorithmen
und Programmierung 1 (DAP 1)
Fakultät für Informatik
Wintersemester 2019/20
Stefan Dissmann
Generische Gestaltung der Datenstruktur Binärer Suchbaum
Folie-875
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels
Generische Gestaltung der Datenstruktur Binärer Suchbaum
Nach Durcharbeiten des Kapitels Generische Gestaltung der Datenstruktur Binärer Suchbaum
sollen die teilnehmenden Studierenden
die Vorteile generischer Klassen an einem weiteren Beispiel kennen,
Möglichkeiten zur Einschränkung von Typparametern kennen,
das Zusammenwirken verschiedener generischer Klassen kennen,
das Prinzip der Delegation zur Wiederverwendung vorhandener Klassen kennen.
Folie-876
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rückblick: Binärer Suchbaum
(siehe Folie 546)
Ein binärer Suchbaum
ist ein binärer Baum, für den gilt, dass
die Information in der Wurzel größer ist als die Information in ihrem linken Kind und
die Information in der Wurzel kleiner ist als die Information in ihrem rechten Kind und
der linke Teilbaum auch ein binärer Suchbaum ist und
der rechte Teilbaum auch ein binärer Suchbaum ist.
Der leere Baum ist auch ein binärer Suchbaum.
Folie-877
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rückblick: Binärer Suchbaum (Fortsetzung)
(siehe Folie 556)
Suchvorgang:
In jedem Knoten wird überprüft,
ob das zu suchende Zeichen
kleiner: dann weiter nach links – oder
größer: dann weiter nach rechts – oder
gleich: gefunden!
ist.
token: ’l’
quantity: 2
token: ’h’
quantity: 1
root
token: ’a’
quantity: 1
token: ’e’
quantity: 2
token: ’o’
quantity: 1
token: ’w’
quantity: 1
token: ’n’
quantity: 1
Folie-878
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rückblick: Nutzung von Vererbung
(siehe Folie 704)
neuer Lösungsansatz:
nur eine Sorte von Knoten, die flexibel zur Datenhaltung benutzt werden können
public class BinarySearchTree
{
private X content;
private BinarySearchTree leftChild, rightChild;
…
Die Klasse X muss eine
Ordnungsrelation garantieren
BinarySearchTree
Student Fraction
X
HuffmanTriple
Folie-879
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Generische Klasse BinarySearchTree
public class BinarySearchTree
{
private T content;
private BinarySearchTree
public BinarySearchTree()
{
content = null;
leftChild = null;
rightChild = null;
}
… // Methoden des Suchbaums
}
Der Typparameter T ist Platzhalter für einen, immer gleichen konkreten Typ.
aber:
– Die Werte eines als Typargument übergebenen Typs müssen eine Ordnungsrelation besitzen.
– Die Ordnung muss innerhalb der Klasse BinarySearchTree bestimmt werden können:
Ein als Typargument übergebener Typ muss geeignete Methoden besitzen.
Typparameter T
Deklaration der
generischen Klasse
Folie-880
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Generische Klasse Comparable
public abstract class Comparable
{
public abstract int compareTo( T t );
}
Die Klasse Comparable ist abstrakt und gibt die Implementierung genau einer Methode vor.
Die Klasse Comparable ist generisch und besitzt einen Typparameter, der den Typ des
Parameters der Methode compareTo bestimmt.
Die Methode compareTo gibt einen int-Wert zurück, der für x und y eines Typs T
folgendermaßen bestimmt werden soll:
– falls x größer als y ist, dann soll gelten: x.compareTo( y ) > 0
– falls y größer als x ist, dann soll gelten: x.compareTo( y ) < 0
– falls x gleich y ist, dann soll gelten: x.compareTo( y ) = 0
Anmerkungen
– Es muss immer gelten: x.compareTo( y ) == -(y.compareTo( x ))
– Es sollte immer gelten:
x.compareTo( y ) == 0 x.equals( y )
Typparameter T
Folie-881
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Generische Klasse Comparable
public abstract class Comparable
{
public abstract int compareTo( T t );
}
Jede Unterklasse der Klasse Comparable ermöglicht es, zwei beliebige Objekte eines Typs T
miteinander zu vergleichen.
Die Objekte von Unterklassen der Klasse Comparable sind also geeignete Inhalte für binäre
Suchbäume, da die geforderte Ordnung hergestellt werden kann.
Die Deklaration der Klasse BinarySearchTree
dass als Typargumente für T nur Unterklassen der Klasse Comparable verwendet werden
dürfen.
Folie-882
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Generische Klasse BinarySearchTree
public class BinarySearchTree
{
private T content;
private BinarySearchTree
public BinarySearchTree()
{
content = null;
leftChild = null;
rightChild = null;
}
… // Methoden des Suchbaums
}
Als Argument für den Typparameter T ist nun nur noch ein solcher Typ zulässig,
der die Klasse Comparable
Da der Typparameter T immer den gleichen Typ bezeichnet, stellt die Einschränkung zugleich
sicher, dass die compareTo-Methode ein Argument des Typs T erwartet.
Typparameter T
wird eingeschränkt
Folie-883
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Generische Klasse BinarySearchTree
public T getContent()
{
return content;
}
public boolean isEmpty()
{
return content == null;
}
public boolean isLeaf()
{
return !isEmpty() && leftChild.isEmpty() && rightChild.isEmpty();
}
public int size()
{
if ( isEmpty() )
{
return 0;
} else {
return 1 + leftChild.size() + rightChild.size();
}
}
Methoden in
der Klasse BinarySearchTree
Folie-884
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Generische Klasse BinarySearchTree
public boolean contains( T t )
{
if ( isEmpty() )
{
return false;
}
else
{
if ( content.compareTo( t ) > 0 )
{
return leftChild.contains( t );
}
else if ( content.compareTo( t ) < 0 )
{
return rightChild.contains( t );
}
return true;
}
}
weitere Methode in
der Klasse BinarySearchTree
content ist Referenz auf T,
T muss Comparable
spezialisieren, besitzt also
eine Methode compareTo
Folie-885
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Generische Klasse BinarySearchTree
public void add( T t )
{
if ( isEmpty() )
{
content = t;
leftChild = new BinarySearchTree
rightChild = new BinarySearchTree
}
else
{
if ( content.compareTo( t ) > 0 )
{
leftChild.add( t );
}
else if ( content.compareTo( t ) < 0 )
{
rightChild.add( t );
}
}
}
Der hier deklarierte Suchbaum für allgemeine Inhalte weist keine spezifische Funktionalität
auf, wie es bei der Klasse CharacterSearchTree der Fall war: quantity++
weitere Methode in
der Klasse BinarySearchTree
Folie-886
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Generische Klasse BinarySearchTree
private void toList( DoublyLinkedList
{
if ( !isEmpty() )
{
leftChild.toList( list );
list.add( content );
rightChild.toList( list );
}
}
Die Methode toList besitzt einen Parameter der generischen Klasse DoublyLinkedList.
Durch Übergabe von T als Typargument werden nur Listen-Objekte als Argumente von
toList akzeptiert, bei denen der Typ ihrer Inhalte zum Typ der im Baum abgelegten Inhalte
passt.
Die Methode toList durchläuft den Baum in InOrder-Reihenfolge.
Die Methode toList wird jetzt genutzt, um einen einfachen Iterator über den Baum
bereitzustellen.
Erinnerung: Ein Iterator ist ein Objekt, das mit den beiden Methoden hasNext und next
einen einmaligen Durchlauf durch eine Datenstruktur ermöglicht.
weitere Methode in
der Klasse BinarySearchTree
Folie-887
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rückblick: Generische Klasse Iterator
(siehe Folie 859)
public abstract class Iterator
{
public abstract boolean hasNext();
public abstract T next();
}
Die Klasse Iterator besitzt jetzt einen Typparameter T.
Ein Iterator, der die Klasse Iterator spezialisiert, liefert also durch seinen next-Methode
immer zu T kompatible Objekte.
Folie-888
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Generische Klasse BinarySearchTree
public Iterator
{
DoublyLinkedList
toList( list );
return list.iterator();
}
Die Methode iterator() liefert einen zum Inhaltstyp T passenden Iterator.
new DoublyLinkedList
Typs T verwalten kann.
Der Aufruf toList( list ) trägt alle Inhalte des Baums in die Liste list ein.
Da toList einen InOrder-Durchlauf verwendet, sind die Inhalte der Liste aufsteigend sortiert.
Die Referenz list verweist auf ein DoublyLinkedList-Objekt.
Jedes DoublyLinkedList-Objekt kann Iterator-Objekte bereitstellen.
return list.iterator() stellt das von dem Listen-Objekt list bereitgestellte Iterator-
Objekt als Iterator für den Baum zur Verfügung, da ja alle Inhalte des Baums auch über die Liste
erreicht werden können.
weitere Methode
in der Klasse
BinarySearchTree
Folie-889
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Generische Klasse BinarySearchTree
Visualisierung der Klassenstruktur
DoublyLinkedList
T
BinarySearchTree
T
Comparable
T
Iterator
T
«abstract»
«abstract»
Folie-890
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
binärer Baum Liste Iterator
Iterator für BinarySearchTree
Implementierte Lösung:
Es wird eine Liste erstellt, die die Inhalte aller Knoten des Baums enthält:
Das ist mit einem InOrder-Durchlauf einfach zu implementieren.
Der Iterator nutzt dann diese Liste für seinen Durchlauf:
Der ist schon implementiert in der Klasse ForwardIterator der Liste.
Die Methode iterator() gibt also einfach den (passenden) Iterator der Liste zurück.
Folie-891
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
binärer Baum Liste Iterator
Iterator für BinarySearchTree (Fortsetzung)
Implementierte Lösung:
Es wird eine Liste erstellt, die die Inhalte aller Knoten des Baums enthält:
Das ist mit einem InOrder-Durchlauf einfach zu implementieren.
Der Iterator nutzt dann diese Liste für seinen Durchlauf:
Der ist schon implementiert in der Klasse ForwardIterator der Liste.
Die Methode iterator() gibt also einfach den (passenden) Iterator der Liste zurück.
Eine solche Vorgehensweise ist typisch für objektorientierte Software:
Eine Klasse (bzw. jedes Objekt dieser Klasse) lässt eine seiner Aufgaben von
einem Objekt einer anderen Klasse erledigen.
Diese Art des einfachen Übertragens einer Aufgabe wird als Delegation bezeichnet.
Folie-892
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Iterator für BinarySearchTree (Fortsetzung)
Der durch Delegation bereitgestellte Iterator ist ein einfacher Lösungsansatz,
dessen Konzeption und Realisierung ohne viel Aufwand vorgenommen werden konnten.
Die Benutzung des Iterators ist identisch zu der von Iteratoren auf der Liste
– es wird ja letztlich der gleiche Iterator benutzt.
Nachteile:
Da die Inhalte des Baums in eine Liste ausgelagert werden, über die iteriert wird, arbeitet diese
Lösung beim Ändern des Baums (Löschen/Hinzufügen von Inhalten) fehlerfrei
– allerdings auf der Basis möglicherweise veralteter Inhalte.
Der Aufwand während der Ausführung ist groß:
– Zunächst muss immer ein vollständiger Durchlauf durch den Baum erfolgen –
auch dann, wenn später gar nicht über alle Inhalte iteriert wird.
– Bei großen Bäumen besitzt die aufgebaute Liste selbst einen entsprechend großen,
eigenen Speicherbedarf.
Folie-893
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Iterator für BinarySearchTree (Fortsetzung)
Implementierung eines Iterators ohne die beiden Nachteile:
Voraussetzungen:
– Ein Iterieren über einen binären Baum erfolgt immer durch ein Hinab- und Hinaufsteigen
durch die Äste des Baums.
– Dabei kann aber durch die nur in eine Richtung vorgenommene Referenzierung nicht einfach
nach oben navigiert werden.
Lösungsansatz:
– Für die Fortsetzung eines bereits begonnenen Durchlaufs durch den Baum werden nur die
Knoten benötigt, die auf dem Ast zwischen der Wurzel und dem aktuell betrachteten Knoten
liegen.
– Der Iterator muss also eine geeignete Datenstruktur besitzen, in der er vorübergehend die
Vorgänger des aktuell betrachteten Knotens aufbewahrt.
Diese Lösung wird in der privaten Klasse StackBasedIterator umgesetzt.
Folie-894
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Iterator für BinarySearchTree (Fortsetzung)
Klasse StackBasedIterator
Algorithmus:
Es werden immer für den aktuell vom Iterator angebotenen Knoten alle noch nicht bearbeiteten
Knoten abgespeichert, die auf dem Pfad liegen, der von dem aktuellen Knoten zur Wurzel führt.
Wird ein Knoten durch den Iterator abgearbeitet, so wird sein InOrder-Nachfolger als
nächster Knoten ausgewählt. Das ist der äußerste linke Knoten in seinem rechten Teilbaum.
Gibt es keinen rechten Teilbaum, also keinen rechten Nachfolger, wird mit dem noch nicht
bearbeiteten Vorgänger des abgearbeiteten Knotens fortgefahren.
Folie-895
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Iterator für BinarySearchTree (Fortsetzung)
Klasse StackBasedIterator
erster zu bearbeitender Knoten
des InOrder-Durchlaufs
noch nicht
bearbeitete Knoten
Folie-896
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Iterator für BinarySearchTree (Fortsetzung)
Klasse StackBasedIterator
zweiter zu bearbeitender Knoten
des InOrder-Durchlaufs
noch nicht
bearbeitete Knoten
Folie-897
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Iterator für BinarySearchTree (Fortsetzung)
Klasse StackBasedIterator
dritter zu bearbeitender Knoten
des InOrder-Durchlaufs
noch nicht
bearbeitete Knoten
Folie-898
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Iterator für BinarySearchTree (Fortsetzung)
Klasse StackBasedIterator
vierter zu bearbeitender Knoten
des InOrder-Durchlaufs
noch nicht
bearbeitete Knoten
Folie-899
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Iterator für BinarySearchTree (Fortsetzung)
Klasse StackBasedTreeIterator
Algorithmus:
Es werden immer für den aktuell vom Iterator angebotenen Knoten alle noch nicht bearbeiteten
Knoten abgespeichert, die auf dem Pfad liegen, der von dem aktuellen Knoten zur Wurzel führt.
Wird ein Knoten durch den Iterator abgearbeitet, so wird sein InOrder-Nachfolger als
nächster Knoten ausgewählt. Das ist der äußerste linke Knoten in seinem rechten Teilbaum.
Gibt es keinen rechten Teilbaum, also keinen rechten Nachfolger, wird mit dem noch nicht
bearbeiteten Vorgänger des abgearbeiteten Knotens fortgefahren.
Für die Implementierung dieses Algorithmus wird eine Datenstruktur benötigt, die es erlaubt,
den zuletzt abgelegten Vorgänger als ersten weiterzubearbeiten.
Eine solche Datenstruktur wird auch Stapel (Stack) oder Kellerspeicher genannt.
Das Verhalten tritt beispielsweise bei einem Stapel von Büchern auf:
Das zuletzt aufgelegte Buch wird als erstes wieder entfernt.
Eine Klasse Stack lässt sich leicht durch die geeignete Nutzung der Klasse DoublyLinkedList
implementieren. Jedes Objekt der Klasse Stack delegiert dabei die Speicherung von Objekten
an ein Objekt der Klasse DoublyLinkedList.
Folie-900
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Stapel
Die Datenstruktur Stapel benötigt nur wenige Operationen:
Ein Hinzunehmen von Inhalten auf den Stapel:
Methode push
Ein Entfernen von Inhalten vom Stapel:
Methode pop
Ein Inspizieren des obersten Inhalts des Stapels:
Methode peek
Ein Prüfen auf Elemente im Stapel:
Methode isEmpty
Folie-901
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
+
+
push
push
pop
pop
Stapel (Fortsetzung)
Folie-902
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Stapel (Fortsetzung)
Darstellung als Liste
push
push
pop
pop
Folie-903
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Stapel (Fortsetzung)
public class Stack
{
private DoublyLinkedList
public Stack() {
elements = new DoublyLinkedList
}
public void push( T o ) {
elements.addFirst( o );
}
public T pop() {
return elements.removeFirst();
}
public T peek() {
return elements.getFirst();
}
public boolean isEmpty() {
return elements.isEmpty();
}
}
Liste als Attribut
Liste wird erzeugt
push = vorne einfügen
pop = vorne entnehmen
Vorhandensein von Inhalt
peek = vorne inspizieren
Folie-904
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Stapel (Fortsetzung)
Warum ist die Klasse Stack keine Spezialisierung der Klasse DoublyLinkedList?
Bei der Spezialisierung werden alle Methoden der Oberklasse in die Unterklasse übernommen.
Bei der Spezialisierung ist ein Verzichten auf Methoden nicht möglich.
Daher würde bei einer Spezialisierung die Klasse Stack auch Methoden wie get (siehe
Folie 741) besitzen, die zur Verwaltung eines Stapels unerwünscht sind.
Die Klasse Stack soll aufgrund ihrer andersartigen Verwaltung der gespeicherten Objekte
auch gar nicht kompatibel zur Klasse DoublyLinkedList sein.
Benutzung und Delegation sind also ein Weg, um
– eine bereits vorhandene Klasse effizient zu nutzen,
– Methoden der vorhandenen Klasse zu verbergen,
– keine zwangsläufige Klassenhierarchie erstellen zu müssen.
Soll eine vorhandene Implementierung wiederverwendet werden,
ohne dass zugleich eine Hierarchie von Typen entsteht,
ist Delegation häufig eine bessere Lösung als Spezialisierung (Vererbung).
Folie-905
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Iterator für BinarySearchTree (Fortsetzung)
Klasse StackBasedIterator
Implementierung der Klasse StackBasedIterator:
Konstruktor:
– legt einen leeren Stack an
– sucht den äußersten linken Knoten des Baums – hier startet die Iteration –
und legt alle auf dem Weg besuchten Knoten auf den Stack
Methode next:
– gibt den obersten Knoten vom Stack zurück
– sucht den äußersten linken Knoten des rechten Teilbaums – hier geht die Iteration weiter –
und legt alle auf dem Weg besuchten Knoten auf den Stack
Methode hasNext:
– überprüft, ob noch ein Knoten auf dem Stack liegt
Methode descendLeftAndPush:
– sucht den äußersten linken Knoten des (Teil-)Baums
und legt alle auf dem Weg besuchten Knoten auf den Stack
Folie-906
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Iterator für BinarySearchTree (Fortsetzung)
Klasse StackBasedIterator
private class StackBasedIterator extends Iterator
{
private Stack
public StackBasedIterator()
{
nodes = new Stack
descendLeftAndPush( BinarySearchTree.this );
}
…
StackBasedIterator ist Iterator über dem Typ T.
der Typparameter T ist in der inneren Klasse sichtbar.
Auf dem Stapel sollen die Knoten eines binären Suchbaums abgelegt werden.
Daher muss als Typargument BinarySearchTree
Typargument
Folie-907
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Iterator für BinarySearchTree (Fortsetzung)
Klasse StackBasedIterator
private class StackBasedIterator extends Iterator
{
private Stack
public StackBasedIterator()
{
nodes = new Stack
descendLeftAndPush( BinarySearchTree.this );
}
…
Das Argument für den ersten Aufruf der Methode descendLeftAndPush muss der ausführende
Knoten der Klasse BinarySearchTree sein.
Innerhalb der inneren Klasse StackBasedIterator bezeichnet this das den Zugriff
umgebende Objekt der Klasse StackBasedIterator.
Die Konstruktion Klassenname.this ermöglicht den Zugriff von einem Objekt einer inneren
Klasse aus zu dem zugehörigen Objekt der umgebenden Klasse.
Zugriff auf
umgebendes Objekt
Folie-908
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Iterator für BinarySearchTree (Fortsetzung)
Klasse StackBasedIterator
…
private void descendLeftAndPush( BinarySearchTree
{
BinarySearchTree
while ( !current.isEmpty() )
{
nodes.push( current );
current = current.leftChild;
}
}
…
Die Methode descendLeftAndPush betrachtet alle Knoten, die auf dem äußersten linken Pfad
liegen und legt diese auf dem Stack nodes ab.
Dadurch können sie leicht in umgekehrter Reihenfolge zur Bearbeitung abgerufen werden.
Ablegen auf Stack
Abbruch bei
leerem Baum
Folie-909
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Iterator für BinarySearchTree (Fortsetzung)
Klasse StackBasedIterator
…
public T next()
{
if ( hasNext() ) {
T content = nodes.peek().getContent();
descendLeftAndPush( nodes.pop().rightChild );
return content;
} else {
throw new IllegalStateException();
}
}
…
und Inhalt sichern
äußerst linken Knoten
im rechten Teilbaum
Knoten vom Stack wählen
suchen
Aufruf von next nicht
zulässig, da alle Inhalte
geliefert wurden
Folie-910
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Iterator für BinarySearchTree (Fortsetzung)
Klasse StackBasedIterator
…
public boolean hasNext()
{
return !nodes.isEmpty();
}
}
Mit der Klasse StackBasedIterator steht ein Iterator zur Verfügung, der mit geringem zusätz-
lichen Speicherbedarf einen über next-Aufrufe gesteuerten InOrder-Durchlauf ermöglicht.
Dieser Iterator liefert auch solche Inhalte, die während des Interierens eingefügt werden und
einen größeren Inhalt als der aktuelle Knoten besitzen – also im InOrder-Durchlauf später
angezeigt werden.
Dieser Iterator berücksichtigt jedoch nicht das Löschen von Knoten aus dem Baum.
Der Iterator arbeitet analog zum Umgang
des Java-Laufzeitsystems mit Methoden-Aufrufen:
dort werden die lokalen Variablen der unterbrochenen Instanzen der
Methoden auf einem Stack abgelegt
solange Knoten auf dem Stack liegen,
kann weiter iteriert werden
Folie-911
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Generische Klasse BinarySearchTree
Visualisierung der Klassenstruktur
DoublyLinkedList
T
BinarySearchTree
T
Comparable
T
StackBasedIterator
E
Iterator
T
Stack
T
«abstract»
«abstract»
Folie-912
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels
Generische Gestaltung der Datenstruktur Binärer Suchbaum
(siehe Folie 875)
Nach Durcharbeiten des Kapitels Generische Gestaltung der Datenstruktur Binärer Suchbaum
sollen die teilnehmenden Studierenden
die Vorteile generischer Klassen an einem weiteren Beispiel kennen,
Möglichkeiten zur Einschränkung von Typparametern kennen,
das Zusammenwirken verschiedener generischer Klassen kennen,
das Prinzip der Delegation zur Wiederverwendung vorhandener Klassen kennen.
Folie-913
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen, Algorithmen
und Programmierung 1 (DAP 1)
Fakultät für Informatik
Wintersemester 2019/20
Stefan Dissmann
Interface
Folie-914
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Interface
Nach Durcharbeiten des Kapitels Interface sollen die teilnehmenden Studierenden
das Konstrukt des Interfaces kennen,
Interfaces und Hierarchien von Interfaces konzipieren und programmieren können,
Interfaces durch Klassen implementieren können,
Interfaces und (abstrakte) Klasse gegeneinander abgrenzen können,
generische Methoden deklarieren und einsetzen können.
Folie-915
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Typkompatibilität und Klassenhierarchie
Problem:
In Java kann jede Klasse nur genau eine Oberklasse besitzen.
Soll eine Klassenhierarchie eine Klasse enthalten,
die zu mehreren Klassen kompatibel sein soll,
so müssen diese selbst wiederum in einer Spezialisierungsbeziehung stehen.
Iterator
?
Comparable
X
X X
oder
Iterator
IteratorComparable
Comparable
Folie-916
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Typkompatibilität und Klassenhierarchie (Fortsetzung)
Diese Lösung ist aber untauglich,
wenn es viele Kombinationen von Typkompatibilitäten gibt oder
wenn die Klassenhierarchie nicht angepasst werden kann, da die Implementierungen
der betroffenen Klassen nicht verfügbar sind.
Iterator
?
Comparable
X
X X
oder
Iterator
IteratorComparable
Comparable
Folie-917
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Spezialisierung in Java
Warum erlaubt Java für jede Klasse nur genau eine Oberklasse?
Es werden so Probleme vermieden,
die mehrfaches Erben (multiple inheritance) mit sich bringen würde:
A CB
private int a; public int a; String a;
Konflikte bei Attributen
mit gleichem Namen:
Zugriffsrechte, Typen
U
a;?
Folie-918
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
U() { }
Spezialisierung in Java (Fortsetzung)
Warum erlaubt Java für jede Klasse nur genau eine Oberklasse?
Es werden so Probleme vermieden,
die mehrfaches Erben (multiple inheritance) mit sich bringen würde:
M1
T
M1(){ a = 5; }
public int a;
Konflikte bei Attributen
aus gleicher Ursprungsklasse:
Anzahl, Initialisierung
M2
M2(){ a = 7; }
U
a ?
?
Folie-919
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Spezialisierung in Java (Fortsetzung)
Warum erlaubt Java für jede Klasse nur genau eine Oberklasse?
Es werden so Probleme vermieden,
die mehrfaches Erben (multiple inheritance) mit sich bringen würde:
A
int m() { }
Konflikte bei Methoden
mit gleicher Signatur:
Verhalten
U
B
int m() { }
C
int m() { }
int m() { }?
Folie-920
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Spezialisierung in Java
Warum erlaubt Java für jede Klasse nur genau eine Oberklasse?
Es werden so Probleme vermieden,
die mehrfaches Erben (multiple inheritance) mit sich bringen würde:
Es könnten Attribute gleichen Namens mit
unterschiedlichen Typen und Zugriffsrechten aus den Oberklassen geerbt werden.
Es könnten Attribute von mehreren Oberklassen geerbt, die einen gemeinsamen Ursprung
in einer gemeinsamen Oberklasse haben.
Alle Oberklassen würden Konstruktoren liefern,
die im Konstruktor der Unterklasse ausgeführt werden müssen.
Es könnten Methoden mit gleichen Signaturen und unterschiedlichen Implementierungen
aus den Oberklassen geerbt werden.
Folie-921
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rückblick: Klassen Iterator, Comparable und SubstitutionStrategy
public abstract class Iterator
public abstract boolean hasNext();
public abstract T next();
}
public abstract class Comparable
public abstract int compareTo( T t );
}
public static abstract class SubstitutionStrategy
public abstract E substitute( E ref );
}
Alle drei Klassen sind abstrakt und enthalten ausschließlich abstrakte Methoden.
Durch die Spezialisierung dieser Klassen sollen Klassenhierarchien geschaffen werden,
in denen für die Unterklassen bestimmte Eigenschaften (in Form von Methoden) garantiert
werden können.
Offensichtlich ist es nützlich für die Gestaltung von vielseitig verwendbaren Klassen,
wenn Klassen wie Iterator, Comparable oder SubstitutionStrategy aber keine weiteren
Vorgaben zur Umsetzung dieser Eigenschaften machen.
Folie-922
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Spezialisierung in Java (Fortsetzung)
Einsatzziele des Spezialisierungskonzepts
Typkompatibilität Wiederverwendung
normale Klasse
(alle Methoden implementiert) X X
abstrakte Klasse
(einige Methoden implementiert) X X
ausschließlich abstrakte Klasse
(keine Methode implementiert) X
Folie-923
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Spezialisierung in Java (Fortsetzung)
Einsatzziele des Spezialisierungskonzepts
Typkompatibilität Wiederverwendung
normale Klasse
(alle Methoden implementiert) X X
abstrakte Klasse
(einige Methoden implementiert) X X
ausschließlich abstrakte Klasse
(keine Methode implementiert) X
Probleme bei
mehrfachem Erben
Folie-924
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Spezialisierung in Java (Fortsetzung)
Einsatzziele des Spezialisierungskonzepts
Typkompatibilität Wiederverwendung
normale Klasse
(alle Methoden implementiert) X X
abstrakte Klasse
(einige Methoden implementiert) X X
ausschließlich abstrakte Klasse
(keine Methode implementiert) X
Java bietet ein anderes Konzept an, um
die Vorteile des mehrfachen Erbens beim Herstellen von Typkompatibilitäten zu ermöglichen
und
die Nachteile des mehrfachen Erbens von konkreten Eigenschaften weitgehend zu vermeiden.
Probleme bei
mehrfachem Erben
Folie-925
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Interface
Java bietet ein anderes Konzept an: Interface
Ein Interface entspricht ungefähr einer Klasse, die keine Attribute enthält. *)
Ein Interface enthält also ausschließlich Methoden.
Methoden müssen einen der Modifizierer abstract, default oder static besitzen.
Der Modifizierer abstract kann bei der Deklaration entfallen.
Deklarationen von Methoden müssen öffentlich sein, so dass jede in einem Interface
deklarierte Methode immer das Zugriffsrecht public besitzen muss.
Der Modifizierer public kann bei der Deklaration entfallen.
Aus Interfaces können eigene Spezialisierungshierarchien gebildet werden.
Ein Interface kann mehrere Interfaces spezialisieren – also «mehrfach erben».
Eine Klasse kann mehrere Interfaces spezialisieren – also «mehrfach erben».
Das Spezialisieren eines Interfaces durch eine Klasse wird als Implementierung bezeichnet.
*) Das stimmt nicht ganz: Ein Interface kann auch Deklarationen von konstanten Attributen enthalten.
Dieser Aspekt wird später kurz betrachtet.
Folie-926
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Interface (Fortsetzung)
Warum erlaubt Java für Interfaces mehrfaches Spezialisieren/Erben?
Die bei Klassen für mehrfaches Erben genannten Probleme
treten im Zusammenhang mit Interfaces weitgehend nicht auf:
Es können Attribute gleichen Namens mit
unterschiedlichen Typen und Zugriffsrechten aus den Oberklassen geerbt werden.
Ein Interface besitzt keine Attribute.
Es können Attribute von mehreren Oberklassen geerbt, die einen gemeinsamen Ursprung
in einer gemeinsamen Oberklasse haben.
Ein Interface besitzt keine Attribute.
Alle Oberklassen liefern Konstruktoren,
die im Konstruktor der Unterklasse ausgeführt werden müssen.
Zu einem Interface können keine Objekte erzeugt werden; es besitzt keinen Konstruktor.
Es können Methoden mit gleichen Signaturen und unterschiedlichen Implementierungen
aus den Oberklassen geerbt werden.
Abstrakte Methoden besitzen keine Implementierung.
Für default- und static-Methoden gelten besondere Regeln.
Folie-927
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Interface (Fortsetzung)
Beispiele für die Syntax mit abstrakten Methoden
public interface I1 public interface I2
{ {
void m(); int f();
} }
public interface I3
{
int g( int i );
void m();
}
Die Deklaration der Methoden kann ohne Modifizierer erfolgen:
void m(); steht in einem Interface für public abstract void m();
Schlüsselwort: interface
Folie-928
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Spezialisierung von
Interfaces: extends
Interface (Fortsetzung)
Beispiele für die Syntax mit abstrakten Methoden
public interface I1 public interface I2
{ {
void m(); int f();
} }
public interface I3 public interface Both extends I1, I2
{ {
int g( int i ); double h( double p );
void m(); }
}
Das Interface Both erweitert die beiden Interfaces I1 und I2:
Klassen, die Both implementieren, müssen also drei Methoden anbieten:
– void m() Deklaration in Interface I1
– int f() Deklaration in Interface I2
– double h( double p ) Deklaration in Interface Both
Folie-929
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Syntaxdiagramm zu Interface
Bezeichner
{
Interface
Signaturenliste
interface
}
Modifiziererliste
extends
Bezeichnerliste< >
Bezeichnerliste
Folie-930
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Interface (Fortsetzung)
Beispiele für die Syntax mit abstrakten Methoden
public interface I1 public interface I2
{ {
void m(); int f();
} }
public interface I3 public interface Both extends I1, I2
{ {
int g( int i ); double h( double p );
void m(); }
}
public class C implements Both, I3
{
public void m() { … }
public int f() { … }
public int g( int i ) { … }
public double h( double p ) { … }
}
Realisierung von Interfaces durch eine Klasse:
implements
Die Klasse muss alle vier Methoden aus I1, I2,
I3 und Both implementieren.
m() aus I1 und m() aus I3 können dabei
nicht unterschieden werden
Folie-931
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Interface (Fortsetzung)
Beispiele für die Syntax mit abstrakten Methoden
public interface I1 public interface I2
{ {
void m(); int f();
} }
public interface I3 public interface Both extends I1, I2
{ {
int g( int i ); double h( double p );
void m(); }
}
public class C implements Both, I3
{
public void m() { … }
public int f() { … }
public int g( int i ) { … }
public double h( double p ) { … }
} Modifizierer in Klasse notwendig: public
Folie-932
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Interface (Fortsetzung)
Beispiele für die Syntax mit abstrakten Methoden
public interface I1 public interface I2
{ {
void m(); int f();
} }
public interface I3 public interface Both extends I1, I2
{ {
int g( int i ); double h( double p );
void m(); }
}
public abstract class A
implements Both, I3
{
public void m() { … }
public int f() { … }
}
alternativ:
Eine abstrakte Klasse kann von Interface
vorgeschriebene Implementierung auf eigene
Unterklassen verschieben.
Die Implementierungen von g und h fehlen noch.
Folie-933
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Bezeichnerliste< Syntaxdiagramm zu Klasse Bezeichner { Klasse Klassenrumpf class } Modifiziererliste extends implements Bezeichner Bezeichnerliste >
Folie-934
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Einsatz des Konzepts Interface am Beispiel der Klasse DoublyLinkedList
Die bei der Deklaration von DoublyLinkedList verwendeten abstrakten Klassen
werden durch passende Interfaces ersetzt.
public class DoublyLinkedList
implements Iterable
…
public Iterator
private abstract class ListIterator
implements Iterator
private class ForwardIterator extends ListIterator { … }
public static interface SubstitutionStrategy
public static interface InspectionStrategy
public static interface DeletionStrategy
private class Element { … }
}
public interface Iterator
public interface Iterable
Folie-935
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel: Interfaces für Iteratoren
Die Syntax von generischen Interfaces entspricht der von generischen Klassen.
Das Interface wird analog zu der bekannten Klasse deklariert:
public interface Iterator
{
boolean hasNext();
E next();
}
Die Umsetzung eines Interfaces durch eine Klasse wird erzwungen
durch die Angabe von implements:
private abstract class ListIterator
implements Iterator
{
public boolean hasNext() { … }
public T next() { … }
…
}
Folie-936
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klassen, die einen Iterator anbieten,
können unmittelbar erkennt werden.
Der Iterator wird immer über die
gleiche Methode bereitgestellt,
die Nutzung ist uniform.
Beispiel: Interfaces für Iteratoren (Fortsetzung)
Deklaration eines weiteren Interfaces, das Klassen charakterisiert und so universell nutzbar macht,
die einen Iterator anbieten:
public interface Iterable
Iterator
}
public class DoublyLinkedList
implements Iterable
…
public Iterator
{
return new ForwardIterator();
}
…
}
public class BinarySearchTree
implements Iterable
…
}
Folie-937
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Generische Methoden
Nun können auch Methoden deklariert werden, die auf allen Datenstrukturen arbeiten,
die das Interface Iterable umsetzen:
public static
{
Iterator
while ( it.hasNext() )
{
System.out.println( it.next() );
}
}
printData ist eine generische Methode, die ihren eigenen Typparameter F besitzt. *)
Der Typparameter wird zwischen den Modifizierern und dem Rückgabetyp angeführt.
printData gibt den Inhalt jeder Datenstruktur aus, die das Interface Iterable implementiert.
Iterable zeigt an, dass die Datenstruktur eine Methode iterator() besitzt,
die ein Iterator
*) Die Methode printData muss nicht innerhalb einer generischen Klasse deklariert werden.
Typparameter
für printData
Folie-938
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Syntaxdiagramm zu Methodenkopf
Typ
( Parameterliste )
Methodenkopf Modifizierer
Bezeichner
>< Bezeichnerliste
Folie-939
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Generische Methoden (Fortsetzung)
DoublyLinkedList
students.add( 15 );
…
printData( ints );
BinarySearchTree
students.add( new Student( “B”, “Inf”, 18 ) );
…
printData( students );
Die Methode printData ist außerhalb der Klassen DoublyLinkedList und BinarySearchTree
deklariert.
Die Methode printData kann mit Argumenten von allen Klassen arbeiten,
die das Interface Iterable implementieren.
Das Typargument für den Typparameter F wird von Java
implizit aus dem der Methode printData übergebenen Argument bestimmt:
– aus printData( ints ) wird für F das Typargument Integer bestimmt,
– aus printData( students ) wird für F das Typargument Student bestimmt.
Folie-940
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Interface – default-Methoden *)
Das Interface Iterable wird von der Java-Klassenbibliothek bereitgestellt und genutzt. **)
Viele (fertige) Klassen implementieren das Interface Iterable.
Ein Hinzunehmen von weiteren (abstrakten) Methoden würde
alle (fertigen) implementierenden Klassen in abstrakte Klassen verwandeln,
da sie keine Realisierungen für die neu hinzugekommenen (abstrakten) Methoden besitzen.
*) default-Methoden sind ein Sprachkonzept seit Java 8.
**) siehe: http://docs.oracle.com/javase/8/docs/api/
Folie-941
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Interface – default-Methoden *)
Das Interface Iterable wird von der Java-Klassenbiliothek bereitgestellt und genutzt. **)
Viele (fertige) Klassen implementieren das Interface Iterable.
Ein Hinzunehmen von weiteren (abstrakten) Methoden würde
alle (fertigen) implementierenden Klassen in abstrakte Klassen verwandeln,
da sie keine Realisierungen für die neu hinzugekommenen (abstrakten) Methoden besitzen.
Lösung:
Ein Interface darf default-Implementierungen von Methoden besitzen,
so dass in den implementierenden Klassen keine Realisierung erzwungen wird.
*) default-Methoden sind ein Sprachkonzept seit Java 8.
**) siehe: http://docs.oracle.com/javase/8/docs/api/
Folie-942
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Interface – default-Methoden *)
Das Interface Iterable wird von der Java-Klassenbiliothek bereitgestellt und genutzt. **)
Viele (fertige) Klassen implementieren das Interface Iterable.
Ein Hinzunehmen von weiteren (abstrakten) Methoden würde
alle (fertigen) implementierenden Klassen in abstrakte Klassen verwandeln,
da sie keine Realisierungen für die neu hinzugekommenen (abstrakten) Methoden besitzen.
Lösung:
Ein Interface darf default-Implementierungen von Methoden besitzen,
so dass in den implementierenden Klassen keine Realisierung erzwungen wird.
Probleme:
Es können jetzt Konflikte auftreten, wenn Methoden mit gleicher Signatur und
unterschiedlicher default-Implementierung aus verschiedenen Interfaces geerbt werden.
*) default-Methoden sind ein Sprachkonzept seit Java 8.
**) siehe: http://docs.oracle.com/javase/8/docs/api/
Folie-943
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Interface – default-Methoden (Fortsetzung)
Geänderte Deklaration des Interfaces Iterable (seit Java 8):
public interface Iterable
{
Iterator
default void forEach( … )
{ … }
default Spliterator
{ … }
}
Da ein Interface keine Attribute besitzen kann, müssen auch die Implementierungen der
beiden Methoden forEach und spliterator ohne Attribute auskommen.
bereits bekannte Methode:
forEach führt eine Aktion für
jedes Element der iterierbaren
Struktur aus (vgl. Strategiemuster)
spliterator erzeugt ein
spliterator-Objekt
erzeugt ein Iterator-Objekt
(«Iterator» für paralelle Verarbeitung)
Folie-944
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Interface – default-Methoden (Fortsetzung)
Wie werden die entstehenden Konflikte gelöst, wenn Methoden mit gleicher Signatur und
unterschiedlicher default-Implementierung aus verschiedenen Interfaces geerbt werden?
Eine Klasse implementiert ein Interface und überschreibt dabei eine geerbte
default-Methode:
Es wird die in der Klasse deklarierte Methode ausgeführt.
Ein Interface erweitert ein Interface und überschreibt dabei eine geerbte
default-Methode:
Es wird die in dem erweiternden Interface deklarierte Methode in der
Vererbungs-/Implementierungshierarchie weitergegeben.
Verhalten bei einfachen Erbungsstrukturen:
konform zu den bisher bekannten Regeln
Folie-945
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Interface – default-Methoden (Fortsetzung)
Wie werden die entstehenden Konflikte gelöst, wenn Methoden mit gleicher Signatur und
unterschiedlicher default-Implementierung aus verschiedenen Interfaces geerbt werden?
Eine Klasse implementiert ein Interface und überschreibt dabei eine geerbte
default-Methode:
Es wird die in der Klasse deklarierte Methode ausgeführt.
Ein Interface erweitert ein Interface und überschreibt dabei eine geerbte
default-Methode:
Es wird die in dem erweiternden Interface deklarierte Methode in der
Vererbungs-/Implementierungshierarchie weitergegeben.
Eine Klasse implementiert ein Interface und erweitert eine Klasse und erbt dabei
von beiden Vorgängertypen eine default-Methode mit gleicher Signatur:
Es wird die in der Oberklasse deklarierte Methode ausgeführt.
Verhalten bei gemischter Erbungsstruktur:
Implementierung der (einzigen) Oberklasse wird ausgewählt.
Folie-946
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Interface – default-Methoden (Fortsetzung)
Wie werden die entstehenden Konflikte gelöst, wenn Methoden mit gleicher Signatur und
unterschiedlicher default-Implementierung aus verschiedenen Interfaces geerbt werden?
Eine Klasse implementiert ein Interface und überschreibt dabei eine geerbte
default-Methode:
Es wird die in der Klasse deklarierte Methode ausgeführt.
Ein Interface erweitert ein Interface und überschreibt dabei eine geerbte
default-Methode:
Es wird die in dem erweiternden Interface deklarierte Methode in der
Vererbungs-/Implementierungshierarchie weitergegeben.
Eine Klasse implementiert ein Interface und erweitert eine Klasse und erbt dabei
von beiden Vorgängertypen eine default-Methode mit gleicher Signatur:
Es wird die in der Oberklasse deklarierte Methode ausgeführt.
Ein Interface erweitert mehrere Interfaces und erbt dabei mehrfach eine
default-Methode mit gleicher Signatur:
Es muss explizit eine neue default-Deklaration angelegt werden.
Auf die geerbten Methoden kann Bezug genommen werden mit:
InterfaceName.super.MethodenName
Folie-947
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Interface – statische Methoden
Interfaces können auch zur Deklaration von statischen Methoden benutzt werden.
Eine Methode wie calculateGcd (siehe Folie 227) kann in einem Interface deklariert werden,
um unabhängig von einer Klasse oder einem Objekt aufrufbar zu sein.
public interface Utilities
{
static int calculateGcd( int v1, int v2 ) { … }
}
Eine in einem Interface deklarierte statische Methode wird nicht vererbt.
Daher kann in Spezialisierungshierarchien und bei der Implementierung durch Klassen kein
Konflikt auftreten.
Der Aufruf kann ausschließlich über den Namen des deklarierenden Interfaces erfolgen:
Utilities.calculateGcd( 27, 18 )
Folie-948
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Unveränderbare Deklarationen: final
Das Schlüsselwort final bezeichnet in Java eine unveränderbare Deklaration:
Eine mit final gekennzeichnete Klasse darf nicht geerbt werden.
Eine mit final gekennzeichnete Methode darf in Unterklassen nicht redefiniert werden.
Mit final gekennzeichneten Attributen, Variablen und Parametern darf nur einmal ein Wert
zugewiesen werden.
Mit final gekennzeichnete Attribute oder Variablen repräsentieren also konstante Werte und
werden kurz auch als Konstante bezeichnet.
Konstante erhalten in Java üblicherweise Bezeichner aus Großbuchstaben:
final int EXCELLENT = 1;
Folie-949
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Interface – Konstante
In einem Interface können auch öffentliche statische konstante Attribute deklariert werden:
public interface Grades
{
int EXCELLENT = 1;
int GOOD = 2;
}
Die Modifizierer public static final können alle oder einzeln entfallen.
Konstante werden von Interfaces an Interfaces oder Klassen vererbt.
Namenskonflikte werden vom Compiler nur gemeldet, wenn diese aufgelöst werden müssten.
Dann muss im erweiternden Interface oder der implementierenden Klasse eine Redefinition
erfolgen.
Folie-950
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Interface – Zusammenfassung
Das Konzept Interface ermöglicht die Deklaration von Verhalten durch das Festlegen einer
Menge von Methodensignaturen.
Interfaces können dazu benutzt werden, die Methoden zusammenzufassen.
Interfaces können dazu benutzt werden, den Zugang zu funktionalen Konzepten wie Iteratoren
zu vereinheitlichen.
Interfaces können sehr flexibel kombiniert werden, da in einer Hierarchie von Interfaces
mehrfaches Erben möglich ist.
Über Interfaces kann eine Hierarchie kompatibler Typen angelegt werden.
Eine Referenz auf ein Interface kann wie eine Referenz auf eine Klasse genutzt werden.
Eine Referenz auf ein Interface kann auf die Objekte der Klassen verweisen, die das Interface
implementieren.
Interfaces verbessern die Flexibilität der Typstruktur, da eine Klasse mehrere Interfaces
implementieren und zusätzlich noch von genau einer Oberklasse erben kann.
Interfaces können Methoden mit default-Implementierungen deklarieren. *)
Interfaces können zusätzlich statische Methoden und Konstante deklarieren. *)
*) Diese Möglichkeiten werden im Rahmen dieser Vorlesung nicht genutzt.
Folie-951
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Interface – Zusammenfassung (Fortsetzung)
Übersicht
Klasse Interface
kann erben von Klasse/Interface Interface
kann vererben an Klasse Klasse/Interface
Attribute + –
(statische) Konstante + +
Konstruktor + –
abstrakte Methode + +
(Instanz-)Methode + –
default-Methode ( + ) +
statische Methode + + (keine Vererbung)
Folie-952
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Interface – Zusammenfassung (Fortsetzung)
Die Java-Entwiclungsumgebung (JDK) stellt eine Vielzahl von (fertigen) Klassen und Interfaces
in verschiedenenen Paketen zur Verfügung.
Hierzu zählen insbesondere auch die folgenden drei Interfaces, die in ihren Deklarationen den in
der Vorlesung vorgestellten Fassungen entsprechen:
public interface Comparable
im Paket java.lang
public interface Iterable
im Paket java.lang
public interface Iterator
im Paket java.util
In den in der weiteren Vorlesung folgenden Implementierungen wird nun immer auf diese
Interfaces zurückgegriffen.
*) Das Paket java.lang ist immer auch ohne expliziten Import verfügbar.
Folie-953
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Interface
(siehe Folie 914)
Nach Durcharbeiten des Kapitels Interface sollen die teilnehmenden Studierenden
das Konstrukt des Interfaces kennen,
Interfaces und Hierarchien von Interfaces konzipieren und programmieren können,
Interfaces durch Klassen implementieren können,
Interfaces und (abstrakte) Klasse gegeneinander abgrenzen können,
generische Methoden deklarieren und einsetzen können.
Folie-954
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen, Algorithmen
und Programmierung 1 (DAP 1)
Fakultät für Informatik
Wintersemester 2019/20
Stefan Dissmann
Anonyme Klassen und Lambda-Ausdrücke
Folie-955
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Anonyme Klassen und Lambda-Ausdrücke
Nach Durcharbeiten des Kapitels Anonyme Klassen und Lambda-Ausdrücke sollen
die teilnehmenden Studierenden
die Möglichkeiten des Einsatzes anonymer Klassen kennen,
die Bedeutung funktionaler Interfaces kennen,
einige Möglichkeiten des Einsatzes von Lambda-Ausdrücken kennen.
Folie-956
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rückblick: Einsatz des Entwurfsmusters Strategie
Deklaration einer Schnittstelle für Strategien:
public static interface SubstitutionStrategy
{
T substitute( T ref );
}
Deklaration einer passenden Strategie:
public class DoubleIntegersStrategy
implements DoublyLinkedList.SubstitutionStrategy
{
public Integer substitute( Integer ref )
{
return 2 * ref;
}
}
Folie-957
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rückblick: Einsatz des Entwurfsmusters Strategie (Fortsetzung)
Anlegen von Strategie-Objekten
Analyse:
Die Methode substituteAll der Klasse DoublyLinkedList sorgt während der Ausführung
dafür, dass die substitute-Methode des als Argument übergebenen Strategie-Objekts auf alle
Inhalte in der Liste angewandt wird.
Dafür muss eine geeignete Implementierung des Interfaces SubstitutionStrategy realisiert
werden. Eine geeignete Klasse muss spezifisch deklariert werden.
Es werden also Klassen benötigt, von denen möglicherweise nur genau ein Objekt erzeugt
werden soll. Beim häufigen Einsatz des Entwurfsmusters Strategie müssen sehr viele von
solchen Klassen implementiert werden: Die Programmstruktur wird unübersichtlich.
Lösungsansatz:
anonyme Klasse
Folie-958
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Anonyme Klasse
Idee:
– Deklaration der Klasse und
– Erzeugen des (einzig möglichen) Objekts
fallen zusammen.
Konsequenzen:
– Die Klasse erhält keinen eigenen Namen. Sie bleibt anonym.
– Die Nutzung ist nur möglich, wenn die Klasse einen bereits bekannten Typ,
also eine Klasse oder ein Interface, erweitert bzw. implementiert.
Dann wird der Zugriff auf die Methode des so erzeugten Objekt möglich über die
Deklarationen der öffentlichen Methoden in der erweiterten Klasse oder implementierten
Schnittstelle.
Folie-959
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Anonyme Klasse (Fortsetzung)
…
DoublyLinkedList
ints.add( 5 );
…
DoublyLinkedList.SubstitutionStrategy
new DoublyLinkedList.SubstitutionStrategy
{
public Integer substitute( Integer ref )
{
return 2 * ref;
}
};
ints.substituteAll( s );
…
Für s wird ein Objekt einer anonymen Klasse erzeugt,
die das Interface SubstitutionStrategy implementiert.
Syntaktisch wird das durch eine konstruktor-analoge Erzeugung mit nachfolgender Deklaration
des Klassenrumpfs erreicht.
ähnlich zu Konstruktoraufruf
Rumpf der Klasse
Folie-960
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Anonyme Klasse (Fortsetzung)
mögliche Fassung ohne Nutzung einer zusätzlichen Referenzvariablen:
…
DoublyLinkedList
ints.add( 5 );
…
ints.substituteAll(
new DoublyLinkedList.SubstitutionStrategy
{
public Integer substitute( Integer ref )
{
return 2 * ref;
}
}
);
…
Objekt wird direkt als Argument übergeben
Rumpf der Klasse
Folie-961
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Anonyme Klasse (Fortsetzung)
…
DoublyLinkedList
ints.add( 5 );
…
int factor = 2;
ints.substituteAll(
new DoublyLinkedList.SubstitutionStrategy
{
public Integer substitute( Integer ref )
{
return factor * ref;
}
}
);
…
Die anonyme Klasse wird innerhalb ihrer Umgebung vereinbart und hat Zugriff auf die dort
deklarierten Attribute und auf solche Variable, die effektiv final oder final sind.
Effektiv final sind Variable, die nicht als final deklariert sind, denen aber trotzdem nur einmal
ein Wert zugewiesen wird, die also im Programm wie Konstante behandelt werden.
effektiv finale Variable factor
Folie-962
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Anonyme Klasse (Fortsetzung)
verbleibendes Problem bei komplexeren anonymen Klassen:
Ein Konstruktor kann nicht deklariert werden, da die Klasse keinen Namen
– und somit auch keinen Namen für den Konstruktor – hat.
Folie-963
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Anonyme Klasse (Fortsetzung)
verbleibendes Problem bei komplexeren anonymen Klassen:
Ein Konstruktor kann nicht deklariert werden, da die Klasse keinen Namen
– und somit auch keinen Namen für den Konstruktor – hat.
Lösung:
Exemplarinitialisierer
Einfache Blöcke, die im Rumpf der anonymen Klasse stehen und
nacheinander in der Reihenfolge ihrer Deklaration in der Klasse ausgeführt werden.
Folie-964
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Exkurs: Initialisierung von Attributen
Attribute können an verschiedenen Stellen einer Klasse initialisiert werden.
Zunächst wird jedes Attribut bei der Reservierung des Speicherplatzes mit 0-Bits belegt.
Jedes Attribut ist daher mit einem Wert vorbelegt, auf Attribute kann auch ohne weitere
Zuweisung fehlerfrei lesend zugegriffen werden.
Ein Attribut kann unmittelbar bei der Deklaration initialisiert werden:
private int value = 27;
Solche Initialisierungen sind auf die Angabe eines Ausdrucks reduziert. Komplexere Abläufe
und insbesondere das voneinander abhängige Initialisieren mehrerer Attribute kann so nicht
vorgenommen werden.
Die Initialisierung bei der Deklaration wird immer vor der Ausführung des Rumpfes eines
Konstruktors ausgeführt.
Darüber hinaus kann eine komfortable Belegung mit Werten in einem Konstruktor erfolgen.
Hier sind Berechnungen auf der Basis von Anweisungen und Fehlerbehandlungen möglich.
Exemplarinitialisierer sind speziell für die Initialisierung von Objekten anonymer Klassen
notwendig, können aber in allen Klassen eingesetzt werden.
Exemplarinitialisierer werden vor dem Konstruktor ausgeführt.
Bei der Erzeugung eines Objekts der Klasse C werden alle Exemplarinitialisierer und der
Konstruktor der Oberklasse vor allen Initialiserungen der Klasse C ausgeführt (Deklaration,
Exemplarinitialisierer, Konstruktor).
Folie-965
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Exkurs: Initialisierung von Attributen (Fortsetzung)
Konstruktoren können auf statische Attribute zugreifen.
Da ein statisches Attribut auch ohne das Vorliegen eines Objekts und somit vor dem ersten
Aufruf eines Konstruktors verfügbar ist, kann es mit einem Konstruktor nicht sicher initialisiert
werden.
Statische Attribute können daher über einen Klasseninitialisierer mit Werten belegt werden.
Klasseninitialisierer können mehrfach in einer Klasse auftreten. Sie werden in der Reihenfolge
ausgeführt, in der sie in der Klasse auftreten. Die Ausführung erfolgt nach der Initialisierung
bei der Deklaration von Klassenvariablen dann, wenn die Klasse in die virtuelle Maschine JVM
geladen wird.
Syntax (innerhalb des Rumpfes einer Klasse):
Initialisierung bei der Deklaration, durch Initialisierer und durch Konstruktoren sollten
vorsichtig (und sinnvoll) miteinander kombiniert werden, da die Abhängigkeiten schnell zu
unübersichtlichen Abläufen führen. Insbesondere werden Initialisierer in langen Klassen leicht
übersehen.
Blockstatic
Folie-966
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Funktionales Interface (seit Java 8)
Ein funktionales Interface ist ein Interface,
das genau eine abstrakte Methode vereinbart.
Funktionale Interfaces werden normalerweise passend annotiert mit
@FunctionalInterface
Beispiel:
@FunctionalInterface
public static interface SubstitutionStrategy
{
T substitute( T ref );
}
Eigenschaften:
– Implementierungen eines funktionalen Interfaces unterscheiden sich bezüglich des über den
Typ des Interfaces erreichbaren Verhaltens nur durch die Implementierungen der einzigen
(abstrakten) Methode.
– Die Implementierung kann daher auf die Deklaration der einzigen Methode reduziert werden:
Lambda-Ausdruck
Folie-967
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lambda-Ausdruck (seit Java 8)
Ein Lambda-Ausdruck ist die Deklaration einer anonymen Methode.
Beispiel:
( int a, int b ) -> { return a * b; }
Der Typ des Rückgabewertes wird nicht angegeben, sondern vom Compiler
durch geeignetes Schließen implizit bestimmt (Typinferenz).
Das Beispiel entspricht der Deklaration einer Methode der Form:
int prod( int a, int b )
{
return a * b;
}
Parameterliste Methodenrumpf
Folie-968
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lambda-Ausdruck (Fortsetzung)
Ein Lambda-Ausdruck ist die Deklaration einer anonymen Methode.
Beispiel:
( int a, int b ) -> { return a * b; }
Kann vom Compiler aus der Verwendung der Methode auf den Typ der Parameter
geschlossen werden, so werden auch diese durch Typinferenz bestimmt.
Dann können die Typangaben entfallen:
( a, b ) -> { return a * b; }
Folie-969
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lambda-Ausdruck (Fortsetzung)
Ein Lambda-Ausdruck ist die Deklaration einer anonymen Methode.
Beispiel:
( int a, int b ) -> { return a * b; }
( a, b ) -> { return a * b; }
Enthält der Rumpf der Methode nur eine return-Anweisung, so können der Block
– und damit die Klammern – und das Schlüsselwort return entfallen:
( a, b ) -> a * b
Folie-970
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lambda-Ausdruck (Fortsetzung)
Ein Lambda-Ausdruck ist die Deklaration einer anonymen Methode.
Beispiel:
( int a, int b ) -> { return a * b; }
( a, b ) -> { return a * b; }
( a, b ) -> a * b
Hat die Methode nur einen Parameter, so kann die Klammerung des Parameters entfallen:
a -> a * a
Folie-971
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lambda-Ausdruck (Fortsetzung)
Ein Lambda-Ausdruck ist die Deklaration einer anonymen Methode.
Beispiel:
( int a, int b ) -> { return a * b; }
( a, b ) -> { return a * b; }
( a, b ) -> a * b
a -> a * a
Hat die Methode keinen Parameter, so muss eine leere Klammerung angegeben werden:
() -> 2
() -> System.out.println( “lambda” )
Folie-972
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lambda-Ausdruck (Fortsetzung)
Einsatz von Lambda-Ausdrücken
Lambda-Ausdrücke können Objekte von funktionalen Interfaces ersetzen:
Ein funktionales Interface erfordert für seine Implementierung
die Realisierung genau einer abstrakten Methode,
ein Lambda-Ausdruck liefert die Implementierung genau einer einzelnen Methode.
Der Compiler stellt zwischen beiden Konzepten eine implizite Beziehung her:
Wird eine Instanz eines funktionalen Interfaces erwartet
und wird stattdessen ein Lambda-Ausdruck angegeben,
so wird die durch diesen gegebene Methode als Umsetzung
der einzigen abstrakten Methode des Interfaces interpretiert und verwendet.
Da das funktionale Interface die vollständige Signatur seiner abstrakten Methode deklariert,
ist die implizite Bestimmung der Typen der Parameter und des Rückgabewertes in der Regel
einfach.
Folie-973
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lambda-Ausdrücke zur Verhaltensbeschreibung
Substitution-Strategie – Lösung mit anonymer Klasse (siehe Folie 960):
ints.substituteAll(
new DoublyLinkedList.SubstitutionStrategy
{
public Integer substitute( Integer ref )
{
return 2 * ref;
}
}
);
Substitution-Strategie – gleichwertige Lösung mit Lambda-Ausdruck:
ints.substituteAll( ref -> 2 * ref );
Der Lambda-Ausdruck liefert eine Methode, die einen Parameter besitzt.
Die Methode substituteAll erwartet als Argument eine Implementierung des Interfaces
SubstitutionStrategy
einem Parameter (des Typs Integer) und einer Integer-Rückgabe erfordert.
Genau das leistet der Lambda-Ausdruck ref -> 2 * ref.
Folie-974
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lambda-Ausdrücke zur Verhaltensbeschreibung (Fortsetzung)
Inspection-Strategie – Lösung mit Lambda-Ausdruck:
:
ints.inspectAll( x -> System.out.print( x + “, ” ) );
Die Methode inspectAll erwartet als Argument eine Implementierung des Interfaces
InspectionStrategy
einem Parameter (des Typs Integer) und ohne Rückgabe erfordert.
Genau das leistet der Lambda-Ausdruck x -> System.out.print( x + “, ” ).
Das Typargument Integer der Erzeugung des der Referenzvariablen ints zugewiesenen
Objekts bildet zugleich das Typargument für die innere Klasse InspectionStrategy.
Deletion-Strategie – Lösung mit Lambda-Ausdruck:
:
ints.deleteSelected( x -> x % 2 == 0 );
Alle Elemente mit geraden Inhalten werden aus der Liste entfernt.
Folie-975
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lambda-Ausdrücke zur Verhaltensbeschreibung (Fortsetzung)
Substitution-Strategie – weitere Lösung mit Lambda-Ausdruck
int factor = 2;
ints.substituteAll( x -> factor * x );
Der Lambda-Ausdruck wird innerhalb seiner lokalen Umgebung vereinbart und kann die dort
deklarierten Variablen benutzen («einfangen»), sofern diese effektiv final oder final sind.
Hinweis:
– Die Schlüsselwörter this und super beziehen sich in Lambda-Ausdrücken auf die sie
umgebende Klasse.
– In anonymen Klassen beziehen sich die Schlüsselwörter this und super ebenfalls auf die
sie umgebende Klasse – das ist aber in diesem Fall die anonyme Klasse selbst!
effektiv finale Variable factor
Folie-976
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Funktionstypen
Das Paket java.util.function enthält zahlreiche vordefinierte funktionale Interfaces:
public interface Function
public interface BiFunction
public interface Predicate
public interface Consumer
public interface Supplier
…
Folie-977
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Funktionstypen (Fortsetzung)
Objekte der implizit erzeugten Klassen können
Referenzen auf die Interfaces zugewiesen werden:
public interface Function
Function
int j = add5.apply( i );
auch möglich ist:
( (Function
public interface Predicate
Predicate
boolean b = isPositive.test( i );
public interface Consumer
Consumer
out.accept( “hello” );
Lambda-Ausdruck
Type-Cast ermöglicht Aufruf
Folie-978
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Funktionstypen (Fortsetzung)
Die Methoden von implizit erzeugten Klassen können
auf bestehenden Methoden aufgebaut werden:
public class BooleanUtilities
{
public static boolean positiveNumber( int i )
{
return i > 0;
}
}
dann ist möglich:
…
Predicate
boolean b = gt0.test( i );
…
Der ::-Operator kürzt ab:
statt Predicate
ist möglich Predicate
Folie-979
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
weitere Methoden in vordefinierten funktionalen Interfaces
Beispiel: interface java.util.function.Function
@FunctionalInterface
public interface Function
{
R apply(T t);
static
{
return t -> t;
}
default
{
return t -> after.apply( apply( t ) );
}
default
{
return t -> apply( before.apply( t ) );
}
}
die abstrakte Methode
Folie-980
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
weitere Methoden in vordefinierten funktionalen Interfaces (Fortsetzung)
Beispiel: interface java.util.function.Function
@FunctionalInterface
public interface Function
{
R apply(T t);
static
{
return t -> t;
}
default
{
return t -> after.apply( apply( t ) );
}
default
{
return t -> apply( before.apply( t ) );
}
}
erzeugt Function-Objekt,
erzeugt Function-Objekt,
dessen apply Identität ist
dessen apply Verkettung ist
Folie-981
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
weitere Methoden in vordefinierten funktionalen Interfaces (Fortsetzung)
Beispiel: interface java.util.function.Function
Deklaration der Methode andThen
Typ der Rückgabe Typ des Parameters
Folie-982
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
weitere Methoden in vordefinierten funktionalen Interfaces (Fortsetzung)
Beispiel: interface java.util.function.Function
Deklaration der Methode andThen
V ist ein nur für diese Methode deklarierter Typparameter, der die Beziehung zwischen dem
Typ der Rückgabe und dem Typ des Parameters herstellt.
Folie-983
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
weitere Methoden in vordefinierten funktionalen Interfaces (Fortsetzung)
Beispiel: interface java.util.function.Function
Deklaration der Methode andThen
V ist ein nur für diese Methode deklarierter Typparameter, der die Beziehung zwischen dem
Typ der Rückgabe und dem Typ des Parameters herstellt.
Die zulässigen Typargumente werden eingeschränkt durch: ? super R und ? extends V
Erlaubt sind nur Oberklassen von R oder Interfaces, die von R implementiert werden.
Erlaubt sind nur Unterklassen von V oder Klassen, die V implementieren.
Folie-984
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
weitere Methoden in vordefinierten funktionalen Interfaces (Fortsetzung)
Beispiel: interface java.util.function.Function
Deklaration der Methode andThen
V ist ein nur für diese Methode deklarierter Typparameter, der die Beziehung zwischen dem
Typ der Rückgabe und dem Typ des Parameters herstellt.
Die zulässigen Typargumente werden eingeschränkt durch: ? super R und ? extends V
Erlaubt sind nur Oberklassen von R oder Interfaces, die von R implementiert werden.
Erlaubt sind nur Unterklassen von V oder Klassen, die V implementieren.
Da der Typ der Unterklasse selbst in der Deklaration der Signatur nicht benötigt wird,
wird die Wildcard ? als Platzhalter verwendet.
Für Typeinschränkungen gilt, dass T selbst die Bedingungen erfüllt.
Es gilt immer: T super T und T extends T
Folie-985
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
weitere Methoden in vordefinierten funktionalen Interfaces (Fortsetzung)
Beispiel: interface java.util.function.Function
public interface Function
{
R apply(T t);
default
{
return t -> after.apply( apply( t ) );
}
…
}
Function enthält eine Methode apply, die ein T-Objekt in ein R-Objekt überführt.
Folie-986
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
weitere Methoden in vordefinierten funktionalen Interfaces (Fortsetzung)
Beispiel: interface java.util.function.Function
public interface Function
{
R apply(T t);
default
{
return t -> after.apply( apply( t ) );
}
…
}
Function enthält eine Methode apply, die ein T-Objekt in ein R-Objekt überführt.
andThen wendet die apply-Methode ihres Arguments auf das Ergebnis des eigenen apply an:
Folie-987
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
weitere Methoden in vordefinierten funktionalen Interfaces (Fortsetzung)
Beispiel: interface java.util.function.Function
public interface Function
{
R apply(T t);
default
{
return t -> after.apply( apply( t ) );
}
…
}
Function enthält eine Methode apply, die ein T-Objekt in ein R-Objekt überführt.
andThen wendet die apply-Methode ihres Arguments auf das Ergebnis des eigenen apply an:
– Der Typ V der Rückgabe von andThen hängt nur von after und nicht von T und R ab.
– Die Bedingungen des Typs V werden auch von allen Unterklassen von V eingehalten,
wobei der genaue Typ der Rückgabe von after nicht interessiert: ? extends V
– Damit after.apply auf das Ergebnis von apply angewandt werden kann, muss after so
definiert sein, dass Objekte von R verarbeitet werden können, wobei der genaue Typ nicht
interessiert: ? super R
Folie-988
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
weitere Methoden in vordefinierten funktionalen Interfaces (Fortsetzung)
Beispiel: interface java.util.function.Function
public interface Function
{
R apply(T t);
default
{
return t -> after.apply( apply( t ) );
}
…
}
Der Lambda-Ausdruck t -> … erzeugt ein zu Function kompatibles Objekt,
dessen apply-Methode die folgende Anweisung implementiert:
after.apply(apply( t ))
Dabei wird der effektiv finale Parameter after «eingefangen».
Das durch den Lambda-Ausdruck erzeugte Objekt wird durch die Methode andThen
zurückgegeben.
Folie-989
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
weitere Methoden in vordefinierten funktionalen Interfaces (Fortsetzung)
Beispiel: interface Function
Function
Function
f.compose( Function.identity() ).apply( 5 ) erzeugt Function-Objekt, das f(id(x))
definiert und für das durch den apply-Aufruf f(id(5)) = 25 berechnet wird.
Folie-990
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
weitere Methoden in vordefinierten funktionalen Interfaces (Fortsetzung)
Beispiel: interface Function
Function
Function
f.compose( Function.identity() ).apply( 5 ) erzeugt Function-Objekt, das f(id(x))
definiert und für das durch den apply-Aufruf f(id(5)) = 25 berechnet wird.
f.compose( g ).apply( 5 ) erzeugt Function-Objekt, das f(g(x)) definiert und für das
durch den apply-Aufruf f(g(5)) = 225 berechnet wird.
Folie-991
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
weitere Methoden in vordefinierten funktionalen Interfaces (Fortsetzung)
Beispiel: interface Function
Function
Function
f.compose( Function.identity() ).apply( 5 ) erzeugt Function-Objekt, das f(id(x))
definiert und für das durch den apply-Aufruf f(id(5)) = 25 berechnet wird.
f.compose( g ).apply( 5 ) erzeugt Function-Objekt, das f(g(x)) definiert und für das
durch den apply-Aufruf f(g(5)) = 225 berechnet wird.
f.andThen( g ).apply( 5 ) erzeugt Function-Objekt, das g(f(x)) definiert und für das
durch den apply-Aufruf g(f(5)) = 75 berechnet wird.
Folie-992
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
weitere Methoden in vordefinierten funktionalen Interfaces (Fortsetzung)
Beispiel: interface Function
Function
Function
f.compose( Function.identity() ).apply( 5 ) erzeugt Function-Objekt, das f(id(x))
definiert und für das durch den apply-Aufruf f(id(5)) = 25 berechnet wird.
f.compose( g ).apply( 5 ) erzeugt Function-Objekt, das f(g(x)) definiert und für das
durch den apply-Aufruf f(g(5)) = 225 berechnet wird.
f.andThen( g ).apply( 5 ) erzeugt Function-Objekt, das g(f(x)) definiert und für das
durch den apply-Aufruf g(f(5)) = 75 berechnet wird.
f.andThen( g ).compose( x -> x + 7 ).apply( 5 ) keine Typbestimmung möglich, da
der Parametertyp von compose zu wenig Vorgaben enthält.
Folie-993
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
weitere Methoden in vordefinierten funktionalen Interfaces (Fortsetzung)
Beispiel: interface Function
Function
Function
f.compose( Function.identity() ).apply( 5 ) erzeugt Function-Objekt, das f(id(x))
definiert und für das durch den apply-Aufruf f(id(5)) = 25 berechnet wird.
f.compose( g ).apply( 5 ) erzeugt Function-Objekt, das f(g(x)) definiert und für das
durch den apply-Aufruf f(g(5)) = 225 berechnet wird.
f.andThen( g ).apply( 5 ) erzeugt Function-Objekt, das g(f(x)) definiert und für das
durch den apply-Aufruf g(f(5)) = 75 berechnet wird.
f.andThen( g ).compose( x -> x + 7 ).apply( 5 ) keine Typbestimmung möglich, da
der Parametertyp von compose zu wenig Vorgaben enthält.
f.andThen( g ).compose( (Integer x) -> x + 7 ).apply( 5 ) erzeugt Function-Objekt,
das g(f(x+7)) definiert und für das durch den apply-Aufruf g(f(5+7)) = 432 berechnet wird.
Folie-994
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
vordefinierte Umsetzungen des Entwurfsmusters Strategie
Vordefinierte Klassen setzen das Entwurfsmuster Strategie ein,
um über Lambda-Ausdrücke interne Abläufe zu steuern.
Beispiel:
public interface Iterator
{
boolean hasNext();
E next();
default void remove()
{ /* optional operation */ }
default void forEachRemaining( Consumer super E> action )
{
while ( hasNext() )
{
action.accept( next() );
}
}
}
funktionales Interface
public interface Consumer
void accept( T t ); …
}
Folie-995
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
vordefinierte Umsetzungen des Entwurfsmusters Strategie (Fortsetzung)
Beispiel: interface java.util.Iterator
funktionales Interface: interface Consumer
DoublyLinkedList
numbers.add( 2 ); numbers.add( 4 ); numbers.add ( 11 );
numbers.add( 5 ); numbers.add( 6 ); numbers.add (7 );
numbers.iterator().forEachRemaining( x -> System.out.print( x + ” ” ) );
erzeugt als Ausgabe: 2 4 11 5 6 7
Iterator
it.next();
it.forEachRemaining( x -> System.out.print( x + ” ” ) );
erzeugt als Ausgabe: 4 11 5 6 7
Folie-996
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
vordefinierte Umsetzungen des Entwurfsmusters Strategie (Fortsetzung)
Beispiel: interface java.util.List
public interface List
{
default void replaceAll( UnaryOperator
{
final ListIterator
while (li.hasNext()) {
li.set( operator.apply( li.next() ) );
}
}
default void sort( Comparator super E> c )
{ … }
…
}
Interface, das die üblichen Methoden
für Listen vorschreibt
Folie-997
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
vordefinierte Umsetzungen des Entwurfsmusters Strategie (Fortsetzung)
Beispiel: interface java.util.List
public interface List
{
default void replaceAll( UnaryOperator
{
final ListIterator
while (li.hasNext()) {
li.set( operator.apply( li.next() ) );
}
}
default void sort( Comparator super E> c )
{ … }
…
}
Die Methode sort stellt eine gemäß
des Comparator-Objekts aufsteigende Sortierung her.
funktionales Interface:
public interface UnaryOperator
extends Function
funktionales Interface:
public interface Comparator
{
int compare( T o1, T o2 );
…
}
Folie-998
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
vordefinierte Umsetzungen des Entwurfsmusters Strategie (Fortsetzung)
Beispiel: interface java.util.List
funktionales Interface: interface UnaryOperator
numbers.replaceAll( x -> x + 3 );
Wirkung: 2 4 11 5 6 7 wird zu 5 7 14 8 9 10
Folie-999
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
vordefinierte Umsetzungen des Entwurfsmusters Strategie (Fortsetzung)
Beispiel: interface java.util.List
funktionales Interface: interface Comparator
numbers.sort( (x,y) -> y – x );
Wirkung: 2 4 11 5 6 7 wird zu 11 7 6 5 4 2 absteigend sortiert,
da sort aufsteigend sortiert
numbers.sort( (x,y) -> x % 2 – y % 2 );
Wirkung: 2 4 11 5 6 7 wird zu 2 4 6 11 5 7 ungerade größer als gerade
numbers.sort( (x,y) -> y % 2 – x % 2 );
Wirkung: 2 4 11 5 6 7 wird zu 11 5 7 2 4 6 gerade größer als ungerade
Folie-1000
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Anonyme Klassen und Lambda-Ausdrücke
(siehe Folie 1107)
Nach Durcharbeiten des Kapitels Anonyme Klassen und Lambda-Ausdrücke sollten
die teilnehmenden Studierenden nun
die Möglichkeiten des Einsatzes anonymer Klassen kennen,
die Bedeutung funktionaler Interfaces kennen,
einige Möglichkeiten des Einsatzes von Lambda-Ausdrücken kennen.
Folie-1001
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen, Algorithmen
und Programmierung 1 (DAP 1)
Fakultät für Informatik
Wintersemester 2019/20
Stefan Dissmann
Beispiel: Mustererkennung
Folie-1002
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Mustererkennung
Nach Durcharbeiten des Kapitels Mustererkennung sollen
die teilnehmenden Studierenden
den Algorithmus zur Erkennung von Mustern in Texten kennen und erklären können,
die Implementierung des Algorithmus zur Erkennung von Mustern in Texten erklären können,
den Prozess der Umsetzung des Algorithmus in ein Java-Programm kennen,
den Gebrauch der Bibliotheksinterfaces java.util.Set, java.util.List und java.util.Map
kennen,
den Gebrauch der Bibliotheksklassen java.util.HashSet, java.util.LinkedList und
java.util.HashMap kennen,
generische Klassen nutzen können.
Folie-1003
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Einsatz generischer Klassen der Java Platform
Die auf den folgenden Folien beschriebene Problemstellung soll durch den Einsatz von bereits
erstellten und zusammen mit dem Java-Compiler bereitgestellten Klassen gelöst werden.
Dabei soll demonstriert werden, wie sich eine durchaus komplexe Aufgabenstellung schnell
und mit relativ wenig selbst geschriebenem Programmtext realisieren lässt.
Folie-1004
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung Mustererkennung
Aufgabe:
Stelle fest ob – und wie häufig – ein (Text-)Muster p in einem Text t vorkommt.
Beispiel:
t: aabaababbaaabbbababaabaabaaaaba
p: abaa
Folie-1005
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung Mustererkennung (Fortsetzung)
Aufgabe:
Stelle fest ob – und wie häufig – ein (Text-)Muster p in einem Text t vorkommt.
Beispiel:
t: aabaababbaaabbbababaabaabaaaaba
p: abaa
Lösung:
Vorkommen von p in t: 4
t: aabaababbaaabbbababaabaabaaaaba
1 2 3 4
Folie-1006
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung Mustererkennung (Fortsetzung)
Lohnt sich die Auseinandersetzung mit diesem einfachen Problem überhaupt?
Ja, insbesondere dann, wenn lange Muster in langen Texten gesucht werden.
Ein trivialer (und einfach zu realisierender) Algorithmus lässt sich sofort angeben:
Vergleiche einen Ausschnitt von t mit p:
Falls keine Übereinstimmung vorliegt, verschiebe den Ausschnitt von t um ein Zeichen.
t: aabaababbaaabbbababaabaabaaaaba
1. p: abaa Mißerfolg
2. p: abaa Treffer
3. p: abaa Mißerfolg
4. p: abaa Mißerfolg
5. p: abaa Mißerfolg
6. p: abaa Mißerfolg
7. p: abaa Mißerfolg
8. p: abaa … Mißerfolg
maximal möglicher Aufwand bei Mißerfolg: length(t) . length(p) Vergleiche
Folie-1007
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung Mustererkennung (Fortsetzung)
Lässt sich die Suche beschleunigen?
Ja, da für den Test alle Zeichen von t
– bis zur Position des ersten Unterschieds zu p oder
– bis zum Ende von p (bei einem Treffer)
betrachtet worden sind.
Folie-1008
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung Mustererkennung (Fortsetzung)
Lässt sich die Suche beschleunigen?
Ja, da für den Test alle Zeichen von t
– bis zur Position des ersten Unterschieds zu p oder
– bis zum Ende von p (bei einem Treffer)
betrachtet worden sind.
Wird das Ergebnis der Untersuchung für jedes Zeichens von t gemerkt,
so muss jedes Zeichen nur einmal betrachtet werden.
Der maximale Aufwand beträgt dann nur: length(t) Vergleiche
Die Suche kann also um den Faktor length(p) beschleunigt werden.
Folie-1009
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung Mustererkennung (Fortsetzung)
Lässt sich die Suche beschleunigen?
Ja, da für den Test alle Zeichen von t
– bis zur Position des ersten Unterschieds zu p oder
– bis zum Ende von p (bei einem Treffer)
betrachtet worden sind.
Wird das Ergebnis der Untersuchung für jedes Zeichens von t gemerkt,
so muss jedes Zeichen nur einmal betrachtet werden.
Der maximale Aufwand beträgt dann nur: length(t) Vergleiche
Die Suche kann also um den Faktor length(p) beschleunigt werden.
Allerdings sind Vorarbeiten notwendig.
Für jedes gelesene Zeichen gibt es zwei Entscheidungsmöglichkeiten:
– Das Zeichen aus t passt zu dem von p als nächstes geforderten Zeichen.
Dann kann mit dem aktuellen Vergleich fortgefahren werden.
– Das Zeichen aus t passt nicht zu dem von p als nächstes geforderten Zeichen.
Dann muss der Vergleich neu begonnen werden.
Folie-1010
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung Mustererkennung (Fortsetzung)
Beispiel:
Falls bei der Suche nach abaa die ersten drei Zeichen eine Übereinstimmung ergeben haben
und beim Vergleich des vierten Zeichen in t ein b auftritt, dann ist folgende Sequenz in t
zuletzt betrachtet worden:
t: …abab????…
Und es gilt:
abab Es ist keine erfolgversprechende Fortsetzung möglich.
abab Es ist keine erfolgversprechende Fortsetzung möglich.
abab Es ist eine erfolgversprechende Fortsetzung möglich,
falls aa folgt.
Der Vergleich wird also fortgesetzt
mit dem nächsten Zeichen aus t: ?
und der Information,
dass zwei Zeichen bereits als richtig erkannt sind: ab
Folie-1011
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung Mustererkennung (Fortsetzung)
Benötigt werden also Regeln, die angeben, wie bei der Suche fortgefahren wird.
Diese Regeln haben die folgende Struktur:
Falls die ersten n Zeichen von p vorliegen und nun das Zeichen c gelesen wird:
dann werden anschließend m Zeichen als erkannt angenommen mit m {0, …, n+1}.
Diese Regeln sind spezifisch für das zu suchende Muster p.
Das Muster p ist immer dann gefunden, wenn m = length(p) gilt.
Folie-1012
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Problemstellung Mustererkennung (Fortsetzung)
Benötigt werden also Regeln, die angeben, wie bei der Suche fortgefahren wird.
Diese Regeln haben die folgende Struktur:
Falls die ersten n Zeichen von p vorliegen und nun das Zeichen c gelesen wird:
dann werden anschließend m Zeichen als erkannt angenommen mit m {0, …, n+1}.
Diese Regeln sind spezifisch für das zu suchende Muster p.
Das Muster p ist immer dann gefunden, wenn m = length(p) gilt.
Eine Möglichkeit, solche Regeln auszudrücken, bietet der – einigen Studierenden aus der
Veranstaltung Rechnerstrukturen bekannte – Moore-Automat. *)
*) Rechnerstrukturen: Foliensatz Synchrone Schaltwerke
Folie-1013
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Moore-Automat (Fortsetzung)
für die Suche nach dem Muster abaa
3
erkannt
Zeichen
4
erkannt
Zeichen
2
erkannt
Zeichen
a
b
bekanntes Beispiel: drei Zeichen aba sind erkannt
ist ein Zustand
ist ein Zustandsübergang bei Eingabe von xx
Folie-1014
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Moore-Automat (Fortsetzung)
für die Suche nach dem Muster abaa
3
erkannt
Zeichen
4
erkannt
Zeichen
2
erkannt
Zeichen
a
b
1
erkannt
Zeichen
0
erkannt
Zeichen
b aa
Übergänge, wenn die gesuchten Zeichen auftreten
Folie-1015
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Moore-Automat (Fortsetzung)
für die Suche nach dem Muster abaa
3
erkannt
Zeichen
4
erkannt
Zeichen
2
erkannt
Zeichen
a
b
1
erkannt
Zeichen
0
erkannt
Zeichen
b aa
Übergänge, wenn die gesuchten Zeichen nicht auftreten
b a
b
Folie-1016
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Moore-Automat (Fortsetzung)
für die Suche nach dem Muster abaa
3
erkannt
Zeichen
4
erkannt
Zeichen
2
erkannt
Zeichen
a
b
1
erkannt
Zeichen
0
erkannt
Zeichen
b aa
Übergänge und Ausgabe, wenn das gesamte Muster erkannt wurde
b a
b b
a
1
Ausgaben erfolgen im Moore-Automat beim Betreten eines Zustands
Folie-1017
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
3 4 2
a
b
1 0
b aa
Startzustand festlegen
b a
b b
a
1
Moore-Automat (Fortsetzung)
für die Suche nach dem Muster abaa
Folie-1018
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
3 4 2
a
b
1 0
b aa
nicht eingezeichnet:
b a
b b
a
1
Moore-Automat (Fortsetzung)
für die Suche nach dem Muster abaa
alle nicht im Muster p vorkommenden Zeichen führen immer zum Startzustand zurück
Folie-1019
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Moore-Automat (Fortsetzung)
für die Suche nach dem Muster abaa:
Mabaa = ( Q, 0, , , , )
Zustandmenge Q = { 0, 1, 2, 3, 4 }
Startzustand 0 Q
Eingabealphabet = { a, b } t mit t Alphabet des Textes t
Ausgabealphabet = { 1 } { } mit = leeres Wort
Ausgabefunktion : Q
mit 4) 1 und q) für alle q Q \ { 4 }
Zustandsüberführungsfunktion QQ
Folie-1020
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Moore-Automat (Fortsetzung)
Zustandsüberführungsfunktion QQ
Q 0 1 2 3 4
a 1 1 3 4 1
b 0 2 0 2 2
x t \{a, b} 0 0 0 0 0
3 4 2
a
b
1 0
b aa
b a
b b
a
1
Folie-1021
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Moore-Automat (Fortsetzung)
für die Suche nach dem Muster abaa:
Mabaa = ( Q, 0, , , , )
Zustandmenge Q = { 0, 1, 2, 3, 4 }
Startzustand 0 Q
Eingabealphabet = { a, b } t mit t Alphabet des Textes t
Ausgabealphabet = { 1 } { } mit = leeres Wort
Ausgabefunktion : Q
mit 4) 1 und q) für alle q Q \ { 4 }
Zustandsüberführungsfunktion QQ
Q 0 1 2 3 4
a 1 1 3 4 1
b 0 2 0 2 2
x t \{a, b} 0 0 0 0 0
Folie-1022
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Moore-Automat (Fortsetzung)
allgemeine Gestaltung von Mp = ( Q, 0, , , , )
Zustandmenge Q = { 0, …, length(p) } ergibt sich direkt aus der Länge von p
Startzustand ist immer 0 Q kein Zeichen erkannt
Eingabealphabet = p t
Ausgabealphabet immer = { 1 } { }
Ausgabefunktion : Q immer mit
length(p)) 1 und q) für alle q Q \ { length(p) }
Zustandsüberführungsfunktion …
Folie-1023
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Moore-Automat (Fortsetzung)
allgemeine Gestaltung von Mp = ( Q, 0, , , , )
Zustandmenge Q = { 0, …, length(p) } ergibt sich direkt aus der Länge von p
Startzustand ist immer 0 Q kein Zeichen erkannt
Eingabealphabet = p t
Ausgabealphabet immer = { 1 } { }
Ausgabefunktion : Q immer mit
length(p)) 1 und q) für alle q Q \ { length(p) }
Zustandsüberführungsfunktion wn sei der Anfang – die ersten n Zeichen – eines Wortes w
prefixes(w) sei die Menge aller Anfangsstücke eines Textes w,
also prefixes(w) = { w0, w1, w2, …, wn-1, w }
Beispiel: Für w = abaa sind
w0 = w1 = aw2 = abw3 = abaw4 = abaa
Also gilt:
prefixes(abaa) = { aababaabaa }
Folie-1024
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Moore-Automat (Fortsetzung)
allgemeine Gestaltung von Mp = ( Q, 0, , , , )
Zustandmenge Q = { 0, …, length(p) } ergibt sich direkt aus der Länge von p
Startzustand ist immer 0 Q kein Zeichen erkannt
Eingabealphabet = p t
Ausgabealphabet immer = { 1 } { }
Ausgabefunktion : Q immer mit
length(p)) 1 und q) für alle q Q \ { length(p) }
Zustandsüberführungsfunktion wn sei der Anfang – die ersten n Zeichen – eines Wortes w
prefixes(w) sei die Menge aller Anfangsstücke eines Textes w,
also prefixes(w) = { w0, w1, w2, …, wn-1, w }
suffixes(w) sei (analog) die Menge aller Endstücke eines Textes w
Beispiel: Für w = abaa gilt dann:
suffixes(abaa) = { aaabaaabaa }
Folie-1025
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Moore-Automat (Fortsetzung)
allgemeine Gestaltung von Mp = ( Q, 0, , , , )
Zustandmenge Q = { 0, …, length(p) } ergibt sich direkt aus der Länge von p
Startzustand ist immer 0 Q kein Zeichen erkannt
Eingabealphabet = p t
Ausgabealphabet immer = { 1 } { }
Ausgabefunktion : Q immer mit
length(p)) 1 und q) für alle q Q \ { length(p) }
Zustandsüberführungsfunktion wn sei der Anfang – die ersten n Zeichen – eines Wortes w
prefixes(w) sei die Menge aller Anfangsstücke eines Textes w,
also prefixes(w) = { w0, w1, w2, …, wn-1, w }
suffixes(w) sei (analog) die Menge aller Endstücke eines Textes w
Dann gilt QQ
…
Folie-1026
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Moore-Automat (Fortsetzung)
allgemeine Gestaltung von Mp = ( Q, 0, , , , )
Zustandmenge Q = { 0, …, length(p) } ergibt sich direkt aus der Länge von p
Startzustand ist immer 0 Q kein Zeichen erkannt
Eingabealphabet = p t
Ausgabealphabet immer = { 1 } { }
Ausgabefunktion : Q immer mit
length(p)) 1 und q) für alle q Q \ { length(p) }
Zustandsüberführungsfunktion wn sei der Anfang – die ersten n Zeichen – eines Wortes w
prefixes(w) sei die Menge aller Anfangsstücke eines Textes w,
also prefixes(w) = { , w1, w2, …, wn-1, w }
suffixes(w) sei (analog) die Menge aller Endstücke eines Textes w
Dann gilt QQ
(n,c) n’ mit n’ = length(wmax)
und wmax ist längstes Wort in suffixes(pn c) prefixes(p)
Insbesondere gilt daher immer: (n,x) 0 für alle x t \ p,
da suffixes(pn x) prefixes(p) = {} mit length() = 0 ist.
Folie-1027
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Moore-Automat (Fortsetzung)
Zustandsüberführungsfunktion …
Dann gilt QQ
(n,c) n’ mit n’ = length(wmax)
und wmax ist längstes Wort in suffixes(pn c) prefixes(p)
Beispiel: Für w = abaa gilt:
prefixes(abaa) = { aababaabaa }
suffixes(abab) = { babbababab }
length(ab) = 2
bisher wurde erkannt: aba
Q 0 1 2 3 4
a 1 1 3 4 1
b 0 2 0 2 2
x t \{a, b} 0 0 0 0 0
abab
Folie-1028
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Implementierung der Mustererkennung
Als Vorbereitung für die Mustererkennung muss also zunächst der
passende Moore-Automat Mp erzeugt werden.
Diese Erzeugung von Mp ist abhängig von dem zu suchenden Muster p,
aber unabhängig von dem zu durchsuchenden Text t.
Der Text t wird anschließend als Eingabe für Moore-Automat Mp benutzt.
– einfache Suche: erfolgreich, wenn der Automat die erste Ausgabe von 1 erzeugt.
– Zählen der Vorkommen von p in t: Summe aller Ausgaben bilden
p Mp
Folie-1029
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Überlegungen zur Implementierung der Erzeugung des Automaten Mp (Fortsetzung)
Zustandmenge: Q = { 0, …, length(p) }
Da die Zustände fortlaufend durch natürliche Zahlen bezeichnet werden, wird keine besondere
Datenstruktur zur Verwaltung benötigt. Variablen des Typs int sind ausreichend für die
Ablage von Zuständen.
Startzustand ist immer der Zustand 0, also ein eindeutiger int-Wert.
Eingabealphabet: = p t
Für alle Elemente von p müssen Zustandsübergänge bestimmt werden, so dass p explizit
ermittelt und gespeichert werden muss. Das kann einfach geschehen, indem jedes Zeichen aus
p zu einer Menge hinzugefügt wird:
Set
Ausgabealphabet: = { 1 } { }
Das einfache Ausgabealphabet muss nicht explizit implementiert werden.
Ausgabefunktion: : Q
Die Ausgabefunktion muss nicht explizit implementiert werden, da die einzige Ausgabe immer
für genau den einen Zustand length(p) erfolgt.
Folie-1030
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Überlegungen zur Implementierung der Erzeugung des Automaten Mp (Fortsetzung)
Zustandsüberführungsfunktion: QQ
Für die Umsetzung des Algorithmus wird die Prefix-Menge zu p benötigt. Diese kann einfach
durch wiederholtes Aufrufen der Methode substring der Klasse String bestimmt werden:
Set
Folie-1031
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Überlegungen zur Implementierung der Erzeugung des Automaten Mp (Fortsetzung)
Zustandsüberführungsfunktion: QQ
Für die Umsetzung des Algorithmus wird die Prefix-Menge zu p benötigt. Diese kann einfach
durch wiederholtes Aufrufen der Methode substring der Klasse String bestimmt werden:
Set
Das Interface Set gibt Methoden für eine Menge vor.
Set ist ein Interface aus dem Paket java.util.
Set
repräsentiert werden.
Folie-1032
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Interface java.util.Set
Eine Auswahl aus den durch das Interface Collection vorgegebenen Methoden:
boolean add(E e) – fügt e zu Menge hinzu, falls e noch nicht enthalten ist
boolean addAll(Collection extends E> c) – fügt alle Inhalte von c zu der Menge hinzu,
die noch nicht enthalten sind (Vereinigung)
boolean contains(Object o) – gibt true zurück, falls o enthalten ist
boolean isEmpty() – gibt true zurück, falls die Menge leer ist
boolean remove(Object o) – löscht o aus der Menge, falls o enthalten ist; gibt true zurück,
falls gelöscht wurde
boolean removeAll(Collection> c) – löscht alle Inhalte von c aus der Menge, die in
dieser enthalten sind
boolean retainAll(Collection> c) – belässt alle Elemente in der Menge, die auch in c
enthalten sind (Durchschnitt)
int size() – gibt die Anzahl der Elemente in der Menge zurück
Iterator
Menge iteriert werden kann
Folie-1033
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Interface java.util.Set
Deklaration des Rückgabetyps von Methoden:
boolean addAll( Collection extends E> c )
Die zulässigen Typargumente werden eingeschränkt durch: ? extends E
Erlaubt sind nur Typen, die E erweitern oder implementieren.
Aufgrund der durch Vererbung/Implementierung gegebenen Typkompatibilität reicht es aus,
wenn die von der Oberklasse von E sichergestellten Methoden verfügbar sind.
Da der Typ der Unterklasse selbst in der Deklaration der Signatur nicht benötigt wird,
wird die Wildcard ? als Platzhalter verwendet.
Erinnerung: Für Typeinschränkungen gilt, dass T selbst die Bedingung extends T erfüllt.
Folie-1034
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Überlegungen zur Implementierung der Erzeugung des Automaten Mp (Fortsetzung)
Zustandsüberführungsfunktion: QQ
Für die Umsetzung des Algorithmus wird die Prefix-Menge zu p benötigt. Diese kann einfach
durch wiederholtes Aufrufen der Methode substring der Klasse String bestimmt werden:
Set
Weiterhin werden Suffix-Mengen zu wechselnden Texten benötigt. Diese können ebenfalls
durch wiederholtes Aufrufen der Methode substring bestimmt werden. Allerdings muss das
längste Endstück von pn c bestimmt werden, das in prefixes(p) ist. Daher werden die Anfangs-
stücke nach ihrer Länge sortiert in einer Liste abgelegt, so dass eine Überprüfung direkt mit
den längeren Endstücken beginnen kann:
List
Folie-1035
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Überlegungen zur Implementierung der Erzeugung des Automaten Mp (Fortsetzung)
Zustandsüberführungsfunktion: QQ
Für die Umsetzung des Algorithmus wird die Prefix-Menge zu p benötigt. Diese kann einfach
durch wiederholtes Aufrufen der Methode substring der Klasse String bestimmt werden:
Set
Weiterhin werden Suffix-Mengen zu wechselnden Texten benötigt. Diese können ebenfalls
durch wiederholtes Aufrufen der Methode substring bestimmt werden. Allerdings muss das
längste Endstück von pn c bestimmt werden, das in prefixes(p) ist. Daher werden die Anfangs-
stücke nach ihrer Länge sortiert in in einer Liste abgelegt, so dass eine Überprüfung direkt mit
den längeren Endstücken beginnen kann:
List
Das Interface List gibt Methoden für eine Liste vor.
List ist ein Interface aus dem Paket java.util.
List
repräsentiert werden.
Folie-1036
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Interface java.util.List
Das Interface gibt neben den für das Interface Collection vorgegebenen Methoden zusätzlich solche
Operationen vor, die sich an der Listenstruktur orientieren.
E get(int index) – gibt den Inhalt der Liste an der Position index zurück
int indexOf(Object o) – gibt die Position des ersten Vorkommens von o in der Liste zurück;
falls o nicht enthalten ist, wird -1 zurückgegeben
int lastIndexOf(Object o) – gibt die Position des letzten Vorkommens von o in der Liste
zurück; falls o nicht enthalten ist, wird -1 zurückgegeben
E set(int index, E element) – ersetzt das Element an der Position index durch e
List
Anmerkung:
Die Semantik der aus dem Interface Collection übernommenen Methoden ist der sequentiellen
Datenstruktur der Liste angepasst, beispielsweise gilt:
boolean add(E e) – fügt e am Ende der Liste an
Folie-1037
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Überlegungen zur Implementierung der Erzeugung des Automaten Mp (Fortsetzung)
Zustandsüberführungsfunktion: QQ
Für die Umsetzung des Algorithmus wird die Prefix-Menge zu p benötigt. Diese kann einfach
durch wiederholtes Aufrufen der Methode substring der Klasse String bestimmt werden:
Set
Weiterhin werden Suffix-Mengen zu wechselnden Texten benötigt. Diese können ebenfalls
durch wiederholtes Aufrufen der Methode substring bestimmt werden. Allerdings muss das
längste Endstück von pn c bestimmt werden, das in prefixes(p) ist. Daher werden die Anfangs-
stücke nach ihrer Länge sortiert in einer Liste abgelegt, so dass eine Überprüfung direkt mit
den längeren Endstücken beginnen kann:
List
Die Überführungsfunktion ist eine Abbildung, die jedem Zustand für jedes Zeichen einen
Folgezustand zuordnet. Für die Implementierung bietet sich daher eine Klasse an, die das
Map-Interface implementiert, das solche Abbildungen beschreibt. Die Realisierung erfolgt
durch zwei Abbildungen Map
Das «äußere» Abbildung (Map) ordnet jedem Zustand (Integer) eine Abbildung (Map) zu,
die jedem Eingabezeichen (Character) den entsprechenden Nachfolgezustand (Integer)
zuordnet.
Folie-1038
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Überlegungen zur Implementierung der Erzeugung des Automaten Mp (Fortsetzung)
Zustandsüberführungsfunktion: QQ
Für die Umsetzung des Algorithmus wird die Prefix-Menge zu p benötigt. Diese kann einfach
durch wiederholtes Aufrufen der Methode substring der Klasse String bestimmt werden:
Set
Weiterhin werden Suffix-Mengen zu wechselnden Texten benötigt. Diese können ebenfalls
durch wiederholtes Aufrufen der Methode substring bestimmt werden. Allerdings muss das
längste Endstück von pn c bestimmt werden, das in prefixes(p) ist. Daher werden die Anfangs-
stücke nach ihrer Länge sortiert in einer Liste abgelegt, so dass eine Überprüfung direkt mit
den längeren Endstücken beginnen kann:
List
Die Überführungsfunktion ist eine Abbildung, die jedem Zustand für jedes Zeichen einen
Folgezustand zuordnet. Für die Implementierung bietet sich daher eine Klasse an, die das
Map-Interface implementiert, das solche Abbildungen beschreibt. Die Realisierung erfolgt
durch zwei Abbildungen Map
Das «äußere» Abbildung (Map) ordnet jedem Zustand (Integer) eine Abbildung (Map) zu,
die jedem Eingabezeichen (Character) den entsprechenden Nachfolgezustand (Integer)
zuordnet.
Überführungen in den Zustand 0, die u.a. für alle t \ p vorgenommen werden müssen,
werden nicht in die Abbildung aufgenommen.
Folie-1039
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Überlegungen zur Implementierung der Erzeugung des Automaten Mp (Fortsetzung)
Zustandsüberführungsfunktion: QQ
Implementierung als Map
3 4 2
a
b
1 0
b aa
b a
b b
a
1
Abbildung Integer Map
Abbildungen Character Integer
Beispiel:
0
1
2
3
4
a 1
a
b
1
2
a 3
a
b
4
2
a
b
1
2
Folie-1040
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Interface java.util.Map
Das Interface gibt Methoden vor, die den Umgang mit einer partiellen Abbildung fK V
ermöglichen, beispielsweise:
boolean containsKey(Object key) – gibt true zurück, falls key ein Wert aus der
Zielmenge V zugeordnet wurde
boolean containsValue(Object value) – gibt true zurück, falls value in der Zielmenge der
Abbildung enthalten ist
V get(Object key) – gibt den Wert der Zielmenge zurück, der key zugeordnet ist; falls key
kein Wert zugeordnet ist, wird null zurückgegeben
Set
V put(K key, V value) – ordnet key den Wert value zu
V remove(Object key) – entfernt das key zugeordnete Element der Zielmenge, falls ein
solches existiert
boolean remove(Object key, Object value) – entfernt eine Zuordnung aus der Abbildung
V replace(K key, V value) – ersetzt die Zuordnung zu key durch value nur dann, wenn
key bereits ein Element der Zielmenge zugeordnet ist
Folie-1041
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Implementierung der Erzeugung des Automaten Mp
public static Set
{
Set
for ( int i = 0; i < s.length(); i++ )
{
result.add( s.charAt( i ) );
}
return result;
}
Set ist das bereits bekannte Interface aus dem Paket java.util. Set
eine Menge von Zeichen, die durch Objekte des Typs Character repräsentiert werden.
java.util.HashSet ist eine Klasse, die das Interface Set implementiert.
Die Implementierung basiert auf einer Hashtable (und wird später genauer betrachtet).
new HashSet<>() erzeugt ein Objekt dieser Klasse, das als Elemente Objekte erwartet,
die kompatibel zu Character sind.
Die Methode charAt bestimmt das Zeichen an der als Argument übergebenen Position des
String-Objekts.
Da result eine Menge realisiert, werden auch mehrfach hinzugefügte Zeichen nur einmal
gespeichert.
Folie-1042
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Implementierung der Erzeugung des Automaten Mp (Fortsetzung)
private static Set
{
Set
for( int i = 0; i <= s.length(); i++ )
{
result.add( s.substring( 0, i ) );
}
return result;
}
Die Methode substring( int from, int to ) liefert den Ausschnitt des Textes im Bereich
(einschließlich) from bis (ausschließlich) to.
Da immer größere Teiltexte gebildet werden, können hier keine doppelten Einträge in die
Menge result erfolgen.
Folie-1043
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Implementierung der Erzeugung des Automaten Mp (Fortsetzung)
private static List
{
List
for( int i = 0; i < s.length(); i++ )
{
result.add( s.substring( i, s.length() ) );
}
return result;
}
List ist das bereits bekannte Interface aus dem Paket java.util.
java.util.LinkedList ist eine Klasse aus dem Paket , die das Interface Set implementiert.
Es werden die Endstücke des Textes s so gebildet, dass zunächst die längeren und
anschließend kürzer werdende Texte erzeugt werden.
Durch das Einsortieren in eine Liste liefert die Iteration über die Liste ebenfalls zunächst die
längeren und anschließend die kürzer werdenden Endstücke.
Folie-1044
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Implementierung der Erzeugung des Automaten Mp (Fortsetzung)
private static Map
{
Map
Set
Set
for ( String prefix : prefixes ) {
for ( char c : tokens ) {
String continuation = prefix + c;
List
for ( String suffix : suffixes ) {
if ( prefixes.contains( suffix ) ) {
if ( ! transitionTable.containsKey( prefix.length() ) ) {
transitionTable.put(
prefix.length(), new HashMap
}
transitionTable.get( prefix.length() ).put( c, suffix.length());
break;
}
}
}
}
return transitionTable;
}
Initialisierungen
bricht Schleife ab
Folie-1045
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kontrolle von Schleifen mit break
Die break-Anweisung ermöglicht das Abbrechen der Ausführung von Schleifen.
Beispiel break:
while ( true )
{
account = requestAccountFromUser();
password = requestPasswordFromUser();
if ( loginOk( account, password ) )
{
break;
}
}
Funktionsweise break:
– Die Ausführung der break-Anweisung unterbricht die Ausführung
der (innersten) umgebenden Schleife .
– Die Programmausführung wird mit der ersten Anweisung hinter der Schleife fortgesetzt.
Folie-1046
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Implementierung der Erzeugung des Automaten Mp (Fortsetzung)
private static Map
{
Map
Set
Set
for ( String prefix : prefixes ) {
for ( char c : tokens ) {
String continuation = prefix + c;
List
for ( String suffix : suffixes ) {
if ( prefixes.contains( suffix ) ) {
if ( ! transitionTable.containsKey( prefix.length() ) ) {
transitionTable.put(
prefix.length(), new HashMap
}
transitionTable.get( prefix.length() ).put( c, suffix.length());
break;
}
}
}
}
return transitionTable;
}
new HashMap<>() erzeugt ein Objekt der Klasse, das
als Elemente Objekte erwartet, die kompatibel zu
Integer und Map
Folie-1047
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Implementierung der Erzeugung des Automaten Mp (Fortsetzung)
private static Map
{
Map
Set
Set
for ( String prefix : prefixes ) {
for ( char c : tokens ) {
String continuation = prefix + c;
List
for ( String suffix : suffixes ) {
if ( prefixes.contains( suffix ) ) {
if ( ! transitionTable.containsKey( prefix.length() ) ) {
transitionTable.put(
prefix.length(), new HashMap
}
transitionTable.get( prefix.length() ).put( c, suffix.length());
break;
}
}
}
}
return transitionTable;
}
Set erweitert das Interface java.util.Iterable.
Jede Menge lässt sich also mit einem Iterator durchlaufen.
Die for-each-Schleife nutzt – wenn möglich – implizit
einen Iterator, wenn die durchlaufene Datenstruktur das
Interface java.util.Iterable erweitert.
Folie-1048
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Implementierung der Erzeugung des Automaten Mp (Fortsetzung)
private static Map
{
Map
Set
Set
for ( String prefix : prefixes ) {
for ( char c : tokens ) {
String continuation = prefix + c;
List
for ( String suffix : suffixes ) {
if ( prefixes.contains( suffix ) ) {
if ( ! transitionTable.containsKey( prefix.length() ) ) {
transitionTable.put(
prefix.length(), new HashMap
}
transitionTable.get( prefix.length() ).put( c, suffix.length());
break;
}
}
}
}
return transitionTable;
}
geordnete
suffix-Menge erzeugen
das zuerst gefundene passende Endstück
ist aufgrund der Konstruktion auch immer
das längste
Folie-1049
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Implementierung der Erzeugung des Automaten Mp (Fortsetzung)
private static Map
{
Map
Set
Set
for ( String prefix : prefixes ) {
for ( char c : tokens ) {
String continuation = prefix + c;
List
for ( String suffix : suffixes ) {
if ( prefixes.contains( suffix ) ) {
if ( ! transitionTable.containsKey( prefix.length() ) ) {
transitionTable.put(
prefix.length(), new HashMap
}
transitionTable.get( prefix.length() ).put( c, suffix.length());
break;
}
}
}
}
return transitionTable;
}
– da prefix das bereits gefundene Anfangsstück ist,
befindet sich der Automat im Zustand prefix.length()
– da suffix das gefundene Anfangsstück für die
Fortsetzung ist, wechselt der Automat in den Zustand
suffix.length()
Folie-1050
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Überlegungen zur Implementierung der Mustererkennung mit dem Automaten Mp
Ziel: Überprüfung des Inhalts eines Textes
Suche nach dem Muster beginnt im Startzustand 0 mit dem ersten Zeichen aus des Textes.
Der Folgezustand wird aus der mit generatetransitionTable angelegten Tabelle ermittelt:
– Ist in der Tabelle ein Folgezustand verfügbar, so wird mit diesem weitergearbeitet.
– Ist in der Tabelle kein Folgezustand verfügbar, so wird mit dem Zustand 0 weitergearbeitet.
– Wird der Endzustand length(p) erreicht, so wurde das Muster p gefunden.
Verschiedene Varianten:
– Feststellen, an welcher Stelle des Textes das Muster p erstmals vorkommt:
int containsAt( String pattern, String text )
– Prüfen, ob das Muster p mindestens einmal im Text vorkommt:
boolean contains( String pattern, String text )
– Zählen, wie häufig das Muster p im Text vorkommt:
int count( String pattern, String text )
Folie-1051
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Implementierung der Mustererkennung mit dem Automaten Mp
public static int containsAt( String p, String text )
{
Map
int state = 0;
final int FINALSTATE = p.length();
for ( int position = 0; position < text.length(); position++ ) {
if ( transitionTable.containsKey( state )
&& transitionTable.get( state ).containsKey( text.charAt( position ) ) ) {
state = transitionTable.get( state ).get( text.charAt( position ) );
if ( state == FINALSTATE )
{
return position - p.length() + 1;
}
} else {
state = 0;
}
}
return -1;
}
Muster nicht gefunden
Korrektur auf Anfangsposition
des gefundenen Musters
Folie-1052
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Implementierung der Mustererkennung mit dem Automaten Mp (Fortsetzung)
public static boolean contains( String p, String text )
{
return containsAt( p, text ) != -1;
}
Folie-1053
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Implementierung der Mustererkennung mit dem Automaten Mp (Fortsetzung)
public static int count( String p, String text )
{
Map
int quantity = 0;
int state = 0;
final int FINALSTATE = p.length();
for ( int position = 0; position < text.length(); position++ ) {
if ( transitionTable.containsKey( state )
&& transitionTable.get( state ).containsKey( text.charAt( position ) ) ) {
state = transitionTable.get( state ).get( text.charAt( position ) );
if ( state == FINALSTATE ) {
quantity++;
}
} else {
state = 0;
}
}
return quantity;
}
Suche läuft weiter, kein return
Folie-1054
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zusammenfassung
Das Beispiel Mustererkennung zeigt,
dass auch die Lösung einer trivial erscheinenden Aufgabe eventuell noch optimiert werden
kann,
dass eine formale Beschreibung als Moore-Automat eine präzise Spezifikation des Verhaltens
einer Methode darstellt,
dass die einfache Umsetzung des Automaten weitgehend auf der Basis vorhandener Klassen
erfolgen kann,
dass trotzdem der implementierte Algorithmus zum Aufbau der Überführungsfunktion des
Automaten von der formalen Beschreibung abweichen kann, um Laufzeit und Speicherbedarf
zu optimieren:
– Endstücke werden in einer (geordneten) Liste abgelegt,
– Übergänge in den Zustand 0 werden nicht explizit in die Abbildung aufgenommen.
Folie-1055
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Mustererkennung
(siehe Folie 1002)
Nach Durcharbeiten des Kapitels Mustererkennung sollten
die teilnehmenden Studierenden nun
den Algorithmus zur Erkennung von Mustern in Texten kennen und erklären können,
die Implementierung des Algorithmus zur Erkennung von Mustern in Texten erklären können,
den Gebrauch der Bibliotheksinterfaces java.util.Set, java.util.List und java.util.Map
kennen,
den Gebrauch der Bibliotheksklassen java.util.HashSet, java.util.LinkedList und
java.util.HashMap kennen,
generische Klassen nutzen können.
Folie-1056
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen, Algorithmen
und Programmierung 1 (DAP 1)
Fakultät für Informatik
Wintersemester 2019/20
Stefan Dissmann
Ausnahmebehandlung und Zugriff auf Dateien
Folie-1057
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Ausnahmebehandlung
Nach Durcharbeiten des Kapitels Ausnahmebehandlung sollen
die teilnehmenden Studierenden
die Vorteile des Konzepts der Ausnahmebehandlung kennen und erklären können,
Ausnahmeklassen anlegen können,
Ausnahme-Objekte erzeugen und werfen können,
Ausnahme-Objekte fangen und verarbeiten können,
Checked Exceptions und Unchecked Exceptions unterscheiden und einsetzen können,
Grundlagen des Umgangs mit Dateien in Java kennen.
Folie-1058
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klassenbibliotheken der Java Platform
Java stellt zusammen mit dem Compiler bereits viele Hundert Klassen bereit.
Einige sind im Rahmen dieser Vorlesung schon vorgestellt worden:
String, Math, Object, HashSet, HashMap, LinkedList
Insbesondere stehen auch geeignete Datenstrukturen bereit.
Eine Liste wie DoublyLinkedList muss also nicht von jedem Entwickler selbst neu gestaltet
werden, sondern es wird in der Regel die bereits getestete und erprobte Implementierung der
Java Platform benutzt.
Teilweise stehen auch verschiedene Implementierungen der gleichen Datenstruktur zur
Verfügung, die sich dann in einzelnen Eigenschaften – beispielsweise bezüglich der Laufzeit
von bestimmten Operationen – unterscheiden:
– LinkedList
näheren Ende aus bis zum gewünschten Index.
– ArrayList
gewünschten Index zu, dafür benötigt die Methode add einen längeren
Zeitraum.
Die Dokumentation findet sich unter:
http://docs.oracle.com/javase/8/docs/api/
Die gängigen Datenstrukturen finden sich im Paket java.util.
Folie-1059
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel – Lesen von Werten aus einer Datei
Paket: java.io
Klasse File
– verwaltet Metainformationen zu Dateien:
Name, Pfad, Zugriffsrechte, Größe, Änderungsdatum, …
– ermöglicht das Ändern einiger dieser Eigenschaften
– ein File-Objekt wird zum Zugriff auf den Inhalt einer Datei nicht unbedingt benötigt
Stream
– ist ein Datenstrom, also eine Folge von Zeichen
– muss nicht unbedingt eine Datei sein
Klasse InputStreamReader
verwaltet einen nur lesbaren Stream von Zeichen
Klasse FileReader extends InputStreamReader
– liest die Zeichen aus einer Datei, die beim Anlegen eines FileReader-Objekts angegeben
werden muss
– ermöglicht den Zugang zu den Inhalten einer Datei
Folie-1060
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Java-Programme und ihre Umgebung
bisher betrachtet:
Programme, die während der Ausführung Ergebnisse erzeugen,
die nach der Ausführung verloren sind.
Das ist nicht der Normalfall.
übliche Anwendungen:
Ergebnisse einer Ausführung bleiben erhalten und
können bei späteren Ausführungen wiederverwendet werden:
Die Daten werden dauerhaft (persistent) gespeichert,
beispielsweise als Dateien.
aber:
Dateien werden durch das Betriebssystem verwaltet!
daher:
Bei der Ausführung besitzt das Programm nicht die alleinige Kontrolle.
Folie-1061
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Java-Programme und ihre Umgebung (Fortsetzung)
Folge:
zuvor geprüfte Randbedingungen bleiben nicht sicher erhalten:
if ( Datei ist vorhanden )
{
while ( ! Ende von Datei )
{
lese und verarbeite Daten
}
}
Gründe für ein Scheitern des Lesens:
– Strom der Festplatte fällt aus.
– Netzwerkverbindung zur Festplatte wird getrennt.
– Lesefehler der Festplatte.
Konsequenz:
Es wird ein Mechanismus benötigt, der die Weiterarbeit des Programms ermöglicht,
obwohl ein Problem aufgetreten ist, dessen Ursache außerhalb des Programms liegt.
kann in jedem Durchlauf
scheitern
Folie-1062
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Java-Klassen und ihre Benutzung
bisher betrachtet:
In DAP 1 wurden bisher Klassen erstellt, die anschließend selbst genutzt
wurden. Das ist nicht der Normalfall.
üblicher Einsatz:
Der Entwickler einer Klasse ist an deren Benutzung nicht beteiligt.
daher:
Der Entwickler einer Klasse kann die zukünftigen Einsatzbereiche der von ihm
erstellten Klasse nicht vorhersehen.
Er plant ein aus seiner Sicht vernünftiges Verhalten, kann aber nie sicher sein,
– dass Argumente die vorgesehenen Werte enthalten und
– dass von ihm als fehlerhaft betrachtete Situationen in bestimmten
Nutzungsszenarien doch möglich sein sollen.
Folie-1063
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Java-Klassen und ihre Benutzung (Fortsetzung)
Folge:
Der Entwickler kann nicht abschätzen, ob ungewöhnliche Situationen beim Aufruf einer
Methode gewünscht oder fehlerhaft sind.
ungewöhnliche Aufrufe für eine Liste könnten zum Beispiel sein:
– removeFirst() für eine leere Liste
– add( null )
– get( -1 )
Konsequenz:
Es wird ein Mechanismus benötigt, der
– einerseits eine solche ungewöhnliche Aufrufsituation signalisiert und
– andererseits trotz einer solchen Situation auch die Weiterarbeit des Programms ermöglicht.
Folie-1064
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Ausnahmebehandlung
Ausnahmen sind ein Konzept, mit dem Methoden während der Laufzeit ungewöhnliche
Situationen (eben: Ausnahmesituationen) anzeigen können.
Die Behandlung einer angezeigten Ausnahme kann dann in der aufrufenden Methode erfolgen.
Probleme und damit Ausnahmen treten in verschiedenen Varianten auf:
– als Ausnahmen, die von der aufrufenden Methode behandelt werden können,
– als Ausnahmen, die von der aufrufenden Methode behandelt werden müssen,
– als schwere Fehler, die zu immer einem Abbruch des Programms führen.
Folie-1065
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Ausnahmeklassen
Eine Ausnahmeklasse ist eine Klasse, die von der Klasse Throwable erbt.
Ausnahmeklassen bilden eine Klassenhierarchie,
für die die üblichen Vererbungs- und Kompatibilitätsregeln gelten.
Ein Objekt einer Ausnahmeklasse kann alternativ zu dem im Methodenkopf deklarierten und
durch return bestimmten Rückgabewert zurückgegeben werden.
Die Möglichkeit der Rückgabe eines Objekts einer Ausnahmeklasse kann zusätzlich im
Methodenkopf deklariert werden.
Die Rückgabe eines Objekts einer Ausnahmeklasse wird im Methodenrumpf durch eine
spezielle Anweisung ausgelöst.
Terminologie:
– Das Zurückgeben einer Ausnahme wird als Werfen bezeichnet.
– Sowohl die Ausnahmeklasse als auch das Objekt einer solchen Klasse werden
(ungenau) als Ausnahme bezeichnet.
Folie-1066
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Hierarchie der Ausnahmeklassen
Throwable
Exception
RuntimeException
Error
… …
…
schwere Fehler
NullPointerException
Ausnahme muss
behandelt werden
Ausnahme kann
behandelt werden
ArithmeticException
Folie-1067
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Anlegen einer Ausnahmeklasse
public class NoElementException
extends Exception
{}
public class WrongIndexException
extends RuntimeException
{}
Die Klasse NoElementException erbt von der Klasse Exception
und kann daher benutzt werden, um ein Ausnahme-Objekt zu erzeugen.
Die Klasse WrongIndexException erbt von der Klasse RuntimeException
und kann daher benutzt werden, um ein Ausnahme-Objekt zu erzeugen.
In vielen Fällen werden im Rumpf einer Ausnahmeklasse keine Attribute oder Methoden
deklariert, da das Vorliegen eines Objekts der Klasse selbst ausreichende Informationen für
die Behandlung der Ausnahme bietet.
Die Klasse Exception stellt einige Konstruktoren bereit, u.a.:
public Exception( String message )
Jedes Ausnahme-Objekt bietet also die Möglichkeit, zusätzliche Informationen in Form eines
Textes abzulegen, indem ein geeigneter eigener Konstruktor erstellt wird.
Folie-1068
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Checked Exceptions
public class NoElementException
extends Exception
{}
Ausnahmeklassen, die Exception – aber nicht RuntimeException – erweitern, führen zu
Checked Exceptions.
Auf Checked Exceptions muss im Programmtext «reagiert» werden.
Der Compiler erzwingt entsprechende Anweisungen.
Kann eine Methode eine Checked Exception werfen, so muss sie dieses in ihrem Kopf
durch eine throws-Angabe anzeigen.
Folie-1069
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Checked Exceptions (Fortsetzung)
In der Klasse DoublyLinkedList
public T removeFirst()
throws NoElementException
{
…
}
Die Methode removeFirst gibt im normalen Ablauf den Inhalt des gelöschten Elements
vom Typ T zurück, kann aber alternativ auch eine Checked Exception der Klasse
NoElementException werfen.
Die Typen der möglicherweise geworfenen Checked Exceptions werden als Liste von
Klassennamen hinter der Parameterliste hinter dem Schlüsselwort throws und
vor dem Rumpf der Methode aufgelistet.
Erinnerung: Die angegebenen Klassen müssen alle von Throwable erben.
Aufgabe der Ausnahme für die Methode removeFirst:
Zeigt an, dass kein erstes Element vorhanden war und daher
weder ein Element gelöscht werden
noch sein Inhalt zurückgegeben werden konnte.
Folie-1070
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Methodendeklaration
Syntaxdiagramm zu Methode
Die Bezeichnerliste hinter dem Schlüsselwort throws darf ausschließlich Namen von Klassen
enthalten, die (direkte oder indirekte) Unterklassen von Throwable sind.
Methodenkopf
Methodenrumpf
Bezeichnerlistethrows
Folie-1071
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Werfen einer Ausnahme
Implementierung der Methode removeFirst:
public T removeFirst() throws NoElementException
{
if ( !isEmpty() )
{
T result = first.getContent();
if ( first.hasSucc() )
{
first = first.disconnectSucc();
} else {
first = last = null;
}
size–;
return result;
} else {
throw new NoElementException();
}
}
Die Anweisung throw unterbricht die Ausführung der Methode.
Der Ablauf kehrt zur aufrufenden Methode zurück und liefert dieser das geworfene Ausnahme-
Objekt der Klasse NoElementException.
throws zeigt an, welche Typen ein
geworfenes Objekt besitzen kann
throw wirft ein Objekt, das
kompatibel mit den Angaben
im Kopf der Methode sein muss
Folie-1072
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Einsatz von Ausnahmen
Ausnahmeklassen sind Klassen, die von der Klasse Throwable erben.
Methoden zeigen eventuell durch die throws-Klausel im Kopf der Deklaration an,
Objekte welcher Ausnahmen sie werfen können.
Eine Methode liefert also immer nur
entweder einen Wert/ein Objekt des in der Deklaration angegebenen Rückgabetyps
oder ein Objekt von einer der in der Deklaration angegebenen Ausnahmeklassen.
Methoden, die Ausnahmen werfen, können daher sehr unterschiedliche Ergebnisse – reguläre
Rückgabe oder Ausnahme – an die aufrufende Methode liefern.
Idee des Konzepts:
– Kann eine Methode so ausgeführt werden, dass sie die Aufgabe erledigt, die bei ihrer
Entwicklung vorgesehen war, so liefert sie ihren Rückgabewert oder auch gar kein Ergebnis.
– Tritt eine Situation auf, für die der Entwickler der Methode ein sinnvolles Weiterarbeiten
nicht für möglich hält oder in der ein aus seiner Sicht vermutlich nicht brauchbares Ergebnis
entsteht, wirft die Methode ein Ausnahme-Objekt.
– Die Situationen, in denen eine Methode Ausnahme-Objekte wirft, muss der Entwickler der
Methode also bereits bei deren Implementierung erkennen und einarbeiten.
– Handelt es sich um eine Checked Exception, muss auch die aufrufende Methode die
Rückgabe eines Ausnahme-Objekts vorsehen.
Folie-1073
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Werfen einer Ausnahme (Fortsetzung)
auch möglich, aber unüblich und eher verwirrend:
public T removeFirst() throws Exception
{
if ( !isEmpty() )
{
T result = first.getContent();
if ( first.hasSucc() )
{
first = first.disconnectSucc();
} else {
first = last = null;
}
size–;
return result;
} else {
throw new NoElementException();
}
}
Auch für Ausnahmen gilt: Objekte der Unterklasse sind kompatibel zur Oberklasse.
Daher können Objekte von Unterklassen der hinter throws angegebenen Klassen
geworfen werden.
irgendeine Ausnahme wird geworfen
throw wirft ein Objekt einer
Unterklasse von Exception
signalisiert:
Folie-1074
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Unchecked Exceptions
public class WrongIndexException
extends RuntimeException
{}
Ausnahmeklassen, die RuntimeException erweitern, führen zu Unchecked Exceptions.
Unchecked Exceptions müssen im Programmtext nicht beachtet werden.
Allerdings können sie bei Bedarf genau so wie Checked Exceptions behandelt werden.
Kann eine Methode eine Unchecked Exception werfen, so muss sie dieses nicht anzeigen.
Folie-1075
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Unchecked Exceptions (Fortsetzung)
Weitere Beispiele für die Klasse DoublyLinkedList
public T get( int index )
{
…
}
Methode get:
– Für einen unzulässigen Index kann get kein Ergebnis liefern.
– Da null ein gültiger Inhalt eines Elements der Liste sein kann,
kann der Misserfolg des Aufrufs nicht über die Rückgabe von null angezeigt werden.
Daher soll in diesem Fall eine Unchecked Exception der Klasse WrongIndexException
geworfen werden.
keine throws-Angabe
Folie-1076
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Unchecked Exceptions (Fortsetzung)
Implementierung der Methode get:
public T get( int index )
{
if ( index >= 0 && index < size )
{
Element
for ( int i = 0; i < index; i++ )
{
current = current.getSucc();
}
return current.getContent();
} else {
throw new WrongIndexException();
}
}
Die Ausnahme kann geworfen werden, obwohl keine throws-Angabe vorliegt.
return- oder throw-Anweisung
beenden die Methode
Folie-1077
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Fangen von Ausnahmen
Konzept:
Die Situationen, in denen Ausnahmen eingesetzt werden,
sollen – im umgangssprachlichen Sinne – Ausnahmen und damit selten bleiben.
Das Auftreten von solchen Situationen hat in der Regel zur Folge, dass größere Abschnitte des
Programmtextes nicht sinnvoll weitergeführt werden können:
– Wenn das Lesen einer Datei unerwartet nicht mehr möglich ist, macht der Versuch einer
weiteren Verarbeitung der nicht gelesenen Daten keinen Sinn.
– Wenn aus einer Liste kein Wert abgefragt werden kann, muss die weitere Bearbeitung ohne
diesen Wert erfolgen
Das Berücksichtigen von Ausnahmen, die von aufgerufenen Methoden geworfen werden, muss
daher syntaktisch so erfolgen, dass
– der Programmtext für die wesentlichen Abläufe lesbar und verständlich bleibt und
– die vom Auftreten einer Ausnahme betroffenen Abläufe zusammenhängend und
gemeinsam behandelt werden können.
In Java erfolgt die Behandlung von Ausnahmen in der aufrufenden Methode innerhalb einer
try-catch-Struktur.
Terminologie:
Das Verarbeiten eines Ausnahme-Objekts wird als Fangen bezeichnet.
Folie-1078
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Fangen von Ausnahmen (Fortsetzung)
Beispiel:
try
{
double result = compute( list.get( i ) );
if ( result > 0 )
{
…
}
}
catch( WrongIndexException e )
{
System.out.println( “wrong index i: ” + i );
}
Innerhalb des try-Blocks wird versucht, alle Anweisungen auszuführen.
Wirft ein Methodenaufruf innerhalb eines try-Blocks ein Ausnahme-Objekt,
wird die Ausführung des try-Blocks abgebrochen.
Die Ausführung wird hinter dem try-Block fortgesetzt.
Der try-Block definiert also einen Bereich, dessen Ausführung beim Auftreten einer
Ausnahme nicht weiter sinnvoll ausgeführt werden kann.
hier kann eine Ausnahme auftreten
Folie-1079
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Fangen von Ausnahmen (Fortsetzung)
Beispiel:
try
{
double result = compute( list.get( i ) );
if ( result > 0 )
{
…
}
}
catch( WrongIndexException e )
{
System.out.println( “wrong index i: ” + i );
}
An einen try-Block können sich (mehrere) catch-Blöcke anschließen.
Die catch-Anweisung bestimmt, welcher Typ von Ausnahmen gefangen werden soll.
Ist im try-Block eine Ausnahme aufgetreten, so wird der Block hinter der
ersten catch-Anweisung ausgeführt, die das geworfene Ausnahme-Objekt fangen kann.
Da sich das Fangen am Typ des geworfenen Objekts orientiert, benötigen Ausnahmeklassen
meist keine zusätzlichen Attribute, um die Problemsituation zu beschreiben.
hier wird festgelegt, welche Ausnahmen an dieser
Position gefangen werden sollen
hier kann eine Ausnahme auftreten
Folie-1080
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Fangen von Ausnahmen (Fortsetzung)
Beispiel:
try
{
double result = compute( list.get( i ) );
if ( result > 0 )
{
…
}
}
catch( WrongIndexException e )
{
System.out.println( “wrong index i: ” + i );
}
Wird in einem try-Block keine Ausnahme geworfen, so werden die sich anschließenden
catch-Blöcke bei der Ausführung übersprungen.
Der Programmtext für die wesentlichen Abläufe befindet sich daher ausschließlich innerhalb
des try-Blocks.
Folie-1081
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Fangen von Ausnahmen (Fortsetzung)
Beispiel:
try
{
double result = compute( list.get( i ) );
if ( result > 0 )
{
…
}
}
catch( WrongIndexException e )
{}
Auch möglich sind leere catch-Blöcke:
Beim Auftreten einer Ausnahme wird der try-Block beendet,
die Ausnahme wird durch eine passende catch-Anweisung gefangen
und ist damit bearbeitet, da der folgende Block leer ist.
Es geht dann nur darum, den Programmtext zwischen dem Auftreten der Ausnahme und dem
Ende des try-Blocks zu überspringen.
Folie-1082
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Fangen von Ausnahmen (Fortsetzung)
Beispiel:
try
{
list.removeFirst();
double result = compute( list.get( i ) );
list.addFirst( result + eps );
}
catch( WrongIndexException e ) { … }
catch( NoElementException e ) { … }
Die beiden Methoden removeFirst und get können jede eine Ausnahme einer
anderen Klasse werfen.
Eine der beiden catch-Anweisungen fängt eines der möglicherweise geworfenen Objekte einer
dieser beiden Klassen und behandelt dann im folgenden Block die Ausnahmesituation.
catch-Blöcke, deren catch-Anweisung kein Ausnahme-Objekt fängt, werden übersprungen.
Sobald eine catch-Anweisung das Ausnahme-Objekt gefangen hat, wird der zugehörige Block
ausgeführt. Damit ist diese Ausnahme bearbeitet.
Nachfolgende catch-Anweisungen und -Blöcke werden daher übersprungen, da ja immer nur
genau ein Ausnahme-Objekt vorliegt und dieses bearbeitet ist.
Folie-1083
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Fangen von Ausnahmen (Fortsetzung)
Beispiel:
try
{
list.removeFirst();
double result = compute( list.get( i ) );
list.addFirst( result + eps );
}
catch( WrongIndexException | NoElementException e )
{ … }
Ausnahmen der Klassen WrongIndexException und
NoElementException werden mit der gleichen catch-Anweisung gefangen.
Das Symbol | kann als (umgangssprachliches) ODER gelesen werden.
Die Zahl der catch-Anweisungen und -Blöcke kann mit dieser Schreibweise verkürzt werden.
Folie-1084
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Fangen von Ausnahmen (Fortsetzung)
Beispiel:
try
{
list.removeFirst();
double result = compute( list.get( i ) );
list.addFirst( result + eps );
}
catch( WrongIndexException e ) { … }
catch( Exception e ) { … }
Da Exception die Oberklasse aller Ausnahmeklassen ist,
fängt die zweite catch-Anweisung alle möglicherweise geworfenen Ausnahme-Objekte,
die nicht vom Typ WrongIndexException sind.
(Diese werden durch die vorangehende catch-Anweisung bereits gefangen.)
Die Oberklasse steht stellvertretend für sich und ihre Unterklassen.
Die Zahl der benötigten catch-Blöcke kann so reduziert werden.
fängt alle noch nicht
gefangenen Ausnahmen
Folie-1085
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Fangen von Ausnahmen (Fortsetzung)
Beispiel:
try
{
list.removeFirst();
double result = compute( list.get( i ) );
list.addFirst( result + eps );
}
catch( Exception e ) { … }
catch( WrongIndexException e ) { … }
Eine Folge von catch-Anweisungen,
in der zunächst ein Fangen der Objekte der Oberklasse und
dann das Fangen von Objekten von Unterklassen erfolgt,
macht niemals einen Sinn, da die nachfolgenden catch-Anweisungen nie erreicht werden
können.
Folie-1086
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zusammenfassung: Grundlagen des Fangens von Ausnahmen
Der Bereich, in dem Ausnahmen gefangen werden sollen,
wird durch einen try-Block festgelegt.
Das Fangen einer Ausnahme erfolgt durch eine catch-Anweisung.
Eine gefangene Ausnahmen wird in dem auf die fangende catch-Anweisung folgenden Block
bearbeitet.
Das Fangen von Ausnahmen kann zusammengefasst werden durch
– die Kombination von zu selektierenden Klassen durch den Einsatz des |-Operators oder
– die Wahl einer Oberklasse als zu selektierende Klasse
in einer catch-Anweisung.
Folie-1087
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zusammenhang von Werfen und Fangen
Beispiel:
Kann eine Methode eine Checked Exception werfen und liegt also eine throws-Angabe vor
public T removeFirst() throws NoElementException { … }
so muss eine aufrufende Methode dieses Werfen berücksichtigen.
Variante mit Fangen und Bearbeiten:
public void call( int i )
{
try
{
double result = compute( list.removeFirst() );
if ( result > 0 )
{
…
}
}
catch( NoElementException e ) { … }
}
Folie-1088
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zusammenhang von Werfen und Fangen (Fortsetzung)
Beispiel:
Kann eine Methode eine Checked Exception werfen und liegt also eine throws-Angabe vor
public T removeFirst() throws NoElementException { … }
so muss eine aufrufende Methode dieses Werfen berücksichtigen.
Variante mit Weiterwerfen
public void call( int i ) throws NoElementException
{
double result = compute( list.removeFirst() );
if ( result > 0 )
{
…
}
}
Da die Methode call die möglicherweise von get geworfene Ausnahme nicht fängt,
aber ihrerseits ein Werfen dieser Ausnahme deklariert, fliegt die Ausnahme weiter als
Rückgabe der Methode call. In diesem Fall wird kein try-Block benötigt.
Folie-1089
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zusammenhang von Werfen und Fangen (Fortsetzung)
Beispiel:
auch möglich: Variante mit Fangen oder Weiterwerfen
public void call( int i ) throws NoElementException
{
try
{
double result = compute( list.removeFirst() );
check( list.get( i ) );
list.addFirst( result + eps );
if ( result > 0 )
{
…
}
}
catch( WrongIndexException e ) { … }
}
Folie-1090
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zusammenhang von Werfen und Fangen (Fortsetzung)
Eine aufrufende Methode muss Checked Exceptions fangen oder weiterwerfen.
Ist im Kopf einer aufgerufenen Methode eine Checked Exception einer Oberklasse
angegeben (siehe Folie 1069), so muss die aufrufende Methode sich um Ausnahmen dieser
Oberklasse kümmern
– auch dann, wenn tatsächlich nur das Objekte von Unterklassen geworfen werden.
Der Compiler überprüft, dass deklarierte Ausnahmen in den aufrufenden Methoden behandelt
werden. Erfolgt das notwendige Fangen oder Weiterwerfen nicht, meldet der Compiler einen
Fehler.
Folie-1091
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse RuntimeException *)
Unchecked Exceptions, die die Klasse RuntimeException
spezialisieren, können auch dann geworfen werden,
wenn sie nicht im Kopf der Methode deklariert sind.
Ausnahmen, die die Klasse RuntimeException
spezialisieren, müssen daher nicht von aufrufenden
Methoden behandelt werden.
Aufrufende Methoden können entsprechend diese
unerwartet aufgetretenen Ausnahmen ihrerseits
ohne Deklaration weiterwerfen.
RuntimeException-Objekte dienen in der Regel dazu,
Programmierfehler anzuzeigen.
Einige der bereits bekannten Ausnahmen zählen dazu:
– ArrayIndexOutOfBoundsException
– ArithmeticException
– NullPointerException
*) Der Name RuntimeException ist etwas verwirred, da alle Ausnahmen während der Laufzeit auftreten.
Exception
RuntimeException
…
Folie-1092
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klasse RuntimeException (Fortsetzung)
Die Möglichkeit, Unchecked Exceptions ohne
Angabe im Kopf der Deklaration zu werfen,
wurde in verschiedenen bisher vorgestellten
Methoden genau dazu ausgenutzt, um eine
nicht zu behandelnde Ausnahmesituation
anzuzeigen:
throw new IllegalStateException();
Da das Konzept des Fangens nicht bekannt war,
erfolgte nie eine weitere Bearbeitung.
Wird ein RuntimeException-Objekt nie gefangen,
so löst es beim Weiterleiten durch die main-Methode
einen Programmabbruch aus.
Es wird dann die StackTrace ausgegeben.
Exception
RuntimeException
…
Folie-1093
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Wiederholung – Lesen von Werten aus einer Datei
(siehe Folie 1059)
Paket: java.io
Klasse File
– verwaltet Metainformationen zu Dateien:
Name, Pfad, Zugriffsrechte, Größe, Änderungsdatum, …
– ermöglicht das Ändern einiger dieser Eigenschaften
– ein File-Objekt wird zum Zugriff auf den Inhalt einer Datei nicht unbedingt benötigt
Stream
– ist ein Datenstrom, also eine Folge von Zeichen
– muss nicht unbedingt eine Datei sein
Klasse InputStreamReader
verwaltet einen nur lesbaren Stream von Zeichen
Klasse FileReader extends InputStreamReader
– liest die Zeichen aus einer Datei, die beim Anlegen eines FileReader-Objekts angegeben
werden muss
– ermöglicht den Zugang zu den Inhalten einer Datei
Folie-1094
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel – Lesen von Werten aus einer Datei (Fortsetzung)
wichtige Methoden der Klasse FileReader
Konstruktoren:
public FileReader( String fileName ) throws FileNotFoundException *)
public FileReader( File file ) throws FileNotFoundException
öffnen die als Argument übergebene Datei
Leseoperation:
public int read() throws IOException
liest ein Zeichen aus der Datei und gibt es (als int-Wert) zurück
oder gibt -1 zurück, wenn das Ende der Datei ereicht ist
Schließen der Datei:
public void close() throws IOException
gibt die zugehörigen Ressourcen im umgebenden Betriebssystem frei
(= schließt den Stream)
*) FileNotFoundException ist eine Unterklasse von IOException
Folie-1095
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel – Lesen von Werten aus einer Datei (Fortsetzung)
Beispiel nur mit catch-Anweisung:
public static void showFile( String filename )
{
FileReader f = null;
try
{
f = new FileReader( filename );
int c = f.read();
while ( c != -1 ) {
System.out.print( (char)c );
c = f.read();
}
f.close();
}
catch ( IOException e )
{
System.out.println( “Datei nicht lesbar” );
if ( f != null ) {
try { f.close(); } catch ( IOException x ) {}
}
}
}
zeichenweises Lesen
Lesen des ersten Zeichens
Anlegen der Stream-Referenz
Erzeugen des Stream-Objekts
Ausgabe: Type-cast notwendig
Schließen des Streams
Folie-1096
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel – Lesen von Werten aus einer Datei (Fortsetzung)
Beispiel nur mit catch-Anweisung:
public static void showFile( String filename )
{
FileReader f = null;
try
{
f = new FileReader( filename );
int c = f.read();
while ( c != -1 ) {
System.out.print( (char)c );
c = f.read();
}
f.close();
}
catch ( IOException e )
{
System.out.println( “Datei nicht lesbar” );
if ( f != null ) {
try { f.close(); } catch ( IOException x ) {}
}
}
}
Abfangen der Ausnahme
Schließen des Streams
close kann Exception
werfen
Folie-1097
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel – Lesen von Werten aus einer Datei (Fortsetzung)
Beispiel nur mit catch-Anweisung:
public static void showFile( String filename )
{
FileReader f = null;
try
{
f = new FileReader( filename );
int c = f.read();
while ( c != -1 ) {
System.out.print( (char)c );
c = f.read();
}
f.close();
}
catch ( IOException e )
{
System.out.println( “Datei nicht lesbar” );
if ( f != null ) {
try { f.close(); } catch ( IOException x ) {}
}
}
}
close wird immer benötigt
Folie-1098
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel – Lesen von Werten aus einer Datei (Fortsetzung)
Beispiel mit finally-Block:
public static void showFile( String filename ) {
FileReader f = null;
try
{
f = new FileReader( filename );
int c = f.read();
while ( c != -1 ) {
System.out.print( (char)c );
c = f.read();
}
}
catch ( IOException e )
{
System.out.println( “Datei nicht lesbar” );
}
finally
{
if ( f != null ) {
try { f.close(); } catch (IOException x) {}
}
}
}
finally-Block wird
immer ausgeführt
Folie-1099
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel – Lesen von Werten aus einer Datei (Fortsetzung)
Beispiel mit Ressourcen-Liste:
public static void showFile( String filename )
{
try ( FileReader f = new FileReader( filename ) )
{
int c;
while ( ( c = f.read() ) != -1 )
{
System.out.print( (char)c );
}
}
catch ( IOException e )
{
System.out.println( “Datei nicht lesbar” );
}
}
In der Ressourcen-Liste hinter try können nur solche Objekte deklariert werden, die nach der
Abarbeitung des try-Blocks wieder geschlossen werden müssen.
Die Klassen dieser Objekte müssen das Interface java.io.Closeable implementieren.
so geöffnete Streams
werden immer geschlossen
Folie-1100
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Syntaxdiagramm zu try-catch-Block
try-catch-Block
Block
Block
finally
try ( )Initialisierungsliste
catch ( )Ausnahmeinitialisierung
Block
Folie-1101
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
gefangene Ausnahme-Objekte
catch-Anweisung:
catch ( IOException e ) { … }
Das gefangene Ausnahme-Objekt kann unter dem Namen e in dem folgenden Block
angesprochen werden.
Zum Beispiel kann eine Ausgabe der Inhalte des Objekts erfolgen:
catch ( IOException e ) { System.out.println( e.toString() ); }
Sind für das Ausnahme-Objekt weitere Methoden deklariert, so können diese eventuell benutzt
werden, um eine präzise Beschreibung des Fehlers zu ermöglichen.
Jede Ausnahmeklasse besitzt eine von Throwable geerbte Methode, die die noch geöffneten
Instanzen von Methoden zum Zeitpunkt des Werfens der Ausnahme ausgibt:
public void printStackTrace()
Also ist möglich:
catch ( IOException e ) { e.printStackTrace(); }
Folie-1102
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Mustererkennung mit dem Automaten Mp für eine Datei
(siehe Folie 1050)
Ziel: Überprüfung des Inhalts einer Datei
Suche nach dem Muster beginnt mit dem ersten Zeichen aus der Datei.
Der Folgezustand wird aus der mit generatetransitionTable angelegten Tabelle ermittelt;
die folgenden Zeichen werden einzeln aus der Datei gelesen.
Zwei (weitgehend bekannte) Varianten werden vorgestellt:
– Feststellen, an welcher Stelle der Datei das Muster p erstmals in der Datei vorkommt:
int containsAt( String pattern, String file )
– Zählen, wie häufig das Muster p in der Datei vorkommt:
int count( String pattern, String file )
Folie-1103
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Mustererkennung mit dem Automaten Mp für eine Datei (Fortsetzung)
public static int containsAt( String p, String file )
throws IOException
{
Map
int state = 0;
final int FINALSTATE = p.length();
int position = 0;
FileReader f = new FileReader( file );
int c = f.read();
while ( c != -1 ) {
position++;
if ( transitionTable.containsKey( state ) &&
transitionTable.get( state).containsKey( (char)c ) ) {
state = transitionTable.get( state ).get( (char)c );
if ( state == FINALSTATE ) {
return position – p.length() + 1;
}
} else {
state = 0;
}
c = f.read();
}
return -1;
}
analog zu read()
Folie-1104
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Mustererkennung mit dem Automaten Mp für eine Datei (Fortsetzung)
public static int count( String p, String file )
throws IOException
{
Map
int quantity = 0;
int state = 0;
final int FINALSTATE = p.length();
FileReader f = new FileReader( file );
int c = f.read();
while ( c != -1 ) {
if ( transitionTable.containsKey( state )
&& transitionTable.get( state ).containsKey( (char)c ) ) {
state = transitionTable.get( state ).get( (char)c );
if ( state == FINALSTATE ) {
quantity++;
}
} else {
state = 0;
}
c = f.read();
}
return quantity;
}
Folie-1105
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels und Zugriff auf Dateien
(siehe Folie 1057)
Nach Durcharbeiten des Kapitels Ausnahmebehandlung sollen
die teilnehmenden Studierenden
die Vorteile des Konzepts der Ausnahmebehandlung kennen und erklären können,
Ausnahmeklassen anlegen können,
Ausnahme-Objekte erzeugen und werfen können,
Ausnahme-Objekte fangen und verarbeiten können,
Checked Exceptions und Unchecked Exceptions unterscheiden und einsetzen können,
Grundlagen des Umgangs mit Dateien in Java kennen.
Folie-1106
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen, Algorithmen
und Programmierung 1 (DAP 1)
Fakultät für Informatik
Wintersemester 2019/20
Stefan Dissmann
Grafische Benutzungsoberflächen – ein Beispiel
Folie-1107
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Grafische Benutzungsoberflächen – ein Beispiel
Nach Durcharbeiten des Kapitels Grafische Benutzungsoberflächen – ein Beispiel sollen
die teilnehmenden Studierenden
die Idee der Gestaltung von grafischen Benutzungsoberflächen kennen.
Folie-1108
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Rückblick Mustererkennung
(siehe Folie 1104)
Für den Aufruf der Methode
public static int count( String pattern, String file )
throws IOException
werden benötigt:
ein Text: das zu suchende Muster (als Argument für den Parameter pattern)
ein Text: der Name der zu durchsuchenden Datei (als Argument für den Parameter file)
Aufgabe:
Entwicklung einer grafischen Benutzeroberfläche, um die benötigten Texte anzugeben und
das Ergebnis der Zählung durch die Methode count auszugeben.
Folie-1109
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Bestandteile der grafischen Benutzungsoberfläche
Konzeption
Fenster mit Rahmen
Bereich zur Eingabe des Musters
Bereich zur Eingabe des Dateinamens
Bereich zur Ausgabe des Ergebnisses
Schaltknopf zum Beenden
Schaltknopf zum Starten der Mustererkennung
Folie-1110
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Bestandteile der grafischen Benutzungsoberfläche
technische Bestandteile aus der Bibliothek JavaFX
Stage
TextField
Label
Button
Scene und Pane
Folie-1111
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Bestandteile der grafischen Benutzungsoberfläche (Fortsetzung)
technische Bestandteile in JavaFX
Stage – das ganze Fenster
Scene – Fensterinhalt
Pane – (geordnete) Gruppe von Elementen
Label – Element zur Textdarstellung
TextField – Element zur Texteingabe
Button – Element, das Aktion bewirkt
ausführliche Beschreibung unter:
http://docs.oracle.com/javase/8/javafx/api/
Folie-1112
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Bestandteile der grafischen Benutzungsoberfläche (Fortsetzung)
import javafx.application.Application;
import javafx.stage.Stage;
…
public class PatternCounting extends Application
{
public void start( Stage primaryStage )
{
…
}
public static void main( String[] args )
{
launch( args );
}
}
Application stellt einen
Ausführungsrahmen bereit
start wird implizit
mit einem geeigneten
Argument aufgerufen
und erzeugt das Fenster
Folie-1113
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Bestandteile der grafischen Benutzungsoberfläche (Fortsetzung)
…
import javafx.scene.layout.FlowPane;
public class PatternCounting extends Application
{
public void start( Stage primaryStage )
{
FlowPane pane = new FlowPane();
pane.setHgap( 10 );
pane.setVgap( 10 );
…
}
}
definieren den Abstand zwischen
den angezeigten Elementen {
{
FlowPane ordnet Elemente
hintereinander an
Folie-1114
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Bestandteile der grafischen Benutzungsoberfläche (Fortsetzung)
Layout-Klassen aus dem Paket javafx.scene.layout:
HBox die Elemente werden nebeneinander
(horizontal) angeordnet
VBox die Elemente werden übereinander
(vertikal) angeordnet
FlowPane die Elemente werden fließend angeordnet
BorderPane die Elemente werden entlang der Ränder angeordnet
StackPane die Elemente werden übereinander gestapelt
Folie-1115
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Bestandteile der grafischen Benutzungsoberfläche (Fortsetzung)
…
import javafx.scene.control.*;
public class PatternCounting extends Application
{
public void start( Stage primaryStage )
{
FlowPane pane = new FlowPane();
pane.setHgap( 10 );
pane.setVgap( 10 );
pane.getChildren().add( new Label( “pattern: “));
TextField pattern = new TextField();
pane.getChildren().add( pattern );
…
}
}
liefert Liste der von pane
verwalteten Elemente
fügt Label hinzu
legt Label an
fügt TextField hinzu
legt TextField an
Folie-1116
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Bestandteile der grafischen Benutzungsoberfläche (Fortsetzung)
…
public class PatternCounting extends Application
{
public void start( Stage primaryStage )
{
…
pane.getChildren().add( new Label( “file: “));
TextField file = new TextField();
pane.getChildren().add( file );
Button count = new Button();
count.setText( “count” );
pane.getChildren().add( count );
pane.getChildren().add( new Label( “result: “) );
Label result = new Label();
pane.getChildren().add( result );
Button quit = new Button();
quit.setText( “quit” );
pane.getChildren().add( quit );
…
}
}
analog
Folie-1117
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Bestandteile der grafischen Benutzungsoberfläche (Fortsetzung)
…
public class PatternCounting extends Application
{
public void start( Stage primaryStage )
{
…
primaryStage.setTitle( “Pattern Matching” );
primaryStage.setScene( new Scene( pane, 220, 100 ) );
primaryStage.show();
…
}
}
Titel des Fensters setzen
Scene-Objekt anlegen und
Fenster sichtbar machen
FlowPane mit Anfangsgröße zuordnen
Folie-1118
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Bestandteile der grafischen Benutzungsoberfläche (Fortsetzung)
Anmerkungen:
Das Layout von graphischen Oberflächen wird in der Regel nicht manuell implementiert.
Hierfür existieren spezielle GUI-Builder, die ein Gestalten von Oberflächen im
WYSIWYG-Stil (what-you-see-is-what-you-get) ermöglichen.
Beispiele für JavaFx-GUI-Builder:
– JavaFX Scene Builder (Oracle) 1)
– JavaFX Composer (NetBeans) 2)
Darüber hinaus arbeitet JavaFX mit Cascading Style Sheets (CSS) zusammen. 3)
1) http://www.oracle.com/technetwork/java/javafx/tools/index.html
2) https://netbeans.org/features/javafx/composer.html
3) http://docs.oracle.com/javase/8/javafx/api/javafx/scene/doc-files/cssref.html
Folie-1119
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Bestandteile der grafischen Benutzungsoberfläche (Fortsetzung)
Zuordnen von Verhalten zu den Button-Objekten
Aufruf der Methode
PatternMatcher.count
Beenden der Ausführung
Ergebnis anzeigen
Folie-1120
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Bestandteile der grafischen Benutzungsoberfläche (Fortsetzung)
Zuordnen von Verhalten zu den Button-Objekten
Zuordnen einer onAction:
Das ist die Aktion, die ausgeführt wird, wenn ein Button ausgewählt wird.
Deklaration:
ObjectProperty
Methode in der Klasse Button, die onAction setzt:
public void setOnAction( EventHandler
Interface EventHandler:
public interface EventHandler
extends EventListener
{
void handle( T event );
}
Folie-1121
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Bestandteile der grafischen Benutzungsoberfläche (Fortsetzung)
Zuordnen von Verhalten zu den Button-Objekten
…
public class PatternCounting extends Application
{
public void start( Stage primaryStage )
{
…
quit.setOnAction( … );
count.setOnAction( … );
}
}
Es wird noch die Zuordnung von passenden EventHandler-Implementierungen
durch Aufrufe von setOnAction benötigt, damit anschließend das Programm
durch Aufruf der main-Methode ausgeführt werden kann.
Folie-1122
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Bestandteile der grafischen Benutzungsoberfläche (Fortsetzung)
Zuordnen von Verhalten zu den Button-Objekten
…
public class PatternCounting extends Application
{
public void start( Stage primaryStage )
{
…
quit.setOnAction( event -> System.exit( 0 ) );
count.setOnAction( … );
}
}
Der Aufruf von System.exit( 0 ) beendet die Ausführung der virtuellen Maschine JVM
und damit auch des Programms.
Das Argument wird an das Betriebssystem übergeben.
Der Wert 0 zeigt ein normales Beenden an.
Lambda-Ausdruck
Folie-1123
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Bestandteile der grafischen Benutzungsoberfläche (Fortsetzung)
Zuordnen von Verhalten zu den Button-Objekten
…
public class PatternCounting extends Application
{
public void start( Stage primaryStage )
{
…
quit.setOnAction( event -> System.exit( 0 ) );
count.setOnAction( event ->
{
try {
result.setText( “” +
PatternMatcher.count( pattern.getText(), file.getText() ) );
} catch ( IOException e ) { result.setText( “file error” ); }
}
);
}
}
Ausnahmebehandlung ist notwendig, da count bei Zugriffsproblemen zu der angegebenen
Datei (file.getText()) eine Ausnahme werfen kann.
Lambda-Ausdruck
Folie-1124
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Bestandteile der grafischen Benutzungsoberfläche (Fortsetzung)
Zuordnen von Verhalten zu den Button-Objekten
…
public class PatternCounting extends Application
{
public void start( Stage primaryStage )
{
…
quit.setOnAction( event -> System.exit( 0 ) );
count.setOnAction( event ->
{
try {
result.setText( “” +
PatternMatcher.count( pattern.getText(), file.getText() ) );
} catch ( IOException e ) { result.setText( “file error” ); }
}
);
}
}
eingefangene effektiv finale
Variablen der Methode start
Folie-1125
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Bestandteile der grafischen Benutzungsoberfläche (Fortsetzung)
Zuordnen von Verhalten zu den Button-Objekten
…
public class PatternCounting extends Application
{
public void start( Stage primaryStage )
{
…
quit.setOnAction( event -> System.exit( 0 ) );
count.setOnAction( event ->
{
try {
result.setText( “” +
PatternMatcher.count( pattern.getText(), file.getText() ) );
} catch ( IOException e ) { result.setText( “file error” ); }
}
);
}
}
Nach der Zuordnung der passenden
EventHandler-Implementierungen
kann das Programm durch Aufruf der
main-Methode ausgeführt werden.
Folie-1126
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Grafische Benutzungsoberflächen – ein Beispiel
(siehe Folie 1107)
Nach Durcharbeiten des Kapitels Grafische Benutzungsoberflächen – ein Beispiel sollen
die teilnehmenden Studierenden
die Idee der Gestaltung von grafischen Benutzungsoberflächen kennen.
Folie-1127
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen, Algorithmen
und Programmierung 1 (DAP 1)
Fakultät für Informatik
Wintersemester 2019/20
Stefan Dissmann
Datenstruktur Hashtable
Folie-1128
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Datenstruktur Hashtable
Nach Durcharbeiten des Kapitels Hashtable sollen
die teilnehmenden Studierenden
die Arbeitsweise einer Hashtable kennen,
die Aufgaben einer Hashfunktion kennen,
die programmtechnische Realisierung einer Hashtable kennen.
Folie-1129
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klassen für Mengen
Bei der Implementierung von Klassen für Mengen müssen
folgende Anforderungen berücksichtigt werden:
Mengen können beliebige Elemente (eines Grundtyps) enthalten.
Einfügen, Entfernen und Prüfen des Enthaltenseins sollten wenig Aufwand verursachen.
Folie-1130
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klassen für Mengen (Fortsetzung)
Bei der Implementierung von Klassen für Mengen müssen
folgende Anforderungen berücksichtigt werden:
Mengen können beliebige Elemente (eines Grundtyps) enthalten.
Einfügen, Entfernen und Prüfen des Enthaltenseins sollten wenig Aufwand verursachen.
Java bietet in dem Paket java.util auch Klassen an, die Mengen realisieren. Darunter sind:
TreeSet Implementierung auf der Basis eines Suchbaums:
– Einfügen und Suchen (= Prüfen des Enthaltenseins) benötigen daher
O(log2n) Schritte für die Suche bis zur Position im Baum.
– Diese Form der Implementierung ist bereits bekannt.
– Voraussetzung ist, dass für die Elemente eine Ordnungsrelation existiert.
– Durch den Suchbaum ist ein geordneter/sortierter Durchlauf möglich.
Folie-1131
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Klassen für Mengen (Fortsetzung)
Bei der Implementierung von Klassen für Mengen müssen
folgende Anforderungen berücksichtigt werden:
Mengen können beliebige Elemente (eines Grundtyps) enthalten.
Einfügen, Entfernen und Prüfen des Enthaltenseins sollten wenig Aufwand verursachen.
Java bietet in dem Paket java.util auch Klassen an, die Mengen realisieren. Darunter sind:
TreeSet Implementierung auf der Basis eines Suchbaums:
– Einfügen und Suchen (= Prüfen des Enthaltenseins) benötigen daher
O(log2n) Schritte für die Suche bis zur Position im Baum.
– Diese Form der Implementierung ist bereits bekannt.
– Voraussetzung ist, dass für die Elemente eine Ordnungsrelation existiert.
– Durch den Suchbaum ist ein geordneter/sortierter Durchlauf möglich.
HashSet Implementierung auf der Basis einer Hashtable:
– Einfügen benötigt konstante Zeit: O(1)
– Suchen (= Prüfen des Enthaltenseins) benötigt (fast) konstante Zeit.
– Eine Ordnungsrelation wird nicht vorausgesetzt.
– Ein geordneter/sortierter Durchlauf ist nicht möglich.
Folie-1132
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Hashtable
Idee:
Gegeben sei eine Menge U (das Universum).
Ordne den x U durch eine Funktion h(x): U IN eine natürliche Zahl (Hashcode) zu.
Speichere die Elemente einer Menge M U in einer Tabelle,
die durch ein Feld t realisiert wird.
Bestimme den Index, den x M in t belegen soll,
direkt aus x als:
t[h( x ) % t.length].
Anmerkungen:
Die Ablage erfolgt schnell und hängt nur von der Berechnungsdauer des Hashcodes ab.
Die Suche erfolgt schnell und hängt nur von der Berechnungsdauer des Hashcodes ab.
Die Mächtigkeit von U kann viel größer als die Länge von t sein,
da h( x ) % t.length dafür sorgt, dass die Größe des Feldes nicht überschritten wird.
Folie-1133
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Hashtable (Fortsetzung)
Beispiel:
U = IR , M = { 5.1, 7.3, 8.2, 15.7 }
h(x) = (int) x
ergibt für ein Feld t der Länge 6:
0
1 7.3
2 8.2
3 15.7
4
5 5.1
Folie-1134
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Hashtable (Fortsetzung)
Beispiel:
U = IR , M = { 5.1, 7.3, 8.2, 15.7 }
h(x) = (int) x
ergibt für ein Feld t der Länge 6:
Aber nun soll 11.2 aufgenommen werden mit h(11.2) = 11 Kollision, da gilt:
h( 11.2 ) % t.length == 5
0
1 7.3
2 8.2
3 15.7
4
5 5.1
Folie-1135
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Hashtable (Fortsetzung)
Lösung für Kollisionen von Werten mit gleichem Hashcode: Liste von Elementen
Beispiel:
U = IR , M = { 5.1, 7.3, 8.2, 15.7, 11.2 }
h(x) = (int) x
ergibt für ein Feld t der Länge 6:
0
1
2
3
4
5
7,3
8,2
15,7
5,1 11,2
Folie-1136
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Hashtable (Fortsetzung)
Lösung für Kollisionen von Werten mit gleichem Hashcode: Liste von Elementen
Konsequenzen:
Die Ablage erfolgt schnell und hängt nur von der Berechnungsdauer des Hashcodes ab.
Die Suche erfolgt schnell und hängt von der Berechnungsdauer des Hashcodes
und der Länge der Kollisionsliste an der durch den Hashcode bestimmten Position ab.
Je stärker h(x) «streut», desto seltener treten Kollisionen auf.
Die geeignete Implementierung von h(x) liegt in der Verantwortung des Entwicklers.
Je mehr Werte in einer Tabelle abgelegt werden, desto größer wird die Wahrscheinlichkeit,
dass Kollisionen auftreten.
Um Kollisionen zu vermeiden,
muss die Datenstruktur Hashtable mit der Anzahl der in ihr abgelegten Werte wachsen.
Folie-1137
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Hashtable (Fortsetzung)
Unterstützung von Hashing in Java:
public class Object
{
…
public int hashCode() { … }
…
}
Jedes Objekt in Java besitzt eine Methode hashCode, die einen int-Wert liefert.
Für eine Ausführung eines Programms liefert hashCode für ein Objekt stets den gleichen Wert.
Bei einer Nutzung einer Datenstruktur, die auf einer Hashtable basiert – beispielsweise
HashSet oder HashMap, kann auf die Methode hashCode zurückgegriffen werden.
Voraussetzung:
Das Ergebnis von hashCode muss konsistent mit dem Ergebnis der Methode equals sein:
a.equals( b ) a.hashCode() == b.hashCode()
Falls equals überschrieben wird, muss auch hashCode überschrieben werden.
Begründung: Ein Objekt wird in einer Hashtable an der durch hashCode bestimmten Position
des Feldes gesucht. Ohne konsistentes Verhalten von equals und hashCode wäre diese
schnelle Prüfung nicht sicher, da gleiche Objekte auch an anderen Positionen liegen könnten.
Folie-1138
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel-Implementierung Hashtable
import java.util.LinkedList;
public class Hashtable
{
List
int capacity;
int size;
Es wird eine von Java bereit gestellte Liste verwendet, um die Kollisionslisten zu verwalten.
Das Verhältnis von size zu capacity wird dazu benutzt, um das Feld table rechtzeitig zu
vergrößern, um so die Zahl der Kollisionen gering zu halten.
– Die Reorganisation erfolgt im Beispiel dann, wenn gilt: (double)size / capacity > 0.75
– Die Reorganisation wird als Rehashing bezeichnet.
ein Feld von Listen als Tabelle
Größe der Tabelle
Zahl der tatsächlich abgelegten Objekte
Folie-1139
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel-Implementierung Hashtable (Fortsetzung)
public Hashtable( int c )
{
if ( c > 0 )
{
capacity = c;
} else {
throw new IllegalArgumentException();
}
table = new LinkedList[capacity];
size = 0;
}
Eine getypte Erzeugung von Feldern ist in generischen Klassen nicht möglich.
Die ungetypte Erzeugung des Feldes führt zu einer Warnung.
Die nicht typsicheren Listen sind technisch unproblematisch, solange innerhalb der Klasse
Hashtable
hier ist KEINE typsichere Erzeugung
möglich
Konstruktor
Folie-1140
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel-Implementierung Hashtable (Fortsetzung)
@SuppressWarnings({“unchecked”})
public Hashtable( int c )
{
if ( c > 0 )
{
capacity = c;
} else {
throw new IllegalArgumentException();
}
table = new LinkedList[capacity];
size = 0;
}
Die Annotation (siehe auch Folie 692) unterdrückt die hier erwartete Warnung.
Um nicht von unerwarteten und damit hilfreichen Warnungen abgelenkt zu werden,
können solche erwarteten Warnungen im Einzelfall gezielt unterdrückt werden.
Der Einsatz von @SuppressWarnings sollte zusätzlich durch einen Kommentar erklärt werden.
Annotation, unterdrückt die
Warnung
hier ist KEINE typsichere Erzeugung
möglich
Folie-1141
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel-Implementierung Hashtable (Fortsetzung)
@SuppressWarnings({“unchecked”})
public Hashtable( int c )
{
if ( c > 0 )
{
capacity = c;
} else {
throw new IllegalArgumentException();
}
table = new LinkedList[capacity];
size = 0;
for( int i = 0; i < capacity; i++ )
{
table[i] = new LinkedList<>();
}
}
für jedes Element des Feldes muss
eine eigene Liste erzeugt werden
Folie-1142
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Annotationen (Exkurs)
Annotationen sind eine Möglichkeit, Programmtexte mit zusätzlichen Informationen
(Metadaten) anzureichern.
Annotationen müssen einem fest vorgegebenen syntaktischen Aufbau folgen.
Annotationen können während der Übersetzung ausgewertet werden.
Annotationen können während der Ausführung ausgewertet werden.
Vordefinierte Annotationen:
– @Override die markierte Methode überschreibt eine Methode der Oberklasse
– @FunctionalInterface das markierte Interface enthält genau eine abstrakte Methode
– @Deprecated veraltete Methode, sollte nicht genutzt werden
– @SuppressWarnings unterdrückt Warnungen des Compilers
Annotationen können selbst definiert werden als Abwandlung einer interface-Deklaration:
@Retention( RetentionPolicy.RUNTIME )
@Target( { ElementType.Method } )
public @interface Info {
int version();
String author();
}
Nutzung:
@Info( version = 5, author = “Stefan” )
Auswertungszeitpunkt festlegen
Wirkungsbereich festlegen
Deklaration einer Annotation
mit zwei Parametern
Folie-1143
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel-Implementierung Hashtable (Fortsetzung)
private int position( T o )
{
return Math.abs( o.hashCode() % capacity );
}
public boolean contains( T o )
{
return table[position( o )].contains( o );
}
Die Methode position bestimmt aus dem hashCode eines Objekts die Position,
an der dieses Objekt im Feld abgelegt wird.
Da alle Methoden diese Position bestimmen müssen, ist die Berechnung in eine private
Methode ausgelagert worden.
Die Methode contains der Hashtable bestimmt die Position des zu suchenden Objekts im
Feld und delegiert dort die Aufgabe an die Methode contains des LinkedList-Objekts.
setzt korrekte Implementierung
von hashCode voraus
Folie-1144
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel-Implementierung Hashtable (Fortsetzung)
public void put( T o )
{
if ( !table[position( o )].contains( o ) )
{
if ( (double)(size + 1) / capacity > 0.75 )
{
rehash();
}
table[position( o )].add( o );
size++;
}
}
public void remove( T o )
{
if ( table[position( o )].remove( o ) )
{
size–;
}
}
Typischerweise wird die Tabelle bei Unterschreiten der 75%-Füllung nicht verkleinert.
o ist nicht enthalten
o an Liste anfügen
Reorganisation notwendig
remove gibt true zurück,
falls o enthalten war
Folie-1145
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Beispiel-Implementierung Hashtable (Fortsetzung)
@SuppressWarnings({“unchecked”})
void rehash()
{
capacity = 2 * capacity;
LinkedList
table = new LinkedList[capacity];
for( int i = 0; i < capacity; i++ )
{
table[i] = new LinkedList<>();
}
size = 0;
for ( LinkedList
{
for ( T elem : list )
{
if ( elem != null )
{
put( elem );
}
}
}
}
Feld-Attribut ist eine Referenz
neue Kapazität wird festgelegt
größeres Feld wird initialisiert
size wird durch put erhöht
Die Reorganisation muss über
put erfolgen, damit die größere
Kapazität bei der Verteilung der
Objekte auch genutzt wird
Folie-1146
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Hashtable (Fortsetzung)
Zusammenfassung:
Die Hashtable ist eine Datenstruktur, in der eine ungeordnete Menge von Daten schnell
zugreifbar abgelegt werden kann.
Das Auftreten von Kollisionen hängt von der Qualität der hashCode-Funktion,
der Größe des Feldes und den eingefügten Objekten ab.
Die hashCode-Funktion ist üblicherweise nicht injektiv, zu viele gleiche Funktionswerte
erhöhen aber das Auftreten von Kollisionen deutlich.
Die Normierung mit %capacity führt dazu, dass auch unterschiedliche Funktionswerte der
hashCode-Funktion auf gleiche Positionen im Feld abgebildet werden.
Die hashCode-Funktion sollte schnell berechenbar sein.
Alternativ möglich ist die einmalige Berechnung und Abspeicherung eines hashCode-Wertes
durch den Konstruktor der abzulegenden Objekte.
Die hashCode-Methode gibt dann den einmal berechneten Wert nur noch zurück.
Rehashing ist eine aufwändige Operation, bei der jeweils das sonst schnelle Einfügen eines
Objekts deutlich verzögert erfolgt.
Folie-1147
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Datenstruktur Hashtable
(siehe Folie 1128)
Nach Durcharbeiten des Kapitels Hashtable sollen
die teilnehmenden Studierenden
die Arbeitsweise einer Hashtable kennen,
die Aufgaben einer Hashfunktion kennen,
die programmtechnische Realisierung einer Hashtable kennen.
Folie-1148
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen, Algorithmen
und Programmierung 1 (DAP 1)
Fakultät für Informatik
Wintersemester 2019/20
Stefan Dissmann
Prioritätswarteschlange (Heap)
Folie-1149
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Prioritätswarteschlange (Heap)
Nach Durcharbeiten des Kapitels Prioritätswarteschlange (Heap) sollen
die teilnehmenden Studierenden
die Datenstruktur Heap kennen,
das Einfügen in einen Heap kennen,
das Löschen aus einem Heap kennen,
die Visualisierung eines Heaps als Baum kennen,
die Abbildung des Baums in ein Feld kennen,
die Implementierung der Klasse PriorityQueue kennen,
den Algorithmus HeapSort und seine Implementierung kennen.
Folie-1150
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Prioritätswarteschlange
Eine Prioritätswarteschlange ist eine Datenstruktur,
zu der Objekte hinzugefügt werden,
die später wieder entfernt werden.
Die Reihenfolge, in der die Objekte entfernt werden,
wird anhand einer objektspezifischen Priorität bestimmt.
Beispiele
Warteschlange beim Bäcker:
Priorität richtet sich nach der Ankunftszeit.
Warteschlange beim Flug-Einchecken:
Priorität richtet sich nach Sitzplatzklasse und Ankunftszeit.
Warteschlange bei der Notfallambulanz:
Priorität richtet sich nach Schwere der Erkrankung und Ankunftszeit.
Warteschlange im Auslieferungslager:
Priorität richtet sich an der Gesamtsituation aus.
Folie-1151
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Prioritätswarteschlange (Fortsetzung)
Eine Prioritätswarteschlange ist eine Datenstruktur,
zu der Objekte hinzugefügt werden,
die später wieder entfernt werden.
Die Reihenfolge, in der die Objekte entfernt werden,
wird anhand einer objektspezifischen Priorität bestimmt.
Benötigt wird eine Datenstruktur, bei der
schnell das Objekt mit der höchsten Priorität bestimmt werden kann,
dieses Objekt schnell entfernt werden kann und
schnell ein neues Objekt eingefügt werden kann.
Folie-1152
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Prioritätswarteschlange (Fortsetzung)
Eine Prioritätswarteschlange ist eine Datenstruktur,
zu der Objekte einzugefügt werden,
die später wieder entfernt werden.
Die Reihenfolge, in der die Objekte entfernt werden,
wird anhand einer objektspezifischen Priorität bestimmt.
Benötigt wird eine Datenstruktur, bei der
schnell das Objekt mit der höchsten Priorität bestimmt werden kann,
dieses Objekt schnell entfernt werden kann und
schnell ein neues Objekt eingefügt werden kann.
Lösungsideen auf der Basis der bekannten Datenstrukturen:
Objekte an ungeordnete Liste hängen, Objekt mit höchster Priorität wird gesucht
Objekte in geordneter Liste ablegen, neues Objekt wird einsortiert
Objekte in binären Suchbaum einsortieren
Folie-1153
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Prioritätswarteschlange (Fortsetzung)
Eine Prioritätswarteschlange ist eine Datenstruktur,
zu der Objekte einzugefügt werden,
die später wieder entfernt werden.
Die Reihenfolge, in der die Objekte entfernt werden,
wird anhand einer objektspezifischen Priorität bestimmt.
Benötigt wird eine Datenstruktur, bei der
schnell das Objekt mit der höchsten Priorität bestimmt werden kann,
dieses Objekt schnell entfernt werden kann und
schnell ein neues Objekt eingefügt werden kann.
Lösungsideen auf der Basis der bekannten Datenstrukturen:
Objekte an ungeordnete Liste hängen, Objekt mit höchster Priorität wird gesucht
Objekte in geordneter Liste ablegen, neues Objekt wird einsortiert
Objekte in binären Suchbaum einsortieren
Objekte in binären Baum einsortieren, der bei Änderungen Baumstruktur garantiert:
Heap
Folie-1154
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Heap
Die Datenstruktur Heap (engl. für Haufen) nutzt einen teilweise sortierten binären Baum, um
schnell den größten Knoten bezüglich einer vorgegebenen Ordnung zu finden,
schnell den größten Knoten bezüglich einer vorgegebenen Ordnung zu löschen und
schnell einen neuen Knoten einzufügen.
Ein (Max-)Heap ist
ein binärer Baum,
der vollständig ist,
für dessen Wurzel gilt,
dass sie eine größere Beschriftung als ihre Kinder besitzt und
dass die beiden Teilbäume ihrerseits auch wieder Heaps sind. (Max-Heap-Bedingung)
Ein Baum ist vollständig,
wenn bis zur vorletzten Ebene jede Ebene ihre maximale Zahl von Knoten enthält und
in der letzten Ebene nur von rechts Knoten fehlen.
Folie-1155
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Heap (Fortsetzung)
Beispiel (die Heap-Bedingung orientiert sich hier an der Ordnung der ganzen Zahlen)
Eigenschaft:
Der größte Knoten (38) steht in der Wurzel (Max-Heap).
38
Heap Heap
nur hier dürfen
Knoten fehlen
Folie-1156
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Heap (Fortsetzung)
Beispiel (die Heap-Bedingung orientiert sich hier an der Ordnung der ganzen Zahlen)
zwei unmittelbar erkennbare weitere Eigenschaften:
Der größte Wert (38) steht in der Wurzel, der zweitgrößte (22) in der zweiten Ebene,
der drittgrößte (21) höchstens in der dritten Ebene hinter dem zweitgrößten usw.
Ein Baum für n Werte hat höchsten log2(n)+1 Ebenen.
15
16211412
113 9 13 5
38
22
nur hier dürfen
Knoten fehlen
Folie-1157
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Heap (Fortsetzung)
Das Finden des größten Wertes ist trivial – das ist der Wert in der Wurzel!
Wurzel = größter Wert
15
16211412
113 9 13 5
38
22
Folie-1158
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Heap – Entfernen des größten Wertes
Ziel:
Nach dem Entfernen des Wertes der Wurzel muss diese einen neuen Wert erhalten,
so dass wieder die Heap-Bedingung im ganzen Baum gilt.
Voraussetzung:
Es liegen zwei Heaps vor, für die eine gemeinsame Wurzel gefunden werden muss.
Folie-1159
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Heap – Entfernen des größten Wertes
Ziel:
Nach dem Entfernen des Wertes der Wurzel muss diese einen neuen Wert erhalten,
so dass wieder die Heap-Bedingung im ganzen Baum gilt.
Voraussetzung:
Es liegen zwei Heaps vor, für die eine gemeinsame Wurzel gefunden werden muss.
Idee:
– Der neue Wert der Wurzel muss aus den Werten der beiden Teilheaps ausgewählt werden.
– Die Vollständigkeit muss erhalten bleiben.
Folie-1160
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Heap – Entfernen des größten Wertes
Ziel:
Nach dem Entfernen des Wertes der Wurzel muss diese einen neuen Wert erhalten,
so dass wieder die Heap-Bedingung im ganzen Baum gilt.
Voraussetzung:
Es liegen zwei Heaps vor, für die eine gemeinsame Wurzel gefunden werden muss.
Idee:
– Der neue Wert der Wurzel muss aus den Werten der beiden Teilheaps ausgewählt werden.
– Die Vollständigkeit muss erhalten bleiben.
Algorithmus:
– Lösche den äußersten rechten Knoten der letzten Ebene.
(Die Vollständigkeit bleibt erhalten.)
– Setze den Wert dieses Knotens in die Wurzel ein.
– Vergleiche den Wert der Wurzel mit dem größeren Wert ihrer Kinder:
Ist der Wert der Wurzel kleiner, vertausche beide Werte und
(Die Heap-Bedingung wird hergestellt.)
wiederhole das Vorgehen für den betroffenen Teilbaum.
– Das Verfahren endet, wenn keine Vertauschung vorgenommen wurde
oder ein Blatt erreicht wird.
Folie-1161
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
38
Datenstruktur Heap – Entfernen des größten Wertes (Fortsetzung)
15
16211412
113 9 13 5
22
X
Folie-1162
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
11
Datenstruktur Heap – Entfernen des größten Wertes (Fortsetzung)
X
Wert des letzten Knotens
in den Wurzelknoten einsetzen
15
16211412
3 9 13 5
11
22
Folie-1163
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Heap – Entfernen des größten Wertes (Fortsetzung)
Vertauschen
Vergleich
15
16211412
3 9 13 5
11
22
Folie-1164
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Heap – Entfernen des größten Wertes (Fortsetzung)
Vertauschen
Vergleich
15
16211412
3 9 13 5
22
11
Folie-1165
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Heap – Entfernen des größten Wertes (Fortsetzung)
Mit höchstens log2(n) Schritten ist die Heap-Bedingung im gesamten Baum wieder hergestellt.
Anmerkung:
Das Erhalten einer vollständigen Ordnung in einer sortierten Liste beim Entfernen des ersten
Elements erfordert demgegenüber gar keinen Aufwand.
Blatt erreicht
15
16111412
3 9 13 5
22
21
Folie-1166
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Heap – Einfügen eines Wertes
Ziel:
Nach dem Einfügen des Wertes muss der Baum die Heap-Bedingung erfüllen.
Voraussetzung:
Es liegt ein Heap vor.
Folie-1167
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Heap – Einfügen eines Wertes
Ziel:
Nach dem Einfügen des Wertes muss der Baum die Heap-Bedingung erfüllen.
Voraussetzung:
Es liegt ein Heap vor.
Idee:
– Der neue Wert muss in einem neuen Knoten ergänzt werden.
– Die Vollständigkeit muss erhalten bleiben.
Folie-1168
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Heap – Einfügen eines Wertes
Ziel:
Nach dem Einfügen des Wertes muss der Baum die Heap-Bedingung erfüllen.
Voraussetzung:
Es liegt ein Heap vor.
Idee:
– Der neue Wert muss in einem neuen Knoten ergänzt werden.
– Die Vollständigkeit muss erhalten bleiben.
Algorithmus:
– Ergänze einen äußersten rechten Knoten in der letzten Ebene.
(Die Vollständigkeit bleibt erhalten.)
– Setze den neuen Wert in diesen Knoten ein.
– Vergleiche den Wert dieses Knotens mit dem Wert seines Vorgängers:
Ist der Wert des Vorgängers kleiner, vertausche beide Werte und
(Heap-Bedingung)
wiederhole das Vorgehen für den betroffenen Vorgänger.
– Das Verfahren endet, wenn keine Vertauschung vorgenommen wurde oder
die Wurzel erreicht ist.
Folie-1169
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Heap – Einfügen eines Wertes (Fortsetzung)
31 neuer Wert
in neuem Knoten
38
15
16211412
113 9 13 5
22
Folie-1170
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Heap – Einfügen eines Wertes (Fortsetzung)
Vergleich
und
Vertauschung
21
38
15
16311412
113 9 13 5
22
Folie-1171
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Heap – Einfügen eines Wertes (Fortsetzung)
Vergleich
und
Vertauschung
21
38
15
16221412
113 9 13 5
31
Folie-1172
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstruktur Heap – Einfügen eines Wertes (5)
Mit höchstens log2(n) Schritten ist die Heap-Bedingung im gesamten Baum wieder garantiert.
Das Herstellen einer Sortierung in einer Liste mit n Werten würde demgegenüber bis zu n
Schritte erfordern.
In der Summe der notwendigen Schritte für gleichhäufig auftretendes Einfügen und Entfernen
schneidet der Heap daher besser als die Lösung mit Sortieren ab.
Vergleich (keine Vertauschung)
21
38
15
16221412
113 9 13 5
31
Folie-1173
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Überlegungen zur Implementierung
Aufgrund der Vollständigkeit kann berechnet werden,
wie viele Knoten auf jeder Ebene vorhanden sind:
Wurzel 20 = 1 Knoten
2-te Ebene 21 = 2 Knoten
3-te Ebene 22 = 4 Knoten
4-te Ebene 23 = 8 Knoten
…
n-te Ebene 2n-1 Knoten
Folie-1174
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Überlegungen zur Implementierung
Aufgrund der Vollständigkeit kann berechnet werden,
wie viele Knoten auf jeder Ebene vorhanden sind:
Wurzel 20 = 1 Knoten
2-te Ebene 21 = 2 Knoten
3-te Ebene 22 = 4 Knoten
4-te Ebene 23 = 8 Knoten
…
n-te Ebene 2n-1 Knoten
Ebenso lässt sich berechnen, wo in einer Ebene die Kinder eines Knotens liegen:
Die Kinder des ersten Knotens der Ebene n liegen an den Positionen 1 und 2 der
folgenden Ebene n+1,
die Kinder des 2-ten Knotens der Ebene n liegen auf den Positionen 3 und 4 der
folgenden Ebene n+1,
usw.
Folie-1175
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Überlegungen zur Implementierung
Aufgrund der Vollständigkeit kann berechnet werden,
wie viele Knoten auf jeder Ebene vorhanden sind:
Wurzel 20 = 1 Knoten
2-te Ebene 21 = 2 Knoten
3-te Ebene 22 = 4 Knoten
4-te Ebene 23 = 8 Knoten
…
n-te Ebene 2n-1 Knoten
Ebenso lässt sich berechnen, wo in einer Ebene die Kinder eines Knotens liegen:
Die Kinder des ersten Knotens der Ebene n liegen an den Positionen 1 und 2 der
folgenden Ebene n+1,
die Kinder des 2-ten Knotens der Ebene n liegen auf den Positionen 3 und 4 der
folgenden Ebene n+1,
usw.
Die Werte der Ebenen können daher hintereinander in einem Feld gespeichert
und die notwendigen Indexpositionen berechnet werden.
(Das lässt sich schnell ausführen!)
Eine Implementierung als rekursive Datenstruktur ist nur notwendig,
sofern eine dynamische Erweiterbarkeit benötigt wird.
Folie-1176
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Überlegungen zur Implementierung (Fortsetzung)
38 15 16221412 113 9 13 531 21
21
38
15
16221412
113 9 13 5
31
Baumdarstellung
Feld
Folie-1177
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Überlegungen zur Implementierung (Fortsetzung)
0 1 2 3 4 5 6 7 8 9 10 11 12 13Indizes
Kinder zu Index k:
2*k und 2*k+1
Vorgänger zu Index k:
k/2
21
38
15
16221412
113 9 13 5
31
38 15 16221412 113 9 13 531 21
Folie-1178
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Überlegungen zur Implementierung (Fortsetzung)
Planung der Klasse PriorityQueue
Konstruktor, der ein Feld der notwendigen Länge anlegt.
Öffentliche Methode void add( T content ), die content in den Heap einfügt.
Öffentliche Methode T poll(), die das Objekt mit der höchsten Priorität zurückgibt und
aus dem Heap löscht.
Öffentliche Methode int size(), die die Anzahl der im Feld abgelegten Objekte zurückgibt.
Private Methode void heapify(), die das Objekt in der Wurzel so tief in einen der beiden
Teilheaps einsinken lässt, dass die Heapbedingung wieder erfüllt ist.
Private Methode void swap( int i, int j), die Objekte an den Indizes i und j im Feld
vertauscht.
Anmerkung:
Der Vergleich der Prioritäten von T-Objekten soll über den bekannten Vergleich mit der
Methode compareTo erfolgen.
Folie-1179
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Implementierung der Klasse PriorityQueue
public class PriorityQueue
{
private Object[] nodes;
private int size;
public PriorityQueue( int capacity ) {
if ( capacity >= 0 ) {
nodes = new Object[capacity+1];
} else {
throw new IllegalStateException();
}
size = 0;
}
…
Das Element am Index 0
bleibt ungenutzt, daher
muss ein zusätzliches
Element erzeugt werden.
Folie-1180
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Implementierung der Klasse PriorityQueue
public void add( T content )
{
if ( size < nodes.length-1) {
size++;
nodes[size] = content;
int current = size;
boolean stop = (current == 1);
while ( !stop )
{
int parent = current/2;
if ( parent>0 && ((T)nodes[current]).compareTo((T)nodes[parent])>0 )
{
swap ( current, parent );
current = parent;
} else {
stop = true;
}
}
}
}
Das am Ende angefügte Objekt wird im Heap so lange in Richtung der Wurzel verschoben,
bis es auf einen kleineren Vorgänger im Heap trifft oder die Wurzel erreicht ist.
neues Objekt am
Ende anfügen
Vorgänger bestimmen
größeres Objekt nach
vorne tauschen
Folie-1181
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Implementierung der Klasse PriorityQueue
public T poll()
{
if ( size >= 1 ) {
T first = (T)nodes[1];
nodes[1] = nodes[size];
nodes[size] = null;
size–;
heapify();
return first;
} else {
throw new IllegalStateException();
}
}
Die Methode heapify macht aus einem Baum mit einem beliebigen Wert in der Wurzel,
deren linker und rechter Teilbaum jeweils Heaps sind, einen Heap.
wirft Ausnahme, falls
kein Objekt im Heap
letztes Objekt nach vorne
Heap-Bedingung herstellen
Folie-1182
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Überblick
Kinder bestimmen
nächste
Folie
Implementierung der Klasse PriorityQueue
private void heapify() {
int current = 1;
int leftChild, rightChild, largerChild;
boolean stop = false;
while ( !stop ) {
leftChild = 2*current;
rightChild = leftChild+1;
if ( leftChild <= size ) {
if ( rightChild <= size ) {
if ( ((T)nodes[rightChild]).compareTo( (T)nodes[leftChild] ) > 0 ) {
largerChild = rightChild;
} else {
largerChild = leftChild;
}
} else {
largerChild = leftChild;
}
if ( ( (T)nodes[largerChild] ).compareTo( (T)nodes[current] ) > 0 ) {
swap( current, largerChild );
current = largerChild;
} else {
stop = true;
}
} else {
stop = true;
}
}
}
kleineres Kind
bei Bedarf tauschen
bestimmen
Folie-1183
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Implementierung der Klasse PriorityQueue
if ( leftChild <= size )
{
if ( rightChild <= size )
{
if ( ((T)nodes[rightChild]).compareTo((T)nodes[leftChild]) > 0 )
{
largerChild = rightChild;
} else {
largerChild = leftChild;
}
} else {
largerChild = leftChild;
}
if ( ( (T)nodes[largerChild] ).compareTo( (T)nodes[current] ) > 0 )
{
swap( current, largerChild );
current = largerChild;
} else {
stop = true;
}
} else {
stop = true;
}
es gibt mindestens 1 Kind
es gibt zwei Kinder
das größere Kind
bestimmen
Kind ist größer als
Vorgänger: Vertauschung
keine Vertauschung
kein Kind vorhanden
Folie-1184
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zusammenfassung Datenstruktur Heap
Der Zugriff auf das Objekt mit der größten Priorität kann unmittelbar erfolgen.
Das Einfügen eines Objekts in den Heap erfordert höchstens log2(n) Schritte.
Das Entfernen des Objekts aus der Wurzel des Heaps erfordert höchstens log2(n) Schritte.
Der Datenstruktur Heap liegt die Vorstellung eines binären Baums zugrunde.
Der Baum kann aufgrund der gegebenen Randbedingungen sequentialisiert werden:
Der Implementierung des Heaps liegt ein Feld zugrunde.
Folie-1185
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Erweiterung: Sortieren mit einem Heap
Gegeben ist eine Folge von n Werten, die sortiert werden sollen.
Vorgehen:
Lege einen Heap der Länge n an.
Füge nacheinander alle n Werte in den Heap ein.
Das Herstellen der Heap-Bedingung erfordert für jeden einzelnen Wert höchstens log2(n)
Schritte, erfolgt also in der Laufzeit O(log2(n)).
Für alle n Werte werden daher höchstens n . log2(n) Schritte, Laufzeit ist O(n
. log2(n)).
Entferne nacheinander jeweils den Knoten mit dem größten Wert (= die Wurzel) aus dem Heap.
Das Herstellen der Heap-Bedingung erfordert für jedes Entfernen höchstens log2(n) Schritte,
also insgesamt für alle n Werte höchstens n . log2(n) Schritte.
Auch das «Abbauen» des Heaps erfolgt wieder mit Laufzeit O(n . log2(n)).
Folie-1186
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Erweiterung: Sortieren mit einem Heap (Fortsetzung)
Gegeben ist eine Folge von n Werten, die sortiert werden sollen.
Vorgehen:
Lege einen Heap der Länge n an.
Füge nacheinander alle n Werte in den Heap ein.
Das Herstellen der Heap-Bedingung erfordert für jeden einzelnen Wert höchstens log2(n)
Schritte, erfolgt also in der Laufzeit O(log2(n)).
Für alle n Werte werden daher höchstens n . log2(n) Schritte, Laufzeit ist O(n
. log2(n)).
Entferne nacheinander jeweils den Knoten mit dem größten Wert (= die Wurzel) aus dem Heap.
Das Herstellen der Heap-Bedingung erfordert für jedes Entfernen höchstens log2(n) Schritte,
also insgesamt für alle n Werte höchstens n . log2(n) Schritte.
Auch das «Abbauen» des Heaps erfolgt wieder mit Laufzeit O(n . log2(n)).
Diese Art des Sortierens besitzt also eine Laufzeit von O(2 . n . log2(n)) = O(n
. log2(n)),
die auch im schlechtesten Fall garantiert werden kann.
Folie-1187
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Erweiterung: Sortieren mit einem Heap (Fortsetzung)
Gegeben ist eine Folge von n Werten, die sortiert werden sollen.
Vorgehen:
Lege einen Heap der Länge n an.
Füge nacheinander alle n Werte in den Heap ein.
Das Herstellen der Heap-Bedingung erfordert für jeden einzelnen Wert höchstens log2(n)
Schritte, erfolgt also in der Laufzeit O(log2(n)).
Für alle n Werte werden daher höchstens n . log2(n) Schritte, Laufzeit ist O(n
. log2(n)).
Entferne nacheinander jeweils den Knoten mit dem größten Wert (= die Wurzel) aus dem Heap.
Das Herstellen der Heap-Bedingung erfordert für jedes Entfernen höchstens log2(n) Schritte,
also insgesamt für alle n Werte höchstens n . log2(n) Schritte.
Auch das «Abbauen» des Heaps erfolgt wieder mit Laufzeit O(n . log2(n)).
Diese Art des Sortierens besitzt also eine Laufzeit von O(2 . n . log2(n)) = O(n
. log2(n)),
die auch im schlechtesten Fall garantiert werden kann.
Dieses Vorgehen heißt HeapSort.
Folie-1188
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Erweiterung: Sortieren mit einem Heap (Fortsetzung)
public static
{
PriorityQueue
for ( T content : elements )
{
pq.add( content );
}
for ( int i = elements.length-1; i >= 0; i– )
{
elements[i] = pq.poll();
}
return elements;
}
Die Methode erhält ein Feld von T-Objekten übergeben und
erzeugt einen Heap,
fügt alle übergebenen Objekte ein,
liest nacheinander das jeweils größte Element aus und löscht es aus dem Heap,
speichert den gelesenen Wert in einem Feld ab.
Folie-1189
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Erweiterung: Sortieren mit einem Heap (Fortsetzung)
Anmerkung:
HeapSort kann auch als in situ-Algorithmus implementiert werden,
wenn zunächst die Ausgangswerte und der Heap und
anschließend der Heap und die sortierte Folge im gleichen Feld abgelegt werden
und sich nur die Grenze zwischen den beiden Bereichen immer verschiebt.
Heap unsortierte Werte
…
…
Aufbauen
des Heaps
Folie-1190
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Erweiterung: Sortieren mit einem Heap (Fortsetzung)
sortierte Werte
größter Wert
Wiederherstellen des Heaps
Abbauen des Heaps
Folie-1191
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Erweiterung: Sortieren mit einem Heap (Fortsetzung)
sortierte Werte
größter Wert
zweitgrößter Wert
Folie-1192
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Erweiterung: Sortieren mit einem Heap (Fortsetzung)
sortierte Werte
…
…
Abbauen
des Heaps
aufsteigende Folge
Folie-1193
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele des Kapitels Prioritätswarteschlange (Heap)
(siehe Folie 1149)
die Datenstruktur Heap kennen,
das Einfügen in einen Heap kennen,
das Löschen aus einem Heap kennen,
die Visualisierung eines Heaps als Baum kennen,
die Abbildung des Baums in ein Feld kennen,
die Implementierung der Klasse PriorityQueue kennen,
den Algorithmus HeapSort und seine Implementierung kennen.
Folie-1194
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Lernziele
(siehe Folie 3)
Nach erfolgreichem Abschluss des Moduls DAP 1 sollen
die teilnehmenden Studierenden
Programme in der Programmiersprache Java implementieren können,
Java-Klassen und -Bibliotheken nutzen können,
Java-Klassen und -Bibliotheken implementieren können,
einige wichtige Algorithmen mit ihren Implementierungen kennen,
einige wichtige Datenstrukturen mit ihren Implementierungen kennen,
eigene Algorithmen konzipieren und implementieren können,
eigene Datenstrukturen konzipieren und implementieren können,
Algorithmen und Datenstrukturen bewerten können,
objektorientierte Mechanismen anwenden können,
einige Entwurfsmuster einsetzen können,
einfache Ideen der Softwaretechnik einsetzen können.
Folie-1195
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen, Algorithmen
und Programmierung 1 (DAP 1)
Fakultät für Informatik
Wintersemester 2019/20
Stefan Dissmann
Abspann: weitere Anweisungen, Operatoren und Konzepte in Java
Folie-1196
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Vorbemerkungen
Dieses Kapitel stellt einige Java-Konzepte vor, die
im Rahmen der bisher vorgestellten Beispiele nicht benötigt wurden,
im Rahmen der bisher vorgestellten Beispiele bewusst nicht verwendet wurden,
da ihr Einsatz leicht zu einem
– unübersichtlichen oder
– schwer verständlichen
Programmierstil führen kann.
Folie-1197
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
switch-Anweisung
Die switch-Anweisung ermöglicht das Unterscheiden und kombinieren verschiedener
Alternativen.
Syntax:
:
switch ( Ausdruck )
case Wert Anweisungsfolge
{
default
}Alternative
Alternative
Folie-1198
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
switch-Anweisung (Fortsetzung)
Funktionsweise:
Der Ausdruck in (…) wird ausgewertet zu einem Wert w und es wird mit der Alternative
fortgefahren, bei der der Wert w angegeben ist.
– Werte können aus den Typen int (bzw. char, byte, short) und String stammen.
– Eine Anweisungsfolge kann auch leer sein.
– Taucht der Wert w bei keiner Alternative auf, so wird die Anweisungsfolge hinter default
angesprungen; fehlt default, ist wird die switch-Anweisung beendet.
– Es werden ab w alle Anweisungen bis zum Ende des Blocks der switch-Anweisung
ausgeführt, sofern dieser nicht zwangsweise mit einer break-Anweisung verlassen wird.
Beispiel:
switch (i) {
case 0: System.out.println(“null”); break;
case 1: System.out.println(“eins”); break;
default: System.out.println(“viele”);
}
Risiko:
Folgen einem case viele Anweisungen und wird der Ablauf nicht konsequent mit
break-Anweisungen gesteuert, können sehr unübersichtliche Abläufe entstehen.
Vermeidungsstrategien:
– Benutzung von if- bzw. if-else-Anweisungen
– Polymorphie
Folie-1199
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
do-while-Schleife
Die do-while-Schleife ermöglicht Schleifen, deren Rumpf mindestens einmal durchlaufen
werden muss, da erst anschließend die Bedingung geprüft wird.
Syntax:
Funktionsweise:
Der Block wird ausgeführt, anschließend wird die Bedingung ausgewertet:
– Ergibt die Bedingung true, wird die Ausführung des Blocks wiederholt.
– Ergibt die Bedingung false, ist die Schleife beendet.
– Nach der ersten Ausführung des Blocks unterscheidet sich diese Schleife in der Ausführung
nicht von der bekannten while-Schleife.
whileBlock Bedingungdo ( ) 😉
Folie-1200
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
do-while-Schleife (Fortsetzung)
Beispiel:
do {
account = requestAccountFromUser();
password = requestPasswordFromUser();
}
while ( !loginOk( account, password ) );
Risiko:
Bei einem langen Schleifenrumpf kann erst weit unten im Programmtext das Abbruchkriterium
gefunden werden.
Vermeidungsstrategie:
Der Rumpf der Schleife wird im Programmtext einmal vor einer while-Schleife aufgeführt
oder die Bedingung einer while-Schleife wird so angepasst, dass diese mindestens einmal
betreten wird.
boolean ok = false;
while ( !ok )
{
account = requestAccountFromUser();
password = requestPasswordFromUser();
ok = loginOk( account, password );
}
Folie-1201
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kontrolle von Schleifen mit continue
Die continue-Anweisung ermöglicht das Abbrechen der Ausführung eines Durchlaufs durch
eine Schleife.
Beispiel:
while ( true )
{
account = requestAccountFromUser();
if ( accountIsDisabled( account ) )
{
continue;
}
password = requestPasswordFromUser();
if ( loginOk( account, password ) )
{
break;
}
}
Funktionsweise continue:
– Die Ausführung der continue-Anweisung unterbricht die Ausführung der (innersten)
umgebenden Schleife.
– Die Programmausführung wird mit dem Prüfen der Bedingung der Schleife fortgesetzt.
Folie-1202
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Kontrolle von Schleifen mit break und continue
markierte Schleifen:
Um Sprünge aus geschachtelten Schleifen heraus zu ermöglichen, können Schleifen mit
Marken versehen werden, die hinter der break-/continue-Anweisung angegeben werden
können. Diese bezieht sich dann auf die entsprechend markierte Schleife.
int i = 0, j = 0;
m: for ( i = 0; i < arr.length; i++ ) {
for ( j = i+1; j < arr.length; j++ ) {
if ( arr[i] == arr[j] ) {
break m;
}
}
}
Risiko:
– Struktur der Einrückungen spiegelt nicht mehr den Ablauf des Programms wieder.
– Mehrere miteinander kombinierte markierte Schleifen können unübersichtliche
Ausführungsfolgen bewirken.
– Wirkung von break und continue wird bei Änderungen leicht übersehen.
Diese Konstruktion sollte daher besser nie eingesetzt werden!
Marke
break unterbricht die äußere Schleife
Folie-1203
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Bedingungsoperator ?:
Der Bedingungsoperator ist der einzige ternäre Operator in Java,
also ein Operator mit drei Operanden:
– der erste Operand muss den Typ boolean besitzen,
– die folgenden beiden Operanden müssen Typen besitzen, die beide kompatibel zur weiteren
Verarbeitung des Ergebnisses sind,
– die ersten beiden Operanden werden durch ? getrennt, die hinteren beiden durch :,
Syntax:
Funktionsweise:
Falls der erste Operand den Wert true ergibt,
liefert der Bedingungsoperator den Wert des zweiten Operanden,
falls der erste Operand den Wert false ergibt,
liefert der Bedingungsoperator den Wert des dritten Operanden.
? Ausdruck :Ausdruck Ausdruck
Folie-1204
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Bedingungsoperator ?: (Fortsetzung)
Beispiele:
int abs( int i ) {
return i<0 ? -i : i;
}
int minimum( int i1, int i2 ) {
return i1
– i>>>n verschiebt die Bits von i n-mal nach rechts und füllt links mit 0 auf.
Bitoperatoren:
Deklariert sind: int i, j; …
– ~i erzeugt das bitweise Komplement für den Wert von i.
– i|j erzeugt eine bitweise ODER-Verknüpfung der Werte von i und j.
– i&j erzeugt eine bitweise UND-Verknüpfung der Werte von i und j.
– i^j erzeugt eine bitweise XOR-Verknüpfung der Werte von i und j.
Konsequenz: Die Symbole der logischen Operatoren lassen sich syntaktisch korrekt auf
Zahlen anwenden!
Folie-1206
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Operator instanceof
Der binäre Operator instanceof vergleicht ein Objekt o mit einer Klasse C:
o instanceof C gibt true zurück, falls o ein Objekt der Klasse C ist
oder C eine Oberklasse der Klasse von o ist.
Beispiele:
o instanceof Object ist immer wahr.
Überschreibungen der Methode equals sollten zuerst immer die Typkompatibilität der
verglichenen Objekte prüfen:
class C
{
public boolean equals( Object o )
{
if ( o instanceof C ) {
…
} else {
return false;
}
}
…
}
Folie-1207
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Operator instanceof (Fortsetzung)
Der Operator instanceof sollte ausschließlich dann benutzt werden, wenn eine Ermittlung des
Typs eines Objekt unbedingt notwendig ist (siehe Beispiel equals).
Der Operator instanceof sollte nicht benutzt werden, um klassenspezifische, unterschiedliche
Abläufe in einer Methode innerhalb einer Vererbungshierarchie zu steuern.
Diese Aufgabe kann übersichtlicher durch das geeignete Überschreiben von Methoden in den
Unterklassen erfolgen.
Fallunterscheidungen der folgenden Form sind in der Regel fehleranfällig und
ein Zeichen mangelnden Verständnisses objektorientierter Denkweisen:
if ( o instanceof C1 ) { … }
if ( o instanceof C2 ) { … }
if ( o instanceof C3 ) { … }
if ( o instanceof C4 ) { … }
Folie-1208
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Operatorprioritäten
Die Priorität eines Operators bestimmt den Zeitpunkt seiner Auswertung in einem Ausdruck.
Priorität Operatoren
1 +, -, ++, –, !, ~, (type) alle unären Operatoren
2 *, /, % «Punktrechnung»
3 +, – «Strichrechnung»
4 <<, >>, >>> Verschiebungsoperatoren
5 >, >=, < , <=, instanceof Vergleiche
6 ==, != (Un-)Gleichheit
7 & UND
8 ^ XOR
9 | ODER
10 && UND (shortcut)
11 || ODER (shortcut)
12 ?: Bedingungsoperator
13 = Zuweisung
14 +=, -=, *=, /=, %=, &=, |=, ^= verkürzende Zuweisungen
Folie-1209
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Zugriffsrechte
Folgende Zugriffsrechte können durch Modifizierer angegeben werden:
public
= in allen Klassen in allen Paketen sichtbar.
protected
= nur im eigenen Paket und in allen erbenden Klassen sichtbar
(keine Angabe entspricht dem Zugriffsrecht: package-private)
= nur im eigenen Paket sichtbar
private
= nur in der eigenen Klasse sichtbar
Anmerkung:
Solange Klassen im gleichen Paket liegen,
zeigt nur private eine einschränkende Wirkung.
Folie-1210
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Felder
Feldvariable und Feldattribute sind besondere Referenzen.
Zulässig ist daher:
int[] arr = null;
Feldattribute werden immer mit null initialisiert.
Als Argumente übergebene Felder sollten daher vor ihrer Nutzung auch überprüft werden,
ob sie auf ein Feldobjekt verweisen, also ungleich null sind.
Da die Größe eines Feldobjekts nach seinem Erzeugen mit new festgelegt ist und
anschließend nicht mehr geändert werden kann, wird diese Länge durch eine
öffentliche Konstante bereitgestellt:
public final int length
Folie-1211
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Modifizierer static
Statische Elemente einer Klasse sind einmal in der Klasse vorhanden und werden nicht für jedes
Objekt einzeln erzeugt.
Statische Elemente einer Klasse können daher ohne das Erzeugen eines Objekts genutzt
werden.
Daher beginnt auch die Ausführung eines Java-Programms immer mit einer
statischen Methode:
public static void main(String[] args)
Statische Methoden können eingesetzt werden, wenn diese einen funktionalen Charakter
besitzen und aus ihren Parametern ein Ergebnis ableiten:
int calculateGcd( int v1, int v2 ) (siehe Folie 227)
Statische innere Klassen können dann eingesetzt werden, wenn die innere Klasse keinen Bezug
zu einem einzelnen Objekt der umgebenden Klasse hat.
Statische Attribute sollten vorsichtig eingesetzt werden, insbesondere dann, wenn von einer
Klasse auch Objekte erzeugt werden. Ein statisches Attribut kann dann von allen Objekten der
Klasse angesprochen und – falls Methoden bereitstehen – geändert werden.
Folie-1212
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Variable Parameteranzahl - Vararg
Methoden mit nur einem deklarierten Parameter, aber mit der Möglichkeit, eine variable
Anzahl von Argumenten übergeben zu können, können folgendermaßen angelegt werden:
public static int maximum( int... values )
{
int max = 0;
if ( values.length > 0 )
{
max = values[0];
for ( int candidate : values )
{
if ( candidate > max )
{
max = candidate;
}
}
}
return max;
}
Auslassungssymbol …
Es sind beliebig viele Parameter
des Typs int erlaubt.
intern abgelegt in einem Feld
von int-Werten
Folie-1213
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Variable Parameteranzahl – Vararg (Fortsetzung)
erlaubte Aufrufe für maximum( int… values ):
int m = maximum(); kein Argument
int m = maximum(17); ein Argument
int m = maximum(2,17,6,1,9,8); viele Argumente
int[] arr = {12,5,6,19}; int m = maximum( arr ); ein Feld
Hinweise:
Eine Deklaration verbraucht also verschiedene Signaturen.
Methoden mit diesen Signaturen können nicht noch einmal explizit deklariert werden.
In der Parameterliste der Deklaration darf nur höchstens ein Vararg-Parameter als letzter
Parameter auftreten.
Alle möglicherweise vor dem Vararg-Parameter stehenden Parameter müssen verpflichtend
angegeben werden. int f( int p, int… values ) erfordert also beim Aufruf immer
die Angabe mindestens eines int-Wertes, der erste übergeben Wert steht immer in p zur
Verfügung.
Vararg-Parameter sehen auf den ersten Blick hilfreich aus, allerdings muss an der
Programmposition des Aufrufs die Anzahl der Argumente festgelegt werden (können).
Folie-1214
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Aufzählungstyp enum
Aufzählungen sind Mengen von selbst definierten Konstanten,
auf denen Vergleiche möglich sind.
Syntax:
Beispiel:
enum Term
{
WINTER, SUMMER
}
}Bezeichner { Bezeichnerenum
,
Folie-1215
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Aufzählungstyp enum (Fortsetzung)
Umsetzung durch Compiler in folgende Klasse:
public class Term extends Enum
{
public static final Term WINTER = new Term( “WINTER”, 0 );
public static final Term SUMMER = new Term( “SUMMER”, 1 );
private Term( String s, int i )
{
super( s, i );
}
…
}
Nutzung:
Term actualTerm = Term.WINTER;
Vorteile:
– Der Aufzählungstyp ist abgeschlossen und typsicher.
– Der Aufzählungtyp darf in switch-Anweisungen als case-Angabe genutzt werden.
– Aufzählungstypen können auch Methoden enthalten und Schnittstellen implementieren.
sorgt für Ordnung
sorgt für toString()
erbt Methoden
mit compareTo
Folie-1216
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Reflexion/Introspektion
Ein Java-Programm kann sich selbst betrachten:
Klasse java.lang.Class
– public String getName()
– public Class super T> getSuperclass()
– public Class>[] getInterfaces()
– public Method[] getMethods()
– public Method[] getDeclaredMethods()
– public Field[] getFields()
– public Field[] getDeclaredFields()
– public boolean isAnonymousClass()
– …
Klasse Object, auch mit der Methode
– public final Class> getClass()
Beispiel:
ints.getClass().getName().equals( “DoublyLinkedList” )
…
Folie-1217
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Garbage Collector
Das explizite Erzeugen eines Objekts mit new reserviert genügend Speicherplatz für die
Verwaltung der Informationen dieses Objekts durch das Laufzeitsystem.
Die vordefinierte maximale Größe aller reservierte Objekte beträgt für aktuelle Java-Versionen
1/4 des verfügbaren Hauptspeichers bis höchstens 1 GigaByte.
Java kennt keine explizite Freigabe von nicht mehr benötigtem Speicherplatz.
Die Freigabe von nicht mehr benötigtem Speicherplatz erfolgt implizit durch den
Garbage Collector (GC).
Der GC überprüft dabei, ob aus dem laufenden Programm noch ein Zugriff auf ein Objekt
möglich ist. Ist das nicht der Fall, wird der Speicherbereich des Objekts freigegeben.
Der GC arbeitet auch anforderungsgetrieben, wird also insbesondere dann aktiv,
wenn für die Erzeugung eines Objekts nicht mehr genügend Speicherplatz verfügbar ist.
Konsequenzen:
– Der GC kann für ein Objekt feststellen, ob im laufenden Programm eine Referenz existiert,
von der aus – eventuell über weitere Referenzen – dieses Objekt erreicht werden kann.
– Der GC kann bei dynamischen Abläufen nicht feststellen und vorhersagen, ob die noch
erreichbaren Objekte später wirklich benötigt werden.
– Der Entwickler hat also die Aufgabe, nicht mehr benötigte Objekte auch zu nie wieder
erreichbaren Objekten zu machen, damit der GC seine Aufgabe erfüllen kann.
Folie-1218
dortmund
technische universität Datenstrukturen, Algorithmen und Programmierung 1
Wintersemester 2019/20
Fakultät für Informatik
Stefan Dissmann
Datenstrukturen, Algorithmen
und Programmierung 1 (DAP 1)
Fakultät für Informatik
Wintersemester 2019/20
Ende