Ingenieurinformatik I Gunnar Teege Skript zur Vorlesung Herbst 2007 Institut für Informatik Universität der Bundeswehr München (Skript generiert mit Targeteam) Inhaltsverzeichnis 1 2 Übersicht 2 1.1 Behandelte Themen . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.2 Literatur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.2.1 Begleitende Literatur . . . . . . . . . . . . . . . . . . . . 3 1.2.2 Weiterführende Literatur . . . . . . . . . . . . . . . . . . 3 Grundlagen der Programmierung 4 2.1 Einführung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 2.1.1 Sicht des Programmierers . . . . . . . . . . . . . . . . . 4 Algorithmus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 2.2.1 Spezifikation als Ausgangspunkt für ein Programm . . . . 6 2.2.2 Begriff des Algorithmus . . . . . . . . . . . . . . . . . . 7 2.2.3 Komponenten eines Algorithmus . . . . . . . . . . . . . . 10 2.2.4 Darstellung von Algorithmen . . . . . . . . . . . . . . . 12 2.2.5 Algorithmus und Programm . . . . . . . . . . . . . . . . 14 2.2 2.3 Datentypen und Ausdrücke . . . . . . . . . . . . . . . . . . . . . 15 2.4 Programmkonstrukte . . . . . . . . . . . . . . . . . . . . . . . . 20 2.5 2.4.1 Zuweisungen . . . . . . . . . . . . . . . . . . . . . . . . 21 2.4.2 Alternativanweisungen . . . . . . . . . . . . . . . . . . . 23 2.4.3 Schleifen . . . . . . . . . . . . . . . . . . . . . . . . . . 25 2.4.4 Blöcke . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 Modularisierung von Programmen . . . . . . . . . . . . . . . . . 26 2.5.1 Zerlegung von Problemen und Algorithmen . . . . . . . . 27 2.5.2 Module . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 i Gunnar Teege, UniBW München 3 2.6 Rekursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 2.7 Objektorientierte Programmierung . . . . . . . . . . . . . . . . . 38 2.8 Programmiersprachen . . . . . . . . . . . . . . . . . . . . . . . . 42 Datenstrukturen und Algorithmen 3.1 3.2 3.3 3.4 3.5 3.6 4 INHALTSVERZEICHNIS Mathematische Hilfsmittel . . . . . . . . . . . . . . . . . . . . . 46 3.1.1 Mengen . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 3.1.2 Relationen und Abbildungen . . . . . . . . . . . . . . . . 50 3.1.3 Alphabete und Sprachen . . . . . . . . . . . . . . . . . . 55 3.1.4 Aussagen . . . . . . . . . . . . . . . . . . . . . . . . . . 57 Daten und Codierung . . . . . . . . . . . . . . . . . . . . . . . . 58 3.2.1 Information und Nachrichten . . . . . . . . . . . . . . . . 58 3.2.2 Bits und Bytes . . . . . . . . . . . . . . . . . . . . . . . 61 3.2.3 Codierung . . . . . . . . . . . . . . . . . . . . . . . . . . 62 3.2.4 Codierung von Bildern und Tönen . . . . . . . . . . . . . 68 3.2.5 Komprimierung . . . . . . . . . . . . . . . . . . . . . . . 69 Datenstrukturen . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 3.3.1 Listen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 3.3.2 Zeiger und Zeigerstrukturen . . . . . . . . . . . . . . . . 72 3.3.3 Bäume . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 Suchverfahren . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 3.4.1 Mengen von Datensätzen . . . . . . . . . . . . . . . . . . 79 3.4.2 Lineare Suche . . . . . . . . . . . . . . . . . . . . . . . . 79 3.4.3 Binäre Suche . . . . . . . . . . . . . . . . . . . . . . . . 79 Sortierverfahren . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 3.5.1 Sortierverfahren - Beispiel Bubble Sort . . . . . . . . . . 80 3.5.2 Rekursives Sortierverfahren - Beispiel Quicksort . . . . . 81 Komplexität . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 3.6.1 Komplexität von Algorithmen . . . . . . . . . . . . . . . 82 3.6.2 Komplexitätsklassen . . . . . . . . . . . . . . . . . . . . 83 Software-Engineering 4.1 46 87 Software/Engineering - Definition des Ideals . . . . . . . . . . . . 87 ii Gunnar Teege, UniBW München 4.2 4.3 4.4 4.5 4.6 4.7 Komplexität von Software-Projekten . . . . . . . . . . . . . . . . 87 4.2.1 Maße für den Umfang von Software . . . . . . . . . . . . 87 4.2.2 Klassifikation von Software-Projekten . . . . . . . . . . . 88 4.2.3 Hauptanforderungen bei der Softwareentwicklung . . . . 88 Vorgehensmodelle . . . . . . . . . . . . . . . . . . . . . . . . . . 88 4.3.1 Code and fix-Verfahren . . . . . . . . . . . . . . . . . . . 88 4.3.2 Wasserfall-Modelle . . . . . . . . . . . . . . . . . . . . . 89 4.3.3 Prototyping und Spiralmodelle . . . . . . . . . . . . . . . 90 Strukturierte Programmierung . . . . . . . . . . . . . . . . . . . 90 4.4.1 Eigenschaften . . . . . . . . . . . . . . . . . . . . . . . . 90 4.4.2 Vorteile . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 Modellierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 4.5.1 Wozu Modellierung? . . . . . . . . . . . . . . . . . . . . 91 4.5.2 Was ist Modellierung in der Informatik . . . . . . . . . . 92 Modelle für Analyse und Entwurf . . . . . . . . . . . . . . . . . 93 4.6.1 Prozessmodell . . . . . . . . . . . . . . . . . . . . . . . 93 4.6.2 Datenmodell . . . . . . . . . . . . . . . . . . . . . . . . 94 4.6.3 Dynamisches Modell . . . . . . . . . . . . . . . . . . . . 95 Objektorientierte Software-Entwicklungsmethoden . . . . . . . . 98 4.7.1 4.8 5 INHALTSVERZEICHNIS Modellierungssprache UML . . . . . . . . . . . . . . . . 98 Software-Qualitätssicherung . . . . . . . . . . . . . . . . . . . . 101 4.8.1 Qualitätskriterien . . . . . . . . . . . . . . . . . . . . . . 102 4.8.2 Maßnahmen zur Qualitätssicherung . . . . . . . . . . . . 102 4.8.3 Qualitätsnormen und Zertifizierung . . . . . . . . . . . . 102 Datenbanken 104 5.1 Dateisysteme . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104 5.2 Datenbanksysteme . . . . . . . . . . . . . . . . . . . . . . . . . 105 5.3 5.2.1 Allgemeines . . . . . . . . . . . . . . . . . . . . . . . . 105 5.2.2 Beispiele aus der Praxis . . . . . . . . . . . . . . . . . . 107 Relationale Datenbanksysteme . . . . . . . . . . . . . . . . . . . 107 5.3.1 Allgemeine Eigenschaften . . . . . . . . . . . . . . . . . 108 5.3.2 Umsetzung des ER-Modells . . . . . . . . . . . . . . . . 110 iii Gunnar Teege, UniBW München INHALTSVERZEICHNIS 5.3.3 Sichten . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 5.3.4 Abfragesprache SQL . . . . . . . . . . . . . . . . . . . . 112 5.3.5 Beispielsysteme . . . . . . . . . . . . . . . . . . . . . . 114 iv Gunnar Teege, UniBW München INHALTSVERZEICHNIS Diese Vorlesung wurde entwickelt an der Fakultät für Informatik, Technische Universität München, von Prof. Hans Schlichter, mit Beiträgen von Dr. Michael Koch. Die Anpassung zur Verwendung an der Universität der Bundeswehr München erfolgte durch Prof. Gunnar Teege mit freundlicher Genehmigung durch die Autoren. 1 Kapitel 1 Übersicht Ziel dieser Vorlesung ist eine inhaltlich abgestimmte Vorstellung der Grundlagen der Informatik sowie deren mögliche Nutzung. Die Vorlesung richtet sich an Nicht-Informatik-Studierende. Die Vorlesung behandelt alle grundlegenden Aspekte der Informatik mit Ausnahme der Aspekte verteilter Informationsverarbeitung. Diese werden in der Anschlussvorlesung behandelt. 1.1 Behandelte Themen • Grundlagen der Programmierung: Wie werden Programme geschrieben? Wie sind Programmiersprachen aufgebaut? • Codierung von Information: Wie wird Information im Rechner dargestellt und gespeichert? • Datenstrukturen und Algorithmen: Wie werden größere Datenmengen in Programmen systematisch strukturiert? Wie werden diese Strukturen verarbeitet? • Datenbanken: Wie werden große Datenmengen getrennt von Programmen strukturiert und gespeichert? • Software-Entwicklungstechnik: Wie werden große Programmsysteme durch Entwickler-Teams produziert? • Rechnerarchitektur: Wie ist die Rechner-Hardware strukturiert? Aus welchen Komponenten besteht ein Rechner? • Systemsoftware: Welche Aufgaben hat ein Betriebssystem? 2 Gunnar Teege, UniBW München 1.2 1.2. LITERATUR Literatur Als Basis für die Vorlesung wurden die nachfolgenden Bücher verwendet. 1.2.1 Begleitende Literatur Begleitend zur Vorlesung können verwendet werden: • P. Levi, U. Rembold: "Einführung in die Informatik für Naturwissenschaftler und Ingenieure", 4. Auflage, Hanser Verlag 2003 • H.-P. Gumm, M. Sommer: "Einführung in die Informatik", 4. Auflage, Oldenbourg Verlag, 2000 • H. Balzert: "Lehrbuch Grundlagen der Informatik", Spektrum Verlag 1999 – hauptsächlich LE 1-3; siehe auch im WWW (URL: http://www.softwaretechnik.de/netscape/buecher/gdi/LE1.html) 1.2.2 Weiterführende Literatur Für Fortgeschrittene zur Vertiefung: • M. Broy: "Informatik - Eine Grundlegende Einführung", Springer-Verlag 1998 (Teile 1 und 2) Diese Buchsammlung dient als Grundlage für die Einführung der Informatik im Informatikstudium (Diplom, Bachelor). • P. Pepper: "Grundlagen der Informatik", Oldenbourg-Verlag 1995. Dieses Buch beschäftigt sich mit den theoretischen Grundlagen der Programmierung (Datenstrukturen, imperative, objektorientierte Programmierstile), kooperierenden und konkurrierenden Systemen sowie dem Aufbau von Rechnern und Aspekten von Betriebssystemen. 3 Kapitel 2 Grundlagen der Programmierung In diesem Kapitel wird kurz in die „Kunst des Programmierens“ eingeführt. Dazu werden die grundlegenden Aspekte hinsichtlich Datenstrukturen, Programmkonstrukte sowie Strukturierung von Programmen behandelt. • Fragestellungen des Abschnitts: – Was ist ein Algorithmus? – Welche elementaren Datenstrukturen gibt es? – Was sind die grundlegenden Konstrukte einer Programmiersprache? – Was versteht man unter Modularisierung und Rekursion? – Was ist unter Objekt-orientierter Programmierung zu verstehen? 2.1 Einführung Unter „Programmierung“ versteht man den Vorgang, in dem Anweisungen für den Computer erstellt werden. Diese Anweisungen werden in Sprachen geschrieben, welche Menschen verstehen können und werden für den Computer in Maschinensprache übersetzt oder vom Computer mit Hilfe eines speziellen Interpreterprogramms interpretiert. 2.1.1 Sicht des Programmierers Aus der Sicht eines Programmierers ergibt sich folgender Ablauf: 4 Gunnar Teege, UniBW München 2.1. EINFÜHRUNG Ablauf der Programmentwicklung • Quellprogramm Das Quellprogramm ist die Ausgangsform des Programms, z.B. in der Programmiersprache C, Java oder Basic. • Übersetzen (Compiler) Mit Hilfe des Compilers (Übersetzungsprogramm) wird aus dem Quellprogramm ausführbarer Objektcode erzeugt, das „Maschinenprogramm“. • Objektcode Objektcode ist die Interndarstellung des Programms, die für den Computer verständlich ist, d.h. das ausführbare Programm (Maschinenprogramm). Mit einem sogenannten "Linker" kann der Objektcode aus mehreren Einzelteilen zusammengesetzt werden: Ausgangspunkt ist dann ein Quellprogramm, das in mehreren unterschiedlichen Dateien abgespeichert ist. • Starten Damit das Maschinenprogramm ausgeführt wird, muss es gestartet werden. Das gleiche Programm kann mehrmals gestartet werden, um unterschiedliche Eingaben zu verarbeiten. • Prozess Als „Prozess“ wird die Ausführung eines Objektcodes bezeichnet; hier werden durch das Betriebssystem zusätzliche Daten dynamisch erzeugt, die für die Ausführung notwendig sind, z.B. die Seitentabelle. 5 Gunnar Teege, UniBW München 2.2. ALGORITHMUS • Tests Um zu verifizieren, ob ein Programm genau dies macht, was beabsichtigt ist, sind i.a. eine Reihe von Testläufen notwendig. Mit vorgegebenen Eingabedaten wird überprüft, ob das Programm/Prozess die gewünschten Ausgabedaten erzeugt. Bei Fehlverhalten des Programms (falsche Ausgabedaten oder sogar Absturz des Programms) muss das Quellprogramm korrigiert werden. I.a muss der Zyklus Quellprogramm erstellen, Übersetzen, Starten, Testen wiederholt durchlaufen werden. 2.2 Algorithmus Bevor man anfängt ein Programm, also eine Vorschrift zur Lösung einer Aufgabe, zu schreiben, muss man zuerst das zu lösende Problem genau beschreiben, d.h. spezifizieren. 2.2.1 Spezifikation als Ausgangspunkt für ein Programm Eine Spezifikation ist eine vollständige, detaillierte und unzweideutige Problembeschreibung. • vollständig: alle relevanten Informationen sind berücksichtigt. • detailliert: alle Hilfsmittel und Grundaktionen sind aufgelistet, die zur Lösung zugelassen sind. • unzweideutig: klare Kriterien sind festgelegt, die bestimmen, wann eine Lösung akzeptabel ist. Beispiel: Informelle Beschreibung des ggT Das folgende ist eine informelle, umgangssprachliche Beschreibung für das Problem der Bestimmung des größten gemeinsamen Teilers zweier Zahlen. „Für beliebige Zahlen m und n berechne den größten gemeinsamen Teiler ggT(m,n), das heißt die größte Zahl, die sowohl m als auch n teilt.“ Diese Beschreibung erfüllt nicht die Anforderungen an eine Spezifikation: • Vollständigkeit Die Beschreibung lässt offen, welche Zahlen (als Eingabe) zugelassen sind (nur positive Zahlen, ganze oder rationale Zahlen, auch die Null?). 6 Gunnar Teege, UniBW München 2.2. ALGORITHMUS • Detailliertheit Die Beschreibung lässt offen, welche Operationen (Befehle) zur Lösung des Problems verwendet werden dürfen (nur „+“ und „-“ oder auch Operationen zur ganzzahligen Division und Restbildung?). • Unzweideutigkeit Die Beschreibung lässt offen, was „berechnen“ heißt: soll das Ergebnis ausgedruckt oder gespeichert werden? Wo? Beispiel: Spezifikation des ggT Die folgende Spezifikation vermeidet die genannten Schwächen der informellen Beschreibung. „Gesucht wird eine Funktion ggT(m,n), die eine Zahl z berechnet (der Variablen z einen Wert zuweist), die die unten aufgeführte Nachbedingung erfüllt, falls die unten aufgeführte Vorbedingung erfüllt ist. Bei der Berechnung dürfen nur Vergleiche, Größenvergleiche, Addition und Subtraktion zweier Zahlen gemäß der Vorbedingung verwendet werden. “ • Vorbedingung für zulässige Eingabewerte m und n sind ganze Zahlen mit 0 < m < 32767 und 0 < n < 32767. • Nachbedingung für erwartete Ausgabewerte z teilt m und z teilt n und für jedes z’, das m teilt und n teilt gilt: z’ ≤ z. • Annahme Dabei wird angenommen, dass die genaue Bedeutung von „x teilt y“ und den übrigen Begriffen bekannt ist. 2.2.2 Begriff des Algorithmus Nach der Spezifikation eines Problems geht es anschließend darum, einen Lösungsweg zu entwerfen. Da die Lösung i.a. von einem Rechner ausgeführt werden soll, muss jeder Schritt exakt vorgeschrieben werden. Dies erfolgt mit Hilfe eines Algorithmus. • Der Algorithmus ist eine der ältesten Beschreibungstechniken für Abläufe; benannt nach dem Mathematiker Al-Khwarizmi (ca. 780-850), der am Hofe des Kalifen von Bagdad wirkte. 7 Gunnar Teege, UniBW München 2.2. ALGORITHMUS • Informelle Charakterisierung eines Algorithmus Ein Algorithmus ist eine detaillierte und explizite Vorschrift zur schrittweisen Lösung eines Problems, d.h. eine Vorschrift zur Lösung einer Aufgabe, wobei die Vorschrift – präzise formuliert, – in endlicher Form dargestellt und – effektiv ausführbar ist. Die Aufgabe kann aus vielen Anwendungsgebieten stammen, z.B. Berechnung numerischer Werte, Text- und Bildverarbeitung, Handhabung von Objekten (Robotik), Zuteilung von Ressourcen, Steuerung von Geräten. • Formale Definition (nach H. Kübe): Ein Algorithmus ist eine in der Beschreibung und Ausführung endliche, deterministische und effektive Vorschrift zur Lösung eines Problems, die effizient sein sollte. – Hierin bedeuten: ∗ endlich in Beschreibung: der Algorithmus kann mit endlich viel Text komplett aufgeschrieben werden. ∗ endlich in Ausführung: nach einer endlichen Zeit wird der Algorithmus beendet ∗ deterministisch: eindeutige Bestimmung des nächsten Schrittes ∗ effektiv: eindeutige Ausführbarkeit der Einzelschritte ∗ effizient: möglichst geringer Verbrauch an Ressourcen (z.B. Arbeitsspeicher) – Anmerkung: meist erweitert man den Begriff des Algorithmus auch auf Vorschriften, die in der Ausführung nicht oder nicht immer endlich sind. Damit wird die Terminierung zu einer Eigenschaft von Algorithmen: endet die Ausführung nach endlicher Zeit? Nicht immer ist Terminierung erwünscht, z.B. für ein Betriebssystem oder ein Echtzeitsystem zur Steuerung eines externen Vorgangs. – Ein Algorithmus heißt terminierend, wenn seine Ausführung für jede mögliche Eingabe nach einer endlichen Anzahl von Schritten endet. 8 Gunnar Teege, UniBW München 2.2. ALGORITHMUS determiniert, wenn er für eine bestimmte Eingabe bei allen Abläufen immer dieselbe Ausgabe liefert – Beispiel Personalführung Eingabe: Liste aller Mitarbeiter wiederhole solange die Liste nicht leer ist wiederhole für alle Mitarbeiter führe willkürlich einen der folgenden Einzelschritte aus: belobige den Mitarbeiter tadle den Mitarbeiter entlasse den Mitarbeiter (entferne ihn aus der Liste) Ende Willkür Ende Wiederhole Ende Wiederhole Ausgabe: Ursprüngliche Liste aller (auch ehemaliger) Mitarbeiter mit Lobund Tadelvorgängen. Im Fall "belobige" und "tadle" bleiben die Mitarbeiter weiter Elemente der Liste. Sie können damit im nächsten Durchlauf wieder ausgewählt werden. Falls für gewisse Mitarbeiter nie der Einzelschritt "entlasse" ausgewählt wird, wird die Liste nie leer; der Algorithmus terminiert nicht. ∗ Algorithmus ist nichtdeterministisch, nichtterminierend, nichtdeterminiert. • Formulierung eines Algorithmus – Sprache Die Formulierung kann in natürlicher oder formaler Sprache vorliegen – Ausführung Die Ausführung kann durch Menschen oder eine Maschine erfolgen. Die Ausführung ist effektiv, wenn sie aus einer Folge von elementaren Bearbeitungsschritten besteht, die für den beabsichtigten Ausführenden zur Verfügung stehen. – Beispiele für Algorithmen ∗ Nicht maschinell ausführbares Beispiel Bestimme das Alter der ältesten Person im Raum 1. Gehe zur ersten Person 2. Frage Person nach dem Alter 3. Merke das Alter 9 Gunnar Teege, UniBW München 2.2. ALGORITHMUS 4. Solange noch nicht alle Personen gefragt, wiederhole Schritte 4.a bis 4.c a) gehe zur nächsten Person b) frage nach dem Alter c) wenn das Alter größer als das gemerkte Alter, dann merke Dir das neue Alter 5. Älteste Person ist "gemerktes Alter" alt ∗ Maschinell ausführbares Beispiel Bestimme die größte Zahl aus einer Menge von Zahlen 1. Lies die erste Zahl 2. Initialisiere Platzhalter/Variable z mit der gelesenen Zahl 3. Lies die nächste Zahl 4. Wenn diese Zahl größer z, dann setze z auf diese Zahl 5. Wenn noch Zahlen vorhanden, dann gehe zu Schritt 3 6. Gib den Wert von z aus Dabei ist vorausgesetzt, dass die Menge der Zahlen so in der Maschine organisiert ist, dass die Maschine den Zugriff auf die „erste“ Zahl und auf die jeweils „nächste“ Zahl ausführen kann, z.B. als Liste. 2.2.3 Komponenten eines Algorithmus Welche Bestandteile treten in einem Algorithmus auf, werden also benutzt um die Vorschrift zu formulieren? Objekte und Anweisungen In ihrer allgemeinsten Form bestehen Algorithmen aus folgenden Bestandteilen: • Objekte und • Anweisungen, die Operationen an Objekten realisieren. Beispiele Objekte sind z.B. Zahlen, Adressen, Textdokumente. Operationen sind z.B. Addition, Suche, Ausdrucken, Rechtschreibprüfung. Die Operationen bewirken, dass die Objekte von einem ursprünglichen Zustand (Anfangs- oder Eingangszustand) über eventuell notwendige Zwischenzustände in einen Endzustand gebracht werden. (EVA-Prinzip: Eingabe -> Verarbeitung -> Ausgabe) 10 Gunnar Teege, UniBW München 2.2. ALGORITHMUS Abstraktion Bei der Beschreibung der Objekte und Operationen ist Abstraktion wichtig. Das bedeutet den Übergang von konkreten Gegebenheiten in eine allgemein gültige Strukturierung der Algorithmen: • Die Abbildung der realen Objekte auf Daten und der Operationen auf einen vorgegebenen Vorrat von Anweisungen und Kontrollstrukturen (z.B. Abbildung einer Menge von Zahlen auf eine Liste mit den Operationen Einfügen, Löschen, Sortieren und Suchen). Abstraktion bedeutet: man konzentriert sich auf das Wesentliche; unwesentliche Anteile werden weggelassen. Struktur eines Algorithmus Jeder Algorithmus kann soweit in detaillierte Einzelschritte zerlegt (verfeinert) werden, bis er nur noch aus folgenden Grundstrukturen für die Operationen besteht: • elementarer Einzelschritt: nicht weiter zerlegbare Verarbeitung, z.B. "schalte rotes Licht ein". Beispiel in Java y = 2; • Sequenz: Folge von Einzelschritten (Anweisungen); Einzelschritte können zu Blöcken zusammengefasst werden. Beispiel schalte rotes Licht ein; warte eine Minute; schalte gelbes Licht ein; Beispiel in Java x = 1; y = 2; z = x + y; • Alternative: über eine Bedingung gesteuerte Verzweigung, falls b ungleich 0 dann gib a/b aus; sonst melde Fehler; ende falls Beispiel in Java if (x == 0) y = 2; else y = x + 1; 11 Gunnar Teege, UniBW München 2.2. ALGORITHMUS • Auswahl (Selektion): Verallgemeinerung der Alternative, Beispiel in Java switch (x) { case 0: y = 2; break; case 1: y = 0; break; case 2: y = -2; break; default: y = x+2; } • Iteration: Wiederholung einer Menge von Einzelschritten. wiederhole i = 1, .., n verarbeite aktuelles Konto Ki; Beispiel in Java while (x > 0) { x = x-1; y = x+y; } Mit diesen Strukturen können alle Algorithmen beschrieben werden. Blöcke Operationen können zu Blöcken zusammengefasst werden. Damit ist strukturiertes oder systematisches Programmieren möglich. Der gesamte Block wird als komplexe Anweisung verstanden und als Einheit in seiner Umgebung betrachtet, wobei Blöcke auch ineinander geschachtelt werden können. Blockbildung ist eine Vorstufe zur Modularisierung. Für jeden einzelnen Block ist nur ein Eingang und nur ein Ausgang notwendig. Die Klammerung von Operationen kann über spezielle Schlüsselwörter oder auch durch Klammern erfolgen, z.B. {} in C oder Java. Beispiel in Java { } int x = y = z = 2.2.4 x, y; a + 5; 16 - b + c; x * y; Darstellung von Algorithmen Es gibt eine Reihe unterschiedlicher Darstellungsmethoden für Algorithmen: informelle textuelle Beschreibung, programmiersprachliche Beschreibung, graphische Beschreibung, z.B. Flussdiagramme oder Nassi-Shneiderman. 12 Gunnar Teege, UniBW München 2.2. ALGORITHMUS Flussdiagramm Dieses Flussdiagramm dient zur Bestimmung des größten gemeinsamen Teilers von M und N; x und y sind Zwischenspeicher für Zwischenwerte; das Endergebnis wird in z gespeichert und kann damit ausgegeben werden. Beispiel: Größter gemeinsamer Teiler von M und N (Euklid’scher Algorithmus) x und y sind Variablen/Platzhalter. Die Zuordnung "x = M" bedeutet: der Speicherzelle mit dem Namen x wird der Wert/Inhalt von M zugeordnet. Animation größter gemeinsamer Teiler siehe Online Version 13 Gunnar Teege, UniBW München 2.2. ALGORITHMUS Programmiersprachliche Darstellung x = M; y = N; while (x != y) if (x > y) x = x - y; else y = y - x; z = x; "x != y" bedeutet hier die Bedingung "x ungleich y". 2.2.5 Algorithmus und Programm Programme sind spezielle Darstellungsformen für Algorithmen. Zusammenhang Der Zusammenhang zwischen einem Algorithmus und einem Programm läßt sich folgendermaßen beschreiben: • Ein Programm ist die Formulierung eines Algorithmus in einer Sprache, die der Computer verstehen und abarbeiten kann. • Aus der Sicht der „Maschine“ ist ein Programm eine abgeschlossene (also endliche) Folge von ausführbaren Anweisungen. • Damit ist eine Automatisierung des Algorithmus möglich. • Programmiersprachen sind ein Hilfsmittel zur Abbildung der Daten- und Kontrollstrukturen des Algorithmus in die Sprachkonstrukte des betreffenden Computers (Maschinensprache, Arbeitsspeicher). • Ausführbare Programme sind die Abbildung der Daten- und Kontrollstrukturen in die Interndarstellung des betreffenden Computers. Man spricht hier von Objektcode. Als Interndarstellung wird die Maschinensprache eines Rechners verwendet; die Maschinensprache ist abhängig von dem jeweiligen Hersteller des Prozessors. Zeitlicher Zusammenhang zwischen Algorithmus und Programm 14 Gunnar Teege, UniBW München 2.3. DATENTYPEN UND AUSDRÜCKE • Animation Programmentwicklung siehe Online Version 2.3 Datentypen und Ausdrücke In diesem und dem folgenden Abschnitt betrachten wir die Grundkonstrukte, die in allen Programmiersprachen Verwendung finden. • Informationen werden auf einem Rechner durch Daten repräsentiert. Die Umsetzung von Daten in Information wird als Interpretation bezeichnet. • Allgemeine Eigenschaften von Daten 1. Es existieren Basisdaten wie Zeichen, Wahrheitswerte (true, false), Zahlen (natürliche Zahlen, ganze Zahlen, Gleitkommazahlen). 2. Daten können angeordnet und miteinander in Beziehung gesetzt werden (z.B. hierarchische Datenstrukturen, Listen). 3. Algorithmen hängen in starkem Maße von der gewählten Datenstruktur (d.h. dem Datentyp und die unterstützten Operationen) ab. Durch geeignete Datenstrukturen können Algorithmen übersichtlicher und effizienter werden. • Datentypen Ein Datentyp ist die Zusammenfassung von Werten gleicher Art zu einer Klasse, z.B. alle ganzen Zahlen, alle Gleitkommazahlen, alle Zeichen. Es gibt 15 Gunnar Teege, UniBW München 2.3. DATENTYPEN UND AUSDRÜCKE verschiedene Arten von Datentypen, in Java hat eine Datentyp-Angabe die Form: datentyp ist: primitivertyp oder klassentyp oder reihungstyp Zur Schreibweise: So geschriebene Bezeichnungen sind Platzhalter für Programmstrukturen. In diesem Fall gibt es mehrere alternative Möglichkeiten für das erklärte Programmkonstrukt datentyp. – Primitive Datentypen Primitive Datentypen sind durch die Programmiersprache fest vorgegeben und werden mit Schlüsselwörtern bezeichnet. Die Verwendung der Schlüsselwörter ("keywords") sind abhängig von der jeweiligen Programmiersprache. In Java: primitivertyp ist: int oder long oder short oder byte oder float oder double oder char oder boolean Zur Schreibweise: So geschriebene Bezeichnungen sind Schlüsselwörter oder Zeichen, die direkt so im Programm auftreten müssen. ∗ ∗ ∗ ∗ ∗ ∗ int: Ausschnitt der ganzen Zahlen long, short, byte: andere Teilmengen der ganzen Zahlen. float: Menge der Gleitkommazahlen double: Menge der Gleitkommazahlen mit doppelter Genauigkeit char: Menge der Zeichen boolean: die Wahrheitswerte true und false. – Konstante Für primitive Datentypen sehen Programmiersprachen meist Schreibweisen vor, um Datenwerte („Konstante“) direkt anzugeben. Beispiele in Java 16 Gunnar Teege, UniBW München 2.3. DATENTYPEN UND AUSDRÜCKE Datentyp int mögliche Konstante 1783, -823 float -142.27f, 3.1415926f, 7.28e5f double -142.27, 3.1415926535, 7.28e5 char ’a’, ’X’, ’5’, ’%’ Dabei steht 7.28e5 für 7.28 * 105, also 728000. – Nichtprimitive vordefinierte Datentypen Diese Datentypen wären im Prinzip mit Mitteln der Programmiersprache durch den Programmierer definierbar, sind aber, da sie häufig benötigt werden, mit der Programmiersprache vordefiniert. Beispiel in Java In Java ist einer der wichtigsten vordefinierten Datentypen die Klasse String für Zeichenreihen. Für diesen Klassentyp sieht die Sprache sogar eine Schreibweise für Konstante vor: "Dies ist eine Zeichenreihe" – Datentyp Verbund Ein Verbund entsteht durch die Zusammenfassung mehrerer zusammengehöriger Datenwerte zu einem komplexen Datenwert. ∗ Beispiel In der folgenden Tabelle bildet jede Zeile einen komplexen Datenwert vom Datentyp „Person“ Vorname Name Adresse Alter Fritz Müller Hauptstr. 7 38 Hans Albers Bahnhofstr. 4 63 ∗ Programmiersprachliche Darstellung in Java In Java ist der Verbundtyp eine stark vereinfachte Form des Klassentyps. Wie bei allen Klassentypen ist eine Deklaration erforderlich, in der ein Name für den Typ vergeben wird: class Person { String vorname; String zuname; String adresse; int alter; } 17 Gunnar Teege, UniBW München 2.3. DATENTYPEN UND AUSDRÜCKE Anschließend ist der Name Person als Datentyp verwendbar. vorname, zuname, adresse und alter heißen Felder oder Instanzvariable des Verbunds. ∗ Allgemeine Schreibweise Ein Verbund-Deklaration hat in Java die allgemeine Form verbunddekl ist: class name { vardeklfolge } Ein Klassentyp wird in Java immer durch den in einer zugehörigen Deklaration vergebene Namen angegeben. klassentyp ist: name ∗ Zugriff auf Felder Ist teege ein Datenobjekt vom Verbund-Datentyp Person, so wird folgendermaßen auf das Adressen-Feld zugegriffen: teege.adresse Allgemeine Schreibweise Ein Feldzugriff hat in Java die allgemeine Form feldzugriff ist: ausdruck . name ∗ Im Gegensatz zu (Verbund-)Datentypen versteht man unter einer Datenstruktur den Datentyp zusammen mit der Menge von Operationen, die auf den Werten dieses Datentyps erlaubt sind. Beispiele für solche Operationen sind Addition und Substraktion bei ganzen Zahlen sowie Einfügen und Löschen bei Listen. – Weitere Datentypen Allgemeinere Klassentypen und Reihungstypen werden später in der Vorlesung behandelt. • Ausdrücke Ausdrücke dienen dazu, Werte von Datentypen zu berechnen. Sie können aus Konstanten, Variablen und Operationszeichen aufgebaut werden. – Allgemeine Schreibweise Ein Ausdruck hat in Java die allgemeine Form 18 Gunnar Teege, UniBW München 2.3. DATENTYPEN UND AUSDRÜCKE ausdruck ist: konstante oder speicherplatz oder ausdruck + ausdruck oder ( ausdruck ) oder ... – Variable Das Konzept der „Variable“ findet sich in den meisten Programmiersprachen. Es wurde aus der Mathematik übernommen und dahingehend abgewandelt, dass eine Variable nacheinander unterschiedliche Werte repräsentieren kann. ∗ Eine Variable ist eine mit Namen versehene Speicherzelle für Datenwerte; Variable können gelesen und geschrieben werden. Im letzten Fall spricht man auch von Zuweisen eines Wertes an eine Variable. ∗ Jeder Bezeichner (Name) einer Variablen muss i.a. vor seiner ersten Benutzung deklariert werden. Dabei wird festgelegt, dass der Name für eine Variable verwendet wird und meist wird der Variable dabei ein Datentyp zugeordnet. Beispiele in Java int i; char c,d,hilfsvar; class Paar { int i1, i2; } Paar p; Allgemeine Schreibweise Eine Variablendeklaration hat in Java die allgemeine Form vardekl ist: datentyp initvarfolge ; initvarfolge ist: variable [= ausdruck] oder variable [= ausdruck] , varfolge Zur Schreibweise: Mit [ und ] geklammerte Abschnitte sind optionale Teile des erklärten Programmkonstrukts und können auch weggelassen werden. Meist sind beliebig viele Variablendeklarationen hintereinander zulässig: 19 Gunnar Teege, UniBW München 2.4. PROGRAMMKONSTRUKTE vardeklfolge ist: vardekl oder vardekl vardeklfolge Der in einer Variablendeklaration festgelegte Name kann dann wie ein Zugriff auf das Feld eines Verbundes als Ausdruck für den jeweils in der Variable gespeicherten Wert verwendet werden: speicherplatz ist: variablenname oder feldzugriff oder ... Beispiele für Ausdrücke – 2 + 15 * (10 - 6) – a + b wobei a und b Variable sind 2.4 Programmkonstrukte Ein Programm besteht aus einer Menge von Anweisungen, die entweder Werte an Variable zuweisen oder den Kontrollfluss steuern. Der Kontrollfluss bestimmt die Folge der Anweisungen, die bei einer Programmausführung ausgeführt werden. Die allgemeine Form einer Anweisung in Java umfasst u.a. folgende Möglichkeiten. anweisung ist: zuweisung ; oder alternative oder auswahl oder wiederholung oder block oder ... 20 Gunnar Teege, UniBW München 2.4.1 2.4. PROGRAMMKONSTRUKTE Zuweisungen In einer Zuweisung wird einer Variablen ein neuer Wert zugeordnet. Ein ggf. vorhandener alter Wert wird dabei gelöscht („überschrieben“). • Eine Variable entspricht einem Bereich im Arbeitsspeicher, der über einen symbolischen Namen angesprochen werden kann (Speicherzelle). Variablen können Daten beliebiger Datentypen speichern. Eine einzelne Variable ist aber in vielen Programmiersprachen auf Daten eines Datentyps festgelegt. Die Syntax von Zuweisungen kann bei den verschiedenen Programmiersprachen unterschiedlich sein, z.B. nur = Zeichen oder := Zeichen. • Beispiele in Java i = 2; i = i + 2; /* Wert von i wird um 2 erhöht und wieder an i zugewiesen */ x = x * (y + 1); Zuweisungen werden folgendermaßen bearbeitet: Zunächst wird die rechte Seite der Zuweisung ausgewertet. Das Ergebnis wird anschließend der linken Seite als Wert zugeordnet. Die linke Seite ist eine Variable und kein arithmetischer Ausdruck. • Allgemeine Schreibweise Die allgemeine Form einer Zuweisung in Java ist folgende. zuweisung ist: speicherplatz = ausdruck • Zuweisung in Java Obwohl eine Zuweisung von der Logik her (und in den meisten Programmiersprachen) eine Anweisung ist, wird sie in Java auch als spezielle Form eines Ausdrucks behandelt. Damit nehmen Zuweisungen in Java eine „Zwitterstellung“ ein. Sie können sowohl einen Ergebniswert beschreiben als auch die Aktivität des Speicherns eines Wertes in einer Variablen. Das Ziel dieser Designentscheidung in Java ist eine kompaktere (aber nicht unbedingt lesbarere) Schreibweise. ausdruck ist: ... oder zuweisung oder ... 21 Gunnar Teege, UniBW München 2.4. PROGRAMMKONSTRUKTE – Wert einer Zuweisung Der Wert, den eine Zuweisung als Ausdruck beschreibt, ist der an die Variable zugewiesene Wert. Daher lässt sich jeder in einem Programm durch einen Ausdruck angegebene Wert „nebenbei“ an eine Variable zuweisen. Beispiel Folgende Ausdrücke liefern den gleichen Wert, im zweiten Fall werden aber zusätzlich Teilergebnisse in Variable gespeichert. 2 + 15 * (10 - 6) und 2 + (z = 15) * (y = (10 - (x = 6))) • Kurzformen Für häufig vorkommende Fälle von Zuweisungen gibt es abkürzende Schreibweisen in Java: – Im Fall, dass die Variable, der zugewiesen wird, im Ausdruck nochmals auftritt, steht die Schreibweise var op= ausdruck für var = var op ausdruck wobei op ein Operator-Zeichen (+, -, *, ...) ist. Beispiel i += 25 – Im Spezialfall, in dem der Ausdruck nur aus der Konstanten 1 besteht, kann weiter abgekürzt werden: op op var steht für var op= 1 Beispiel ++i ∗ Hinweis Es gibt auch die Form var op op Sie hat als Zuweisung die gleiche Wirkung, liefert als Ausdruck aber einen anderen Wert, nämlich den Wert der Variablen vor Ausführung der Zuweisung. Beispiel 22 Gunnar Teege, UniBW München 2.4. PROGRAMMKONSTRUKTE Nach Ausführung von i = 5; x = i++; hat i den Wert 6, x den Wert 5. Nach Ausführung von i = 5; x = ++i; haben i und x den Wert 6. 2.4.2 Alternativanweisungen Die Alternativanweisung erlaubt die Auswahl von Alternativen abhängig von einer Bedingung. Die Alternativen sind selbst wieder Anweisungen. • Allgemeine Schreibweise Die allgemeine Form einer Alternativanweisung in Java ist folgende. alternative ist: if ( ausdruck ) anweisung [ else anweisung ] Der Datentyp des Ausdrucks muss boolean sein. • Beispiel 1 if (a > b) z = a; /* Zuweisung an die Variable z */ else z = b; • Beispiel 2 (Schachteln von Alternativen) if (a > b) z = a; else if (a < b) z = b; else z = 0; • Neben einfachen Alternativanweisungen gibt es in den meisten Programmiersprachen noch das verallgemeinerte Konstrukt der Auswahl (switch, case). • Allgemeine Schreibweise Die allgemeine Form einer Auswahlanweisung in Java ist folgende. 23 Gunnar Teege, UniBW München 2.4. PROGRAMMKONSTRUKTE auswahl ist: switch ( ausdruck ) { fallfolge } fallfolge ist: fall oder fall fallfolge fall ist: case ausdruck : [ anweisungsfolge ] oder default: [ anweisungsfolge ] anweisungsfolge ist: anweisung oder anweisung anweisungsfolge Dabei muss der Datentyp aller Ausdrücke einer von char, byte, short oder int sein. • Überspringen von Fällen In den meisten Anwendungen sollen in jedem Fall nur die direkt zum Fall gehörigen Anweisungen ausgeführt werden. Dies geschieht in C jedoch nicht automatisch, sondern die Auswahlanweisung muss am Ende des Falls explizit verlassen werden. Zu diesem Zweck (und zum Verlassen von Schleifen) existiert eine spezielle „break“-Anweisung in Java: anweisung ist: ... oder break; oder ... • Beispiel für Auswahlanweisung switch (a) { case 1: case 2: case 3: z = a + 10; break; case 4: case 17: if (b > 0) z = a + b; else z = a; break; default: z = a - 1; break; } 24 Gunnar Teege, UniBW München 2.4.3 2.4. PROGRAMMKONSTRUKTE Schleifen Eine Schleife beschreibt die wiederholte Ausführung einer Anweisungsfolge. Dabei wird zusätzlich festgelegt, wann die Wiederholung beendet werden soll. • Allgemeine Schreibweise Es gibt mehrere Varianten von Schleifen in Java: wiederholung ist: while-schleife oder for-schleife oder ... – Die while-Schleife Die allgemeine Form einer while-Schleife in Java ist folgende. while-schleife ist: while ( ausdruck ) anweisung Der Datentyp des Ausdrucks muss boolean sein. Vor jedem Schleifendurchlauf wird der Ausdruck ausgewertet. Die Schleife wird nur fortgesetzt, wenn das Ergebnis der Wert true ist. – Die for-Schleife Die for-Schleife in Java lässt sich beschreiben als abkürzende Schreibweise für eine häufig verwendete Form der while-Schleife: for (vardekl ausdruck; zuweisung) anweisung steht für vardekl while (ausdruck) { anweisung zuweisung; } • Beispiel 1 int N = 10, sum = 0; for (int i = 0; i < N; i++) sum += i; – Bestandteile einer for-Schleife Deklaration und Anfangswert der Laufvariable i, z.B. i =0 Endwert der Laufvariable i, z.B. i < N Inkrementierung (Hochzählen) der Laufvariable i nach jedem Schleifendurchlauf, z.B. i++ Anweisungen, die bei jedem Schleifendurchlauf ausgeführt werden, z.B. sum += i 25 Gunnar Teege, UniBW München 2.5. MODULARISIERUNG VON PROGRAMMEN • Beispiel 2 sum = 1 while (i > 0) { sum = sum * i; i = i - 1; } • Beispiel 3 Einfache unendliche Schleife while (true) { ...... } • Neben der while-Schleife gibt es auch noch andere Konstruktionen, wie z.B. do-while/repeat-until, die die Bedingungen erst am Ende der zu wiederholenden Anweisung überprüfen. 2.4.4 Blöcke Blöcke fassen sowohl Anweisungen als auch Variablendeklarationen zusammen. Die allgemeine Schreibweise für Blöcke in Java ist damit: block ist: { deklanweisfolge } deklanweisfolge ist: deklanweis oder deklanweis deklanweisfolge deklanweis ist: vardekl oder anweisung 2.5 Modularisierung von Programmen Die wichtigste Technik für den systematischen Aufbau von Programmen ist die Modularisierung. Dabei wird das Programm in mehrere eigenständige Einheiten, die Module zerlegt. 26 Gunnar Teege, UniBW München 2.5.1 2.5. MODULARISIERUNG VON PROGRAMMEN Zerlegung von Problemen und Algorithmen Einen modularisierten Algorithmus erhält man auf natürliche Weise, wenn man bereits das Problem in mehrere Teilprobleme zerlegt. Dies ist die wesentliche Technik beim Umgang mit komplexeren Problemstellungen. Zerlegung von Problemen Durch Zerlegung eines Problems erhält man einfachere Teilprobleme, die man jeweils separat lösen kann (Prinzip des „divide and conquer“). Dabei ist auch die Verteilung der Teilprobleme auf verschiedene Entwickler gut möglich (Teamarbeit). • Teilprobleme Teilprobleme können selbst wieder weiter zerlegt werden. Eine Zerlegung ist nicht mehr nötig, wenn eine direkte Lösung möglich ist. – Ad-hoc-Lösung Eine direkte Lösung kann möglich sein, weil das Teilproblem so einfach ist, dass ein Lösungsalgorithmus unmittelbar angebbar ist. – Bekannte Lösung Ein Teilproblem kann auch als bekannt erkannt werden und es kann ein existierender Lösungsalgorithmus verwendet werden. Sammlungen existierender Lösungsalgorithmen werden auch als „Bibliotheken“ bezeichnet. Zusammenfügen der Teile Die Lösungen für die Teilprobleme müssen zu einer Lösung für das Gesamtproblem zusammengesetzt werden. Die Art der Zusammensetzung wird bereits beim Zerlegen des Problems ermittelt und festgelegt. Dabei sind zwei Aspekte relevant. • Datenfluss Welche Eingaben oder Zwischenergebnisse des Gesamtproblems sind Eingaben für das Teilproblem? Wie gehen Ergebnisse des Teilproblems in das Gesamtproblem ein? – Schnittstelle Zu diesem Zweck wird für jedes Modul eine „Schnittstelle“ festgelegt, die die Ein- und Ausgaben genau beschreibt. Bei der Verwendung des Moduls muss 27 Gunnar Teege, UniBW München 2.5. MODULARISIERUNG VON PROGRAMMEN genau angegeben sein, wie die Schnittstelle mit der Umgebung verknüpft wird, also welche Daten aus der Umgebung an das Modul übergeben werden und was mit den Ausgaben weiter geschieht. • Ablauf Wann wird das Modul beim Ablauf der Gesamtlösung aktiviert? – Dies wird mit den üblichen Mitteln festgelegt, mit denen der Ablauf eines Algorithmus beschrieben wird, also Sequenz, Alternativen und Iteration. Das Modul wird wie ein komplexer Einzelschritt in den Ablauf des Gesamtalgorithmus eingebettet. Vorteile der Modularisierung Die Modularisierung eines Algorithmus /Programms hat mehrere wichtige Vorteile. • Verständlichkeit Ein modularisiertes Programm ist i.a. leicher zu verstehen, da jedes Modul für sich erfasst werden kann. Für das Verständnis des Gesamtprogramms kann dann jedes Modul in seiner Gesamtbedeutung verwendet werden, anstatt immer die Details seiner Einzelschritte berücksichtigen zu müssen. • Unabhängige Entwicklung Jedes Modul kann aus dem zugehörigen Teilproblem unabhängig vom Rest des Gesamtproblems entwickelt werden. Dies reduziert die Komplexität bei der Entwicklung, setzt aber eine saubere und korrekte Zerlegung des Gesamtproblems voraus. • Mehrfachverwendung Tritt ein Teilproblem mehrfach im Rahmen des Gesamtproblems auf, muss es nur einmal behandelt werden und im Algorithmus muss nur einmal die Lösungsvorschrift beschrieben werden. • Wiederverwendung Häufig treten Teilprobleme eines Problems auch als Teilprobleme anderer Probleme auf. Wurde der Algorithmus modularisiert, lassen sich Module ggf. direkt als Module in anderen Algorithmen wiederverwenden. 28 Gunnar Teege, UniBW München 2.5. MODULARISIERUNG VON PROGRAMMEN Beispiel: Quadrate zeichnen Dieses Beispiel zeigt Mehrfachverwendung eines Programm-Moduls und seine Einbettung in das Gesamtprogramm. Aufgabe: Zeichnen von zwei konzentrischen Quadraten • Plotterfunktionen Gegeben sind folgende Plotter-Grundfunktionen: – Bewege (x): bewege Zeichenstift um Länge x in aktuelle Zeichenrichtung – Links (x): drehe Zeichenrichtung um x Grad nach links – Rechts (x): drehe Zeichenrichtung um x Grad nach rechts – Stift heben – Stift senken • Teilaufgaben Es existieren die folgenden beiden Teilaufgaben (wobei der Zeichenstift am Start in der Mitte des inneren Quadrats ist). – Position auf A; Quadrat 10 cm zeichnen – Position auf B; Quadrat 20 cm zeichnen 29 Gunnar Teege, UniBW München 2.5. MODULARISIERUNG VON PROGRAMMEN • Definition eines Moduls Kopf Modul Quadratzeichnen(Größe) Rumpf Stift senken wiederhole 4-mal Bewege (Größe) Links (90) Stift heben – Modul ist ein Schlüsselwort (keyword); es markiert den Beginn einer Moduldefinition. Der Name des Moduls ist "Quadratzeichnen". – Größe ist hier ein formaler Platzhalter; man bezeichnet ihn als formalen Parameter. Er spezifiziert in unserem Fall die Länge einer Quadratkante. Bei der Nutzung des Moduls muss dem formalen Parameter ein aktueller Wert zugewiesen werden. • Nutzung des Moduls (Hauptprogramm) Links (45) Bewege (10cm*1/2* sqrt(2)) Links (135) Quadratzeichnen (10cm) Rechts (135) Bewege ((20cm-10cm)*1/2*sqrt(2)) Links (135) Quadratzeichnen (20cm) Rechts (180) "sqrt(2)" berechnet die Wurzel von 2. 30 Gunnar Teege, UniBW München 2.5. MODULARISIERUNG VON PROGRAMMEN – Der Stift startet in der Mitte mit der eingezeichneten Orientierung. Nach Ablauf des Algorithmus steht der Stift in Punkt B mit der Orientierung nach oben. Beginn des Zeichnens ist Position A; linke Kante wird zuerst gezeichnet; nach dem ersten Quadratzeichnen wurde noch eine 90 Grad Drehung durchgeführt, d.h. Orientierung ist wieder nach unten. Die Argumente des Moduls Quadratzeichnen sind nun Aktualparameter. 2.5.2 Module In vielen Programmiersprachen (z.B. C, C++, Java) existieren Funktionen (Prozeduren) als Mittel zur Strukturierung von Programmen. Allgemeine Schreibweise in Java In Java werden Funktionen i.a. als Methoden bezeichnet. Die Definition einer Methode in Java hat die Form 31 Gunnar Teege, UniBW München 2.5. MODULARISIERUNG VON PROGRAMMEN methdekl ist: static datentyp name ( [ parameterfolge ] ) block parameterfolge ist: parameter oder parameter , parameterfolge parameter ist: datentyp variable • Aufruf / Verwendung einer Methode Die Verwendung einer Methode ist eine spezielle Form eines Ausdrucks. Das Ergebnis des Ausdrucks ist das Methodenergebnis. Wesentlicher Teil des Ausdrucks sind Teilausdrücke für die an die Methode zu übergebenden Parameterwerte. ausdruck ist: ... oder methaufruf oder ... methaufruf ist: name ( [ ausdruckfolge ] ) ausdruckfolge ist: ausdruck oder ausdruck , ausdruckfolge • Ergebnisangabe Um in einer Methode festlegen zu können, welches Ergebnis ein Aufruf der Methode liefert, existiert eine spezielle Anweisung. Sie hat die Form: anweisung ist: ... oder return [ ausdruck ] ; oder ... 32 Gunnar Teege, UniBW München 2.6. REKURSION • Methoden ohne Ergebnis Es gibt auch Module, die nur Aktivitäten beschreiben sollen und kein Ergebnis haben. Diese werden häufig auch als „Prozedur“ bezeichnet. In Java muss in diesem Fall der Pseudotyp „void“ als Ergebnistyp in der Methodendefinition angegeben werden. Der Aufruf einer solchen Methode ist zwar syntaktisch ein Ausdruck, kann aber nur sinnvoll als Anweisung verwendet werden. Beispiel Folgendes ist ein Beispiel für die Definition einer Methode in Java: static int addiere10fach(int sum1, int sum2) { int h; h = 10 * sum2; return sum1 + h; } Mögliche Aufrufe dieser Methode sind die folgenden: addiere10fach(17,4) addiere10fach(5, addiere10fach(22, 3 + 6 * 9)) • Parameter Die Parameter, die als Namen in der Methodendefinition angegeben sind, werden als „formale“ Parameter bezeichnet. Sie verhalten sich wie Variable, denen beim Aufruf der Methode die Eingabewerte zugewiesen werden. Die Eingabewerte, die im Methodenaufruf durch Ausdrücke angegeben werden, bezeichnet man als „aktuelle“ Parameter. Die Zuweisung der aktuellen Parameter an die formalen Parameter geschieht implizit gemäß der Position der Ausdrücke im Methodenaufruf und der formalen Parameter in der Methodendefinition. 2.6 Rekursion Unter Rekursion versteht man eine spezielle Form der Modularisierung, bei der das zu definierende Modul auch in der Definition selbst benutzt wird. • Bei bestimmten Algorithmen und Datenstrukturen ist mit Rekursion eine „natürlichere“ Darstellung möglich. • Beispiel ’Fibonacci-Zahlen’ 33 Gunnar Teege, UniBW München 2.6. REKURSION Bei den Fibonacci-Zahlen ist bereits die übliche mathematische Problemstellung rekursiv formuliert. Eine direkte Umsetzung als rekursiver Algorithmus bietet sich daher an. – Definition fib(n) = fib(n-1) + fib(n-2) für n>2 fib(1) = fib(2) = 1 Wertebereich: n>=1, mit n natürliche Zahl – Algorithmus Modul fib(n) Falls n kleiner 3 dann Ergebnis = 1 sonst Ergebnis = fib(n-1) + fib(n-2) – Ausführungslauf, z.B. fib(4) fib(4) - fib(3) -- fib(2) = 1 -- fib(1) = 1 - fib(3) = 2 - fib(2) = 1 fib(4) = 3 • Beispiel ’Größter gemeinsamer Teiler’ Gegeben seien zwei Zahlen a, b mit a>0 und b>0. Gesucht ist der größte gemeinsame Teiler ggT(a, b) der beiden Zahlen. Berechnung mit dem Algorithmus nach Euklid. – Idee 34 Gunnar Teege, UniBW München 2.6. REKURSION Wenn a < b, dann ist der ggT(a,b) der gleiche wie ggT(a,b-a): Wenn die Zahl x die Zahlen a und b teilt, dann auch b-a. Und wenn es einen größeren Teiler von a und b gäbe, würde er auch b-a teilen. – Algorithmus Modul ggT(a ,b) Falls a = b, dann Ergebnis = a falls a < b dann Ergebnis = ggT(a, b-a) falls a > b dann Ergebnis = ggT(a-b, b) • Beispiel ’Türme von Hanoi’ Gegeben sind drei senkrechte Stäbe und n Scheiben verschiedener Größe. Die Aufgabe lautet: Übertrage Turm von Scheiben von einem Stab auf einen anderen, wobei stets nur eine Scheibe bewegt wird und nie eine größere Scheibe auf einer kleineren liegt. – Rekursive Lösung für n Scheiben übertrage n Scheiben von b nach a: übertrage n-1 Scheiben von b nach c letzte Scheibe von b nach a übertrage n-1 Scheiben von c nach a ∗ Algorithmus Die Definition von solveTvH beinhaltet einen Aufruf von solveTvH (mit anderen Parametern) 35 Gunnar Teege, UniBW München 2.6. REKURSION Modul solveTvH(n, Quelle, Ziel, Zw) /* Zw ist das Zwischenlager */ Falls n = 1 dann bewege Scheibe von Quelle nach Ziel sonst solveTvH(n-1, Quelle, Zw, Ziel); /* Ziel dient hier als Zwischenlager; Zwischenlager ZW ist für diese Anweisung das Ziel.*/ bewege Scheibe von Quelle nach Ziel; solveTvH(n-1, Zw, Ziel, Quelle); /* Zw ist die Quelle und muss nach Ziel bewegt werden; Quelle dient nun als Zwischenlager. Man beachte hier, das jeweils die Rolle den Plätze vertauscht wird; der Zwischenspeicher kann die Rolle der Quelle, des Ziels und des Zwischenspeichers übernehmen.*/ /* ... */ bezeichnet einen Kommentar, und keine ausführbaren Anweisungen. – Aufrufschachtelung für n=3 Aufruf solveTvH (3, b, a, c) führt zu den nachfolgenden Rekursionen: ∗ 3bac ( 2bca ( 1bac (b → a); b → c; 1acb (a → c) ); b → a; 2cab ( 1cba (c → b); c → a; 1bac (b → a) ) ) 3bac entspricht dem Aufruf solveTvH (3, b, a, c) b → a entspricht: bewege Scheibe von b nach a 36 Gunnar Teege, UniBW München 2.6. REKURSION – Zahl der Schritte: 2n-1; n ist die Anzahl der zu bewegenden Scheiben. – Anwendung in der Praxis Das Lagerhaltungssystem des Hamburger Container-Hafens ermittelt, welche Portalkräne gerade frei, welche Positionen im Container-Lager noch nicht belegt sind und ermittelt daraus den optimalen Platz, wobei der Ansatz von "Türme von Hanoi" Verwendung findet: Kein Container darf auf einer anderen Kiste abgestellt werden, die zu einem füheren Zeitpunkt als er selbst wieder abgeholt wird, zum Weitertransport per Bahn, LKW oder wieder per Schiff. Animation Türme von Hanoi siehe online Version Animation Rekursionsarten 37 Gunnar Teege, UniBW München 2.7. OBJEKTORIENTIERTE PROGRAMMIERUNG siehe online Version 2.7 Objektorientierte Programmierung Bei der objektorientierten Programmierung (z.B. Sprache Java) wird ein Softwaresystem durch eine Menge von Objekten realisiert, im Gegensatz zur prozeduralen Programmierung (z.B. Sprache C), wo die Anweisungen im Vordergrund stehen. • Im objektorientierten Programmieren stehen die Daten im Vordergrund. Daten werden in Objekten zusammengefasst ("Verkapselung"). Die Funktionen können lokal zu den Objekten definiert werden. • Die Funktionen werden Methoden genannt. • Prozedurales / Objektorientieres Programmieren Häufig wird zwischen prozeduraler Programmierung und objektorientierter Programmierung unterschieden. 38 Gunnar Teege, UniBW München 2.7. OBJEKTORIENTIERTE PROGRAMMIERUNG – Prozedurales Programmieren Computer bekommt eine Sequenz von Anweisungen, die er ausführt, dann wartet er auf nächste Eingabe. Drei Basiselemente: Sequenz, Auswahl (ifthen-else), Iteration. Trennung von Daten und Anweisungen. – Objektorientiertes Programmieren Nicht Mengen von Anweisungen, sondern Objekte. Ein Objekt hat Attribute, Methoden und Ereignisbehandlung. Zusammenfassung von (zusammengehörigen) Daten und Anweisungen. Methoden entsprechen Funktionen; sie nutzen und verändern die Attribute des Objektes. Ereignisse werden bei der Ausführung von Methoden ausgelöst. Beispiel eines Ereignisses ist die Division durch 0. • Objekt -Klasse Ein Objekt ist ein Exemplar (Instanz) eines Gegenstandes oder Begriffs der Modellwelt; ein Objekt ist möglichst stark an Gegenstand oder Begriff der realen Welt angelehnt. – Objekt Ein Objekt hat 1. eine Identität, z.B. vom Benutzer vergebene Namen. Objekte haben in der Regel auch einen intern erzeugten Identifikator, z.B. (Netzadresse des erzeugenden Rechners, Zeitstempel). Dieser Identifikator ist für den Benutzer meist nicht sichtbar; der Benutzer verwendet Namen, der intern in den Identifikator abgebildet wird. Falls der Name nicht eindeutig ist, müssen zusätzliche Eigenschaften das Objekt eindeutig identifizieren; Werkzeuge benutzen jedoch internen Identifikator zur Ansteuerung der Objekte. 2. einen Zustand, definiert durch private Daten ("Instanzvariable"), 3. ein Verhalten, spezifiziert durch eine Menge von Operationen (Methoden), die auf den privaten Daten agieren und Operationen anderer Objekte aufrufen können; 4. Beziehungen zu anderen Objekten. – Klasse Objekte mit gleichem Verhalten werden zu Klassen zusammengefasst. Ein Objekt "weiß", zu welcher Klasse es gehört. In der Klasse wird festgelegt: Die Algorithmen für das Verhalten (Methoden) und welche Attribute die Objekte haben. 39 Gunnar Teege, UniBW München 2.7. OBJEKTORIENTIERTE PROGRAMMIERUNG ∗ Beispiel: Klassendefinition public class circle { double x, y; // Koordinaten der Kreismitte double r; //Radius des Kreises // Konstruktor für die Erzeugung von Objekten: public circle (double xcoord, double ycoord, double radius) {x = xcoord; y = ycoord; r = radius;} // Methoden, die Umfang und die Fläche // als Ergebnis liefern: public double circumference(){return 2 * 3.14159 * r;} public double area(){return 3.14159 * r * r;} } double bezeichnet eine Variable mit doppelter Genauigkeit. • Erzeugen eines Objekts Nach der Spezifikation einer Klasse können beliebig viele Objekte für diese Klasse erzeugt werden => Erzeugen einer Objektinstanz. Man spricht deshalb in diesem Zusammenhang auch gern von der Objektinstanziierung. Jedes Objekt hat seine eigenen Variablen, während die Methoden gemeinsam benutzt werden. – Beispiel circle kreis1, kreis2; // Vereinbarung zweier Variable double flaeche, umfang; kreis1 = new circle(2.0,2.0,1.0); // Erzeugen des Objekts kreis1 // Mittelpunkt: (2,2), Radius: 1.0 // Abfragen der Fläche von kreis1: flaeche = kreis1.area(); // Erzeugen des zweiten Kreises kreis2 = new circle(4.0, -1.0, 10.0); // Abfragen des Umfangs von kreis2: umfang = kreis2.circumference() .............. Man beachte, dass bei der Berechnung von Fläche und Umfang das betreffende Objekt (kreis1, kreis2) explizit angegeben wird. 40 Gunnar Teege, UniBW München 2.7. OBJEKTORIENTIERTE PROGRAMMIERUNG Alle Instanzen einer Klasse benutzen folgendes gemeinsam: a) denselben Code für ihre Methoden und b) dieselben Namen für ihre Variablen. • Vererbung Vererbung ist ein Werkzeug zum Organisieren und Konstruieren von Klassen, wobei existierende Klassen wiederverwendet werden können. – Definition - Vererbung Seien K und Ki, i = 1,..,n Klassen; Vererbung ist eine Beziehung zwischen K und den Ki, wobei Struktur und Verhalten von K durch Struktur und Verhalten der Ki bestimmt wird; K "erbt" von den Klassen Ki; ∗ Vererbung definiert eine Beziehung zwischen Klassen; K heißt Unterklasse (Subklasse) von Ki; Ki nennt man Oberklasse (Superklasse) von K; ∗ Vererbung bewirkt, dass Unterklassen über alle Eigenschaften (Attribute, Operationen und Beziehungen) der Oberklasse verfügen; Vererbung kann über mehrere Stufen einer Hierarchie hinweg erfolgen. Vererbung bezieht sich auf Variable und Methoden; ∗ Unterscheidung zwischen Einfachvererbung und Mehrfachvererbung 41 Gunnar Teege, UniBW München 2.8. PROGRAMMIERSPRACHEN Einfachvererbung: eine Klasse hat nur eine direkte Oberklasse, d.h. n=1. Mehrfachvererbung: eine Klasse hat mehrere direkte Oberklassen Beispielsweise kann die Klasse Autoreifen sowohl von der Klasse Auto als auch von der Klasse Rad erben. – Beispiel public class GraphicCircle extends circle { // Es werden automatisch die Variablen und Methoden // der Klasse circle geerbt; // nur die neuen Informationen müssen hier // aufgeführt werden: // Die Farben für Rand und Füllfläche. color o, f; public GraphicCircle (double xcoord, double ycoord, double radius, color outline, color fill) {super(xcoord,ycoord,radius); o = outline; f = fill;} public void draw(Window dw) {dw.drawCircle(x, y, r, o, f;} } Die Erweiterung gegenüber Circle besteht darin, dass der Kreis nun mit Rand und Füllfarbe dargestellt werden kann. Die Beschreibung der Klasse "circle" (Oberklasse) spezifiziert die privaten Daten "x, y, r"; die Klasse "GraphicCircle" (Unterklasse) spezifiziert die privaten Daten "o, f". 2.8 Programmiersprachen Auf der untersten Ebene verarbeitet ein Rechner Instruktionen, die in einer Maschinensprache spezifiziert sind. Zum besseren Umgang mit Maschinensprachen 42 Gunnar Teege, UniBW München 2.8. PROGRAMMIERSPRACHEN wurden bereits frühzeitig sogenannte Assemblersprachen eingesetzt. Diese sind jedoch sehr Hardware-nahe, und machen es schwierig komplexe Programme zu schreiben . Deshalb wurden sogenannte höhere Programmiersprachen, z.B. C oder Java bereitgestellt, die die Programmierung erleichtern sollen. • Programme, die in einer höheren Programmiersprache erstellt wurden, müssen in ein entsprechendes Programm einer Maschinensprache transformiert werden. • Interpretierer und Übersetzer – Ein Interpretierer (Interpreter) ist ein Programmiersystem, das Anweisungen schrittweise zergliedert, daraus zustandsähnliche Aktionen ableitet und sofort ausführt (es wird jeweils nur eine Programmanweisung betrachtet, und nicht das gesamte Programm; für jede Anweisung wird dann ein Maschinensprache-Unterprogramm des Interpretierers aufgerufen, das der Realisierung der Anweisung entspricht). – Neben Interpretierern gibt es noch sogenannte Übersetzer oder Compiler, welche die Anweisungen eines Programms in einem Durchlauf analysieren und komplett in Maschinensprache umwandeln. – Vorteile von Interpretierern ∗ Interpretierer sind einfacher zu realisieren als Übersetzer (Compiler) ∗ Ermöglicht Quellprogramm-bezogenes, inkrementelles Testen – Nachteile von Interpretierern ∗ Ineffizient bei einfachen, häufig benutzten Funktionen ∗ Fehler, die sonst Übersetzer findet, werden erst zur Laufzeit entdeckt – Beispiele für Interpretierer(sprachen) ∗ Basic ∗ Kommandosprachen von Betriebssystemen, z.B. Shell in DOS Eingabefenster ∗ Skriptsprachen (z.B. JavaScript) • Scriptsprachen Scriptsprachen ermöglichen dem Endanwender, innerhalb einer Applikation (z.B. Textsystem) zu programmieren. – Ziele von Scriptprogrammen ∗ Anpassen der Applikation an eigene Umgebung 43 Gunnar Teege, UniBW München 2.8. PROGRAMMIERSPRACHEN ∗ Definition von Macros zur Erleichterung der Eingabe. ∗ zur automatische Aktualisierung, z.B. von Feldern in einer Tabellenkalkulation ∗ zur Einbettung von Funktionen in Web-Seiten – Funktionen/Programme erstellt mit Hilfe von Scriptsprachen werden nicht übersetzt, sondern nach dem Programmaufruf direkt ausgeführt, d.h. der Programmcode wird Zeile für Zeile gelesen und ausgeführt; Verwendung von Interpretierer. – Tabellenkalkulation Dokumente einer Tabellenkalkulation heißen Rechenblätter. Sie bestehen aus Zellen, die in endlich vielen Zeilen und Spalten organisiert sind. Zellen enthalten Daten verschiedener Sorten (Zahl, Währung, Datum, Text, ...) Formeln, die aus vordefinierten Funktionen zusammengesetzt sind (Summe, Mittelwert, Runden, ...) ∗ variable Daten werden mit Hilfe von Verweisen auf andere Zellen in Formeln eingegeben, z.B. Summe(A1:A4), Summe(A1;B1;C1) ∗ nur Funktionen mit einer Datenausgabeleitung, d.h. es gibt keinen Datenspeicher ⇒ nicht jeder Algorithmus kann in einer Tabellenkalkulation dargestellt werden. ∗ Auswertung von Formeln bei Zellenänderung. • Auswahl einer Programmiersprache Im Prinzip sind alle Programmiersprachen gleichwertig, d.h. sie erlauben die Formulierung aller Algorithmen. In der Praxis gibt es aber Unterschiede, die bei der Entscheidung für die Verwendung einer Programmiersprache in einem Entwicklungsprojekt helfen. – Kriterien für die Auswahl einer Programmiersprache ∗ Technische Kriterien Angemessenheit für Problem Übersichtlichkeit, Strukturiertheit, Selbst-Dokumentation Unterstützung fortschrittlicher Softwareentwicklungskonzepte Unterstützung/Einbindung von Systemdiensten und Systemstrukturen (des Betriebssystems) Qualität und Leistungsfähigkeit des Übersetzers Vorhandene Entwicklungs- und Testhilfen; vorgefertigte Routinen Übertragbarkeit, Wiederverwendbarkeit 44 Gunnar Teege, UniBW München 2.8. PROGRAMMIERSPRACHEN ∗ Nicht-technische Kriterien Verträglichkeit mit vorhandenen Daten und Programmen Erfahrung der Benutzer Wünsche des Auftraggebers Lizenzgebühren und -bedingungen Güte der Lieferanten-Unterstützung Standardisierung Zukünftige Bedeutung der Sprache – Empfehlungen wenn ... ... dann einfache Programme, Anwendungserweiterungen Basic, Visual Basic, Python, Perl Datenbank-Anwendung Programmlogik und komplexe C, C++ , Java Datenbank-Anwendung und einfache Programm- SQL, Reportgenerator logik Technisch-wissenschaftliche Anwendung und C, C++, Java (Datenbank oder komplexe E/A-Strukturen) und Portabilität (System-Software oder PC-Anwendung) und Por- C, C++, Java tabilität Künstliche Intelligenz-Anwendung Prolog, LISP Internet-Anwendung und Portabilität Java, PHP, Python 45 Kapitel 3 Datenstrukturen und Algorithmen In diesem Kapitel werden einige Klassen von Algorithmen vorgestellt, insbesondere Suchverfahren und Sortierverfahren. • Fragestellungen des Abschnitts: – Welche Hilfsmittel aus der Mathematik finden in der Informatik besonders Verwendung? – Was ist eine Wortmenge? – Was ist ein Byte? – Wie stellt ein Computer ganze Zahlen dar? – Wie stellt ein Computer Bilder dar? – Welche Möglichkeiten gibt es, Datenmengen im System darzustellen? – Welche Möglichkeiten gibt es, in Datenmengen zu suchen? – Welche Möglichkeiten gibt es, Datenmengen zu sortieren? – Was versteht man unter der Komplexität eines Algorithmus? 3.1 Mathematische Hilfsmittel Informatik hat viele Charakteristiken einer Ingenieurwissenschaft. Wie diese verwendet sie in hohem Maße mathematische Hilfsmittel. Die Art der Hilfsmittel unterscheidet sich jedoch von vielen Ingenieurwissenschaften: Der Schwerpunkt liegt nicht auf dem „Rechnen“ oder geometrischen Verfahren, sondern auf der Organisation von Informationen. Geeignete mathematische Hilfsmittel hierfür sind Mengen und einige darauf aufbauende Konzepte. 46 Gunnar Teege, UniBW München 3.1.1 3.1. MATHEMATISCHE HILFSMITTEL Mengen Der Begriff der „Menge“ bildet heute die wesentliche Grundlage für alle Bereiche der Mathematik. Er wurde von Georg Cantor im 19. Jahrhundert eingeführt und folgendermaßen beschrieben: „Zusammenfassung von bestimmten wohlunterschiedenen Objekten unserer Anschauung oder unseres Denkens zu einem Ganzen.“ Charakterisierung von Mengen Um eine konkrete Menge zu charakterisieren, muss man in irgendeiner Weise angeben, welche Objekte („Elemente“) in ihr enthalten sind. Dies kann in unterschiedlicher Weise geschehen. • Umgangssprachliche Beschreibung Eine Menge kann umgangssprachlich charakterisiert werden, indem man Eigenschaften der Elemente beschreibt. Beispiele „Die Menge aller Personen in diesem Raum“ oder „Die Menge der Zahlen, die kleiner sind als 6“. • Formale Beschreibung Umgangssprachliche Charakterisierungen sind meist auf mehrere Arten zu interpretieren, es ist unsicher, welche Menge genau gemeint ist. Daher werden normalerweise formale Beschreibungen verwendet, für die die Bedeutung genau festgelegt ist. Beispiel {x ∈ Nat | x < 6} • Aufzählung Falls die Menge nur wenige Elemente enthält, kann sie auch charakterisiert werden, indem alle Elemente einzeln angegeben werden. Beispiele „Guido, Andrea, Gunnar und Frank“, {1, 2, 3, 4, 5} 47 Gunnar Teege, UniBW München 3.1. MATHEMATISCHE HILFSMITTEL • Konstruktion aus anderen Mengen Schließlich kann man Mengen auf der Basis anderer Mengen charakterisieren. Dazu verwendet man Operationen, die auf definierte Weise aus einer oder mehreren Mengen eine neue Menge konstruieren. Beispiele Vereinigung: A ∪ B, Durchschnitt: A ∩ B. – Das cartesische Produkt Eine relativ große Bedeutung spielt in der Informatik die Operation des „(cartesischen) Produkts“, auch als „Paarbildung“ oder „Tupelbildung“ bezeichnet. Das Produkt zweier Mengen A und B ist die Menge aller Paare, bei denen das erste Objekt ein Element aus A und das zweite Objekt ein Element aus B ist. Formal: A × B = {(a,b) | a ∈ A ∧ b ∈ B} Im Fall von mehr als zwei Mengen spricht man (als Verallgemeinerung von „Tripel“, „Quadrupel“ etc.) von „Tupeln“. Beispiel {1,2} × {x,y,z} = { (1,x), (1,y), (1,z), (2,x), (2,y), (2,z) } • Mengen von Mengen Auch Mengen sind „Objekte unseres Denkens“ und können als Elemente von Mengen auftreten. In gewissen Fällen (z.B. bei Mengen die sich selbst enthalten) können hier Paradoxa auftreten, die aber für die normale Anwendung von Mengen keine Rolle spielen. – Potenzmenge Eine häufig verwendete Konstruktion ist die Menge aller Teilmengen einer vorgegebenen Menge M, die „Potenzmenge von M“, geschrieben als ℘(M). Beispiel ℘({1,2,3}) = { {}, {1}, {2}, {3}, {1,2}, {1,3}, {2,3}, {1,2,3}}. Mächtigkeit von Mengen Ein wichtiger Begriff bei Mengen ist ihre Mächtigkeit. Dabei handelt es sich um eine Verallgemeinerung des Konzepts „Zahl der Elemente“. Bei unendlichen Mengen läßt sich die Anzahl der Elemente nicht mehr als Zahl angeben, trotzdem unterscheiden sich auch unendliche Mengen aufgrund der Anzahl ihrer Elemente („Mächtigkeit“). 48 Gunnar Teege, UniBW München 3.1. MATHEMATISCHE HILFSMITTEL • Endliche Mengen Bei endlichen Mengen kann die Anzahl der Elemente immer als (natürliche) Zahl angegeben werden. – Endliche Mengen spielen in der Informatik eine wichtige Rolle, da jede endliche Menge bei hinreichend großem Aufwand komplett erfasst und bearbeitet werden kann. Beispiel Ein Beispiel für eine endliche Menge ist die Menge aller Einwohner Deutschlands. • Abzählbar unendliche Mengen Abzählbar unendliche Mengen sind alle Mengen, die „gleich viele“ Elemente haben wie die Menge der natürlichen Zahlen. Abzählbar unendliche Mengen haben zwar unendlich viele Elemente, diese lassen sich aber im Prinzip „durchnumerieren“. – Abzählbar unendliche Mengen spielen in der Informatik eine wichtige Rolle als Grenzfall der endlichen Mengen. Eine abzählbar unendliche Menge kann zwar nie komplett, aber bei beliebig großem Aufwand zu einem beliebig großen Teil repräsentiert und verarbeitet werden. Jedes einzelne Element kann komplett erfasst werden und kommt irgendwann an die Reihe. Beispiel Die Menge aller möglichen deutschen Texte ist abzählbar unendlich. • Überabzählbare Mengen Überabzählbare Mengen haben „mehr“ Elemente als die natürlichen Zahlen. Das bekannteste Beispiel für eine überabzählbare Menge ist die Menge der reellen Zahlen. – Überabzählbare Mengen spielen für die Informatik nur eine geringe Rolle, da sie auch mit unendlichem Aufwand nie komplett bearbeitet werden können und typischerweise auch bereits einzelne Elemente nicht mehr komplett erfasst und bearbeitet werden können. Überabzählbare Mengen werden daher in der Informatik meist durch abzählbare Mengen „angenähert“. Beispiel Um die reellen Zahlen in der Informatik zugänglich zu machen, werden sie durch die sogenannten numerisch reellen Zahlen angenähert, die nur eine gewisse Zahl von Nachkommastellen zulassen. Das Vorgehen bei dieser Annäherung und die Konsequenzen daraus behandelt ein eigenes Teilgebiet der Mathematik, die sogenannte „Numerik“. 49 Gunnar Teege, UniBW München 3.1.2 3.1. MATHEMATISCHE HILFSMITTEL Relationen und Abbildungen Relationen sind formale Modelle für Beziehungen zwischen Objekten, Abbildungen sind formale Modelle für Zuordnungen von Objekten untereinander. Beide Konzepte lassen sich sehr leicht auf der Basis von Mengen darstellen. Relationen Eine n-stellige Relation beschreibt eine bestimmte Beziehung zwischen jeweils n Objekten. Werden n Objekte beliebig herausgegriffen (sie können dann zu einem n-Tupel zusammengefasst werden), so gilt die Relation für diese n Objekte entweder oder sie gilt nicht. Beispiel für eine Relation Die Beziehung zwischen Personen und Wohnsitzen kann als (zweistellige) Relation modelliert werden. Für jedes beliebige Paar aus einer Person und einem Wohnsitz gilt entweder, dass der Wohnsitz zur Person gehört, oder nicht. • Relationen als Mengen Jeder Relation enspricht direkt eine Menge, nämlich die Menge aller n-Tupel, für die die Relation gilt. Umgekehrt bezeichnet man jede beliebige Teilmenge des cartesischen Produkts von n Mengen als n-stellige Relation. Beispiel Die Wohnsitz-Relation ist eine Teilmenge des cartesischen Produkts aus der Menge aller Personen und der Menge aller Wohnsitze. • Darstellung von Relationen Es gibt unterschiedliche Mittel, eine Relation anschaulich darzustellen. Diese sind i.a. aber nur anwendbar auf endliche Relationen. – Grafisch Eine übliche grafische Darstellung basiert auf der Darstellung der Objekte als „Knoten“ in einer Ebene. Jede Beziehung wird dadurch dargestellt, dass die beteiligten Objekte durch Linien verbunden werden. Wohnsitzrelation grafisch 50 Gunnar Teege, UniBW München 3.1. MATHEMATISCHE HILFSMITTEL – Tabelle Eine Relation kann auch als Tabelle dargestellt werden. Die Anzahl der Spalten entspricht der Stelligkeit der Relation. In jeder Zeile ist eine Gruppe von Objekten eingetragen, für die die Beziehung gilt. Die Tabelle ist also nichts anderes als eine zeilenweise Aufzählung der Tupel aus der Mengendarstellung der Relation. Wohnsitzrelation als Tabelle – Matrix Eine weitere Darstellung für zweistellige Relationen ist die Matrix-Form. Jede Zeile entspricht einem Objekt aus der ersten Menge, jede Spalte einem Objekt aus der zweiten Menge. An jedem Kreuzungspunkt steht eine 1, falls für die beiden Objekte die Beziehung gilt, ansonsten eine 0. Wohnsitzrelation als Matrix 51 Gunnar Teege, UniBW München 3.1. MATHEMATISCHE HILFSMITTEL • Relationen in der Informatik Relationen spielen in der Informatik eine wichtige Rolle. – Modellierung von Zusammenhängen Relationen dienen zur Modellierung von Zusammenhängen. Das Erfassen von Zusammenhängen und Strukturen ist eine wichtige Voraussetzung für den Entwurf von informationsverarbeitenden Systemen. Beispiel Für eine Kundenverwaltung einer Firma spielen Beziehungen zwischen Personen, Namen, Städten, Postleitzahlen, Telefonnummern, Produkten, Kontonummern, etc. eine Rolle. Diese können als Relationen modelliert werden. – Datenbanken Speziell im Bereich der Datenbanken ist diese Art der Modellierung zu einem sehr erfolgreichen Standard geworden. Bei diesen „relationalen“ Datenbanken wird der gesamte Datenbank-Inhalt als Menge von Relationen modelliert und ist auch in dieser Form für den Anwender zugänglich. Die Zugriffsschnittstelle basiert auf mathematischen Operationen für Relationen. Abbildungen Eine Abbildung beschreibt die systematische Zuordnung von Objekten zu Objekten. Zu jedem Objekt gibt es ein zugeordnetes „Bildobjekt“. Abbildungen werden auch als „Funktionen“ bezeichnet. • Abbildungen als Relationen Abbildungen können als spezielle zweistellige Relationen angesehen werden. Die Einschränkung dabei ist, dass die Relation „eindeutig“ sein muss, es also zu jedem Element der ersten Menge höchstens ein Element der zweiten Menge 52 Gunnar Teege, UniBW München 3.1. MATHEMATISCHE HILFSMITTEL gibt, das mit ihm in Beziehung steht. Anders ausgedrückt, kommt jedes Element der ersten Menge in höchstens einem Paar in der Relation vor. Beispiel Die Beziehung zwischen Personen und ihren Haupt-Wohnsitzen ist eine Abbildung, da jede Person (per Gesetz) höchstens einen Hauptwohnsitz haben kann. • Darstellung von Abbildungen Abbildungen können wie Relationen dargestellt werden. In der grafischen Darstellung werden anstelle von Linien meist Pfeile verwendet, um den Zuordnungscharakter zu verdeutlichen. Haupt-Wohnsitz-Abbildung grafisch – Formel Falls das Bildobjekt auf systematische Weise aus dem Objekt konstruierbar ist, kann eine Abbildung auch als Operation aufgefasst werden und durch eine Formel mit einem Parameter beschrieben werden, die die Art der Konstruktion angibt. Der Parameter ist ein Stellvertreter für das jeweilige Objekt. Beispiele Die Quadrierungs-Operation x2 ist eine Abbildung, die jeder natürlichen Zahl eine natürliche Zahl zuordnet. Die Additions-Operation ist eine Abbildung, die jedem Paar von natürlichen Zahlen eine natürliche Zahl (die Summe) zuordnet. – Funktionsgraph Die bekannteste Darstellung einer Abbildung reeller Zahlen auf reelle Zahlen ist der Funktionsgraph, eine in ein Koordinatensystem eingetragene Linie. Diese Darstellungsform spielt in der Informatik praktisch keine Rolle. • Abbildungen in der Informatik Abbildungen spielen ebenfalls eine zentrale Rolle in der Informatik. 53 Gunnar Teege, UniBW München 3.1. MATHEMATISCHE HILFSMITTEL – Modellierung von Informationsverarbeitung Jede Art der Informationsverarbeitung, die bei konkreter Eingabe ein eindeutiges Ergebnis liefert, kann als Abbildung der Eingabe auf das Ergebnis modelliert werden. Bei dieser Modellierung wird meist nur beschrieben, was das Ergebnis sein soll, ohne genau angeben zu müssen, wie es konstruiert wird. Ein solches abstraktes Modell ist eine wichtige Vorstufe für die eigentliche Programmierung. Ordnungen Eine weitere wichtige Spezialform von zweistelligen Relationen einer Menge mit sich selbst sind Ordnungsrelationen. Eine Ordnungsrelation hat zwei Eigenschaften: sie ist unsymmetrisch, gilt also höchstens in einer Richtung, und sie ist transitiv. In formaler Schreibweise ist eine Relation R eine Ordnungsrelation, wenn für jedes Paar (a,b) ∈ R gilt: (b,a) 6∈ R und für alle Paare (a,b) ∈ R, (b,c) ∈ R gilt: (a,c) ∈ R • Darstellung von Ordnungen Die Existenz einer Ordnungsrelation auf einer Menge bewirkt, dass die Elemente in gewisser Weise eine „Position“ zueinander erhalten. Im Spezialfall einer „linearen“ Ordnung lassen sich die Elemente in einer Linie anordnen. Im allgemeineren Fall ergeben sich komplexere Diagramme, die die Anordnung der Elemente zueinander darstellen. Beispiel Die übliche „kleiner als“ Relation der natürlichen Zahlen ist eine lineare Ordnung. Ihr entspricht die Anordnung der Zahlen auf dem „Zahlenstrahl“. Beispiel Die Relation „ist Teilmenge von“ ist eine Ordnung auf der Potenzmenge jeder Menge, aber keine lineare Ordnung. • Ordnungen in der Informatik Ordnungen spielen in der Informatik eine wichtige Rolle im Zusammenhang mit der Strukturierung von Mengen. Ordnungen sind wichtige Voraussetzungen für die Anwendung von Suchverfahren und Sortierverfahren. 54 Gunnar Teege, UniBW München 3.1.3 3.1. MATHEMATISCHE HILFSMITTEL Alphabete und Sprachen Die wichtigste Art von Mengen in der Informatik sind die sogenannten „Wortmengen“. Sie spielen in der Informatik eine ähnlich zentrale Rolle wie die reellen Zahlen in anderen Wissenschaften. Alphabete Ausgangspunkt für eine Wortmenge ist eine beliebige endliche oder abzählbare Menge, zu der eine lineare Ordnung existiert. Diese Menge wird in diesem Zusammenhang als „Alphabet“ bezeichnet, ihre Elemente als „Zeichen“. Beispiel Das lateinische Alphabet ist ein Alphabet in diesem Sinne, wenn man es als Menge von 26 Zeichen auffasst. Entsprechendes gilt für die anderen auf der Welt benutzten Alphabete. Wortmengen Die Bildung einer Wortmenge über einem Alphabet ist verwandt mit dem cartesischen Produkt. Es werden alle cartesischen Produkte beliebiger Stelligkeit des Alphabets mit sich selbst vereinigt. Anders ausgedrückt, sind die Elemente der Wortmenge alle n-Tupel aus Zeichen des Alphabets, wobei n alle natürlichen Zahlen durchläuft. Formal ist die Wortmenge A* zu einem Alphabet A charakterisiert durch A* = { a1 ... an | n ≥ 0 ∧ a1 ∈ A ∧ ... ∧ an ∈ A} Die Elemente der Wortmenge werden auch als „Zeichenreihen“ oder „Worte“ bezeichnet. • Beispiel Die Wortmenge über dem lateinischen Alphabet ist die Menge aller Buchstabenreihen beliebiger Länge, also aller möglichen „Wörter“ (egal, ob sie in einer natürlichen Sprache verwendet werden oder nicht). Eingeschlossen sind das „leere Wort“, das keinen Buchstaben enthält und alle Worte aus nur einem Buchstaben. Sprachen Eine „Sprache“ im Sinne der Informatik ist jede Teilmenge einer Wortmenge. Es handelt sich also nicht mehr um alle beliebigen Zeichenreihen, sondern um eine Auswahl. 55 Gunnar Teege, UniBW München 3.1. MATHEMATISCHE HILFSMITTEL Beispiel Die Menge aller im Deutschen vorkommenden Wörter ist eine Teilmenge der Wortmenge über dem lateinischen Alphabet. Damit ist sie eine Sprache im Sinne der Informatik. Wortmengen und Sprachen in der Informatik Wortmengen und Sprachen sind in der Informatik die Grundlage für die Darstellung von Daten und Informationen. • Binärzeichen Ein wichtiges in der Informatik vorkommendes Alphabet ist die zweielementige Menge {0,1}. Die Elemente werden auch als „Binärzeichen“ oder „Binärziffern“ bezeichnet. Die Wortmenge dazu ist die Menge aller Folgen aus Binärziffern. Diese Menge bildet die technische Basis für die Darstellung aller Daten in der Informatik. • Texte Aber auch andere Alphabete spielen eine wichtige Rolle. Wird das lateinische Alphabet um Zahlen, Satzzeichen und ein „Zwischenraum“-Zeichen erweitert, entspricht die zugehörige Wortmenge allen möglichen Texten in lateinischer Schrift. Auf dieser Grundlage lassen sich beispielsweise Methoden der Textverarbeitung mathematisch modellieren. Zugehörige Sprachen im Sinne der Informatik sind beispielsweise die Menge aller grammatikalisch korrekten deutschen Texte, die Menge aller korrekten Java-Programme oder die Menge aller Kochrezepte. Wortmengen und Ordnungen Die lineare Ordnung auf dem Alphabet läßt sich zu einer linearen Ordnung auf der Wortmenge (und damit auch auf jeder Sprache) erweitern. Aus dem täglichen Leben ist diese Konstruktion als „lexikographische“ Ordnung bekannt. Ausgehend von der linearen Anordnung der Buchstaben im Alphabet lassen sich beliebige Worte linear ordnen, beispielsweise im Telefonbuch. • Mächtigkeit von Wortmengen Auch für ein endliches (nichtleeres) Alphabet ist die Wortmenge immer bereits unendlich, da die Länge der Worte nicht beschränkt ist. Mit Hilfe einer geeigneten Ordnung läßt sich jede Wortmenge aber durchnumerieren. Daraus folgt, dass jede Wortmenge abzählbar unendlich ist. 56 Gunnar Teege, UniBW München 3.1.4 3.1. MATHEMATISCHE HILFSMITTEL Aussagen Aussagen sind ebenfalls eine wesentliche mathematische Grundlage, die in der Informatik intensiv verwendet wird. Umgangssprachlich ist eine Aussage die Formulierung einer Behauptung, die zutreffen kann oder nicht. Aussagen werden beispielsweise bei der Charakterisierung von Mengen verwendet. Aussagen als Worte einer Sprache Sobald Aussagen in irgendeiner Form (umgangssprachlich oder formal) als Text formuliert sind, handelt es sich um Zeichenreihen in einer Wortmenge. Der „Wahrheitsgehalt“ einer Aussage kann modelliert werden durch eine Abbildung in die Menge der „Wahrheitswerte“ {„wahr“, „falsch“ } oder durch Bildung der Teilmenge (Sprache) der wahren Aussagen. Damit sind Aussagen nicht nur Hilfsmittel der Informatik, sondern sie können selbst mit informationstechnischen Methoden verarbeitet werden. Formale Schreibweise für Aussagen Ähnlich wie im Fall der Charakterisierung von Mengen verwendet man auch für Aussagen bevorzugt eine formale Notation („aussagenlogische Formeln“), um Unklarheiten zu vermeiden. Typische Bestandteile der formalen Notation für Aussagen sind die Operationssymbole ∧, ∨, ¬, → für „und“, „oder“, „nicht“, „impliziert“. Aussagen als Hilfsmittel Formale Aussagen werden in allen Bereichen der Informatik als Hilfsmittel zur Beschreibung und Modellierung eingesetzt. Beispielsweise lassen sich Anforderungen an ein Software-System als formale Aussagen schreiben und damit eindeutig festlegen. Beispiel Primitive Aussagen: prozessor_frei, leitung_frei, wartend, sendend. Aussagenlogische Formeln: ¬ sendend ∨ ¬ (prozessor_frei ∨ leitung_frei) sendend → ( ¬ prozessor_frei ∧ ¬ leitung_frei) ¬(prozessor_frei ∧ leitung_frei ∧ wartend) (prozessor_frei ∧ leitung_frei) → ¬ wartend 57 Gunnar Teege, UniBW München 3.2. DATEN UND CODIERUNG Gesetze für Aussagen Es gibt eine Reihe allgemein geltender formaler Gesetze, mit denen man aussogenlogische Formeln ineinander umformen kann, ohne ihren Wahrheitsgehalt zu verändern. Beispiel Gesetze für beliebige aussagenlogische Formeln a und b: ¬ (a ∨ b) = (¬ a) ∧ (¬ b) ¬ (a ∧ b) = (¬ a) ∨ (¬ b) a → b = ( ¬ a) ∨ b Bearbeitung von Aussagen In vielen Gebieten der Informatik spielt auch die Verarbeitung von Aussagen eine Rolle. Dies gilt insbesondere für das Gebiet der sogenannten künstlichen Intelligenz. Beispiel Schlussregeln erzeugen aus vorgegebenen wahren Aussagen neue wahre Aussagen („Inferenz“). • Modus Ponens Für beliebige aussagenlogische Formeln p,q gilt: wenn p → q wahr und p wahr sind, dann ist auch q wahr. • Modus Tollens Für beliebige aussagenlogische Formeln p,q gilt: wenn p → q wahr und ¬ q wahr sind, dann ist auch ¬ p wahr („Umkehrschluss“). 3.2 Daten und Codierung Dieser Abschnitt beschäftigt sich mit Information und ihrer Darstellung im Computer 3.2.1 Information und Nachrichten Information tritt in vielen Formen auf. Sie ist immer an eine Repräsentation (Darstellung) gebunden, entweder im Gehirn oder z.B. an Schallwellen oder die 58 Gunnar Teege, UniBW München 3.2. DATEN UND CODIERUNG Zeichen eines geschriebenen Textes. Die Übertragung zwischen verschiedenen Repräsentationen nennt man auch Codierung. Information-/Datenverarbeitung Um Information in einem Rechner speichern und verarbeiten zu können, muss eine geeignete Darstellung verwendet werden. Eine Codierung ist notwendig, da die für den Menschen verständliche Information auf eine für den Rechner verständliche Darstellung abgebildet werden muss. Bei der Interpretation durch einen Automaten ist ein semantischen Modell (Beschreibung der Bedeutung) notwendig. • Für den menschlichen Anwender bedeutsame Informationen werden im Rechner als (binäre) Daten repräsentiert. Man spricht deshalb auf der Ebene des Benutzers von Informationsverarbeitung, während auf der Rechnerebene von Datenverarbeitung gesprochen wird. • Daten werden im Rechner als eine Folge von Bits dargestellt. Darstellung von Information Für dieselbe Information kann es verschiedene Interpretationen geben (je nach Modell) und für dieselbe Information viele verschiedene Repräsentationen. Dieselbe Information lässt sich auf verschiedene Arten darstellen, z.B. Sitzverteilung 59 Gunnar Teege, UniBW München 3.2. DATEN UND CODIERUNG im Bundestag. Die Daten werden im Rechner trotz unterschiedlicher Darstellungen auf identische Weise gespeichert. Die Daten werden zwar auf 3 verschiedene Arten dargestellt, jedoch im Rechner existieren sie nur einmal. Nachrichten Im Kontext der Übertragung spricht man oft von Nachrichten anstelle von Daten. • Eine Nachricht ist eine Folge von Zeichen, oft aus sinnesphysiologischen oder technischen Gründen in Worte unterteilt. • Soll eine Nachricht von einem Sender zu einem Empfänger gelangen, muss 60 Gunnar Teege, UniBW München 3.2. DATEN UND CODIERUNG zwischen beiden ein Übertragungskanal bestehen, z.B. eine Verbindung über ein Rechnernetz. • Um übertragbar oder speicherbar zu sein, muss eine Nachricht eine Repräsentation haben, i.a. als Bitfolge. 3.2.2 Bits und Bytes Bits (und Bytes) bilden die Grundlage der Darstellung, die für Information in Rechnern verwendet wird. Damit setzen sich alle Daten aus Bits zusammen. Bits Abkürzung für „Binary digits“. • Ein Bit ist die kleinstmögliche Informationsheit. Ein Bit lässt zwei mögliche Werte auf eine Frage zu, z.B. Ja oder Nein, Wahr oder Falsch, Links oder Rechts. • Oft werden in diesem Zusammenhang die beiden Werte 0 und 1 benutzt. Technisch werden die beiden Werte durch elektrische Ladungen (0 = ungeladen, 1 = geladen), elektrische Spannungen (0 = 0 Volt, 1 = 5 Volt) oder Magnetisierungen dargestellt. • Bitfolgen werden benötigt, falls zur Darstellung mehr als zwei Werte notwendig sind (z.B. die Beantwortung einer Frage enthält mehr als zwei mögliche Antworten, wie "Woher kommt der Wind?" - Süd, West, Ost oder Nord). Mit 3 Bit können insgesamt 8 verschiedene Werte repräsentiert werden. Man erhält auf diese Weise eine ein-eindeutige Zuordnung von Bitkombinationen zu acht verschiedenen Himmelsrichtungen. Bitfolge 000 001 010 011 100 101 110 111 Himmelsrichtung Süd West Nord Ost Südost Nordwest Nordost Südwest 61 Gunnar Teege, UniBW München 3.2. DATEN UND CODIERUNG • Jedes zusätzliche Bit in einer Folge verdoppelt die Anzahl der möglichen, unterschiedlichen Bitfolgen, d.h. es gibt genau 2N mögliche Bitfolgen der Länge N. Byte Ein Byte umfasst acht Bit, ist also eine Bitfolge der Länge 8. Diese Größe hat sich im Computerbereich als wichtigste Grundeinheit eingebürgert. • Häufige Abkürzungen für größere Einheiten: – 1 KB = 1024 Bytes = 210 Bytes (Kilo) – 1 MB = 1024 * 1024 Bytes = 220 Bytes (Mega) – 1 GB = 1024 * 1024 * 1024 Bytes = 230 Bytes (Giga) – 1 TB = 1024 * 1024 * 1024 * 1024 Bytes = 240 Bytes (Tera) – 1 PB = 1024 * 1024 * 1024 * 1024 * 1024 Bytes = 250 Bytes (Peta) – 1 EB = 1024 * 1024 * 1024 * 1024 * 1024 * 1024 Bytes = 260 Bytes (Exa) – Als nächste zwei Stufen sind „Zetta“ und „Yotta“ gebräuchlich, allerdings nicht offiziell standardisiert. – Hinweis Die Definition über Zweierpotenzen ist eine spezielle im Bereich der Informationstechnik übliche Variante. In anderen Gebieten bezeichnen die Kürzel Zehnerpotenzen in Dreierschritten (103 = 1000 ist ungefähr 1024 = 210) 3.2.3 Codierung Codierung ist allgemein die Zuordnung (oder Abbildung) der Werte eines Zeichenvorrats auf Werte eines anderen Zeichenvorrats. Eine Codierung ist die Abbildung der für den Menschen verständliche Darstellung der Information auf eine für den Rechner verständliche Darstellung. • Zeichen: Ausprägung (Form, Wert) eines Signals; häufig spricht man auch von Symbolen, z.B. Buchstaben. • Zeichenvorrat: Menge der Zeichen (d.h. Formen, Werte), die ein bestimmtes Signal annehmen kann. Ein Alphabet ist ein Zeichenvorrat mit linearer Ordnung der Zeichen, z.B. das deutsche Alphabet A - z; das kleinste Alphabet besteht aus 2 Zeichen (binäre Daten). 62 Gunnar Teege, UniBW München 3.2. DATEN UND CODIERUNG • Codierung erfolgt für bestimmten Zweck: – Speicherung – Übertragung – Komprimierung, z.B. von Bildern oder Video – Verschlüsselung – Veranschaulichung • Eine Codierung ist z.B. notwendig, da die für den Menschen verständliche Information auf eine für den Rechner verständliche oder speicherbare Darstellung abgebildet werden muss. Hier Zuordnung von Symbolen, die für den Menschen Sinn machen, zu Bitfolgen. Das Binärsystem ist ein 2-wertiges Alphabet, dessen Zeichen als Bits (Binary digits) bezeichnet und als {0, 1} dargestellt werden. Bitfolgen sind höher-wertige Alphabete. Bei Codierung mittels des Binärsystems werden Informationseinheiten jeweils im Rechner als Bitfolgen dargestellt. • Die einer Codierung zugrundeliegende Abbildung muss berechenbar, eindeutig und (in der Regel) umkehrbar sein. • Ganze Zahlen Ganze Zahlen werden auf Basis des Binärsystems codiert. So wie im Dezimalsystem jede Ziffer die Anzahl einer Zehnerpotenz (1, 10, 100, 1000, ...) angibt, gibt im Binärsystem jede Ziffer die Anzahl einer Zweierpotenz (1, 2, 4, 8, 16, 32, ...) an. Während im Zehnersystem zehn Ziffern erforderlich sind, reichen im Binärsystem zwei Ziffern (0, 1) aus (genannt „Bit“, von „binary digit“). Beispiel Dezimalsystem: 148 = 8 * 100 + 4 * 101 + 1 * 102 Binärsystem: 1010 = 0 * 20 + 1 * 21 + 0 * 22 + 1 * 23 (= 10 im Dezimalsystem) – Formel für Wert einer Binärsystem-Zahl W = n−1 X bi × 2n−1−i i=0 mit den Binärziffern bi ∈ {0, 1} und n ist die Anzahl der verwendeten Bits. Beachte, es wird die Folge b0 b1 ... bn-1 betrachtet. Beispiel eine ganze Zahl sei als 8 bit lange Zahl zur Basis 2 dargestellt 63 Gunnar Teege, UniBW München 3.2. DATEN UND CODIERUNG ∗ W (000011012 ) = 0×27 +...+0×24 +1×23 +1×22 +0×21 +1×20 = 8+4+1 = 1310 Dabei stellt 00001101 einen Wert zur Basis 2 da. Zur Basis 10 ist der Wert 13. – Verfahren zur Umwandlung Umwandlung einer Dezimalzahl w in eine Dualzahl z dividiere w durch 2: Ergebnis w1 und Rest r0 dividiere w1 durch 2: Ergebnis w2 und Rest r1 fahre fort, bis das Ergebnis der Division 0 und Rest rk ist. Die Dualzahl ist z = rk rk−1 ...r1 r0 ∗ Beispiel Dezimalzahl w = 23 23 : 2 = 11 mit Rest 1 11 : 2 = 5 mit Rest 1 5 : 2 = 2 mit Rest 1 2 : 2 = 1 mit Rest 0 1 : 2 = 0 mit Rest 1 Die Dualzahl lautet: z = 10111 – Feste Ziffernanzahl Typischerweise werden Zahlen durch eine Bitfolge fester Länge codiert (ggf. mit führenden Nullen auffüllen). Die Anzahl der Bits ist meist ebenfalls eine Zweierpotenz, z.B. 4 Bit, 16 Bit, 32 Bit oder 64 Bit. In aktuellen Rechnerarchitekturen werden für die Darstellung einer ganzen Zahl entweder 32 oder 64 Bit verwendet. Bei Verwendung von n Bit sind die Zahlenwerte 0 bis 2n-1 codierbar. – Negative Zahlen Positive ganze Zahlen werden immer durch ihre Darstellung im Binärsystem codiert. Für die Codierung negativer ganzer Zahlen gibt es mehrere Möglichkeiten. ∗ Vorzeichen-Darstellung Das erste Bit der Zahlencodierung wird als Vorzeichenbit interpretiert (0 entspricht +, 1 entspricht -) die restlichen Bits codieren den Absolutwert der Zahl im Binärsystem. Damit sind Zahlen von -(2n-1-1) bis 2n-1-1 möglich. Es gibt jedoch zwei Nullen, d.h. eine positive (000...00) und eine negative Null (100...00). Beispiel Für n=4 sind die Zahlen von -7 bis +7 codierbar: 64 Gunnar Teege, UniBW München 3.2. DATEN UND CODIERUNG 0 = 0000 -0 = 1000 1 = 0001 -1 = 1001 2 = 0010 -2 = 1010 3 = 0011 -3 = 1011 4 = 0100 -4 = 1100 5 = 0101 -5 = 1101 6 = 0110 -6 = 1110 7 = 0111 -7 = 1111 ∗ Einerkomplement-Darstellung Das erste Bit der Zahlencodierung wird als Vorzeichenbit interpretiert. Die restlichen n-1 Bits enthalten für positive Zahlenwerte die Binärzahl, für negative Zahlenwerte den um 2n-1-1 erhöhten Zahlenwert (immer positiv) als Binärzahl. Damit sind bei n Bits ebenfalls Zahlen von -2n-1-1 bis 2n-11 möglich. Es gibt ebenfalls zwei Nullen, die positive (000...00) und eine negative Null (111...11). Vorteil: das Hochzählen funktioniert für negative und positive Zahlen gleich. Beispiel Für n=4 sind die Zahlen von -7 bis +7 codierbar: 0 = 0000 -0 = 1111 1 = 0001 -1 = 1110 2 = 0010 -2 = 1101 3 = 0011 -3 = 1100 4 = 0100 -4 = 1011 5 = 0101 -5 = 1010 6 = 0110 -6 = 1001 7 = 0111 -7 = 1000 ∗ Zweierkomplement-Darstellung Beim Zweierkomplement werden Zahlen wie beim Einerkomplement codiert, aber bei negativen Zahlenwerten wird der Wert um 2n-1 erhöht. Die negative Null entfällt und es ist eine negative Zahl mehr darstellbar als positiven Zahlen. Das Zweierkomplement hat den Vorteil der einfachen Umsetzung der Grundrechenarten Addition und Subtraktion. Beispiel für 4 bit Darstellung Zweierkomplement-Darstellung mit 4 bit für eine ganze Zahl 65 Gunnar Teege, UniBW München 3.2. DATEN UND CODIERUNG 3 X W = bi × 23−i i=0 mit bi ∈ {0, 1} Formel für Wert einer Zweierkomplement-Zahl n−1 W = −b0 × 2 + n−1 X bi × 2n−1−i i=1 Rechnen mit Zweierkomplement-Zahlen Negativbildung und Grundrechenarten sind einfach durchführbar. Negativbildung einer Zahl Die Berechnung der negativen Zahldarstellung aus der entsprechenden positiven Zahldarstellung erfolgt durch die Komplementbildung (Bits werden invertiert), anschließend wird 1 addiert. Dies ergibt die Zweierkomplement Darstellung der zur positiven Zahl zugehörigen negativen Zahl. Beispiel Zweierkomplement-Codierung mit 8 Bit für -14: 14 = Komplement: 1 addiert: Addition von zwei Zahlen 00001110 11110001 11110010 66 Gunnar Teege, UniBW München 3.2. DATEN UND CODIERUNG Stellenweise mit Übertrag, analog zum Dezimalsystem. Differenzbildung von zwei Zahlen Realisierbar durch Addition mit negativer Zahl. Beispiel Berechnung 17 - 14: dezimal dual 17 00010001 +(-14) 11110010 =3 00000011 • Alphanumerische Daten - ISO-ASCII 8-bit-Code Darstellung von alphanumerischen Zeichen in einer 8-Bit Folge, d.h. Codierung eines Zeichens durch eine (Binär-)zahl zwischen 0 und 255. – ISO = International Standards Organisation – ASCII = American Standard Code for Information Interchange – Kleinbuchstaben sind in alphabetischer Reihenfolge durchnummeriert (97 124) – Großbuchstaben sind in alphabetischer Reihenfolge durchnummeriert (65 92) – Ziffern 0 bis 9 sind in aufsteigender Reihenfolge dargestellt (48 - 58) – Darstellung von Sonderzeichen, z.B. CR (Carriage Return = Absatzende), LF (Linefeed = Neuzeile) – Zu den entsprechenden Zeichen des ASCII Codes wird der jeweilige Zahlenwert zur Basis 10 angegeben. Zeichen Dezimal Binärdarstellung a 97 01100001 A 65 01000001 b 98 01100010 B 66 01000010 0 48 00110000 ? 63 00111111 CR 13 00001101 Viele Systeme bei der Netzübertragung arbeiten noch mit 7-bit ASCII Code. Dieser enthält viele spezielle, sprachspezifische Zeichen wie ü, ä oder ö nicht. Diese Zeichen müssen daher in eine 7-bit Darstellung konvertiert werden (Verwendung eines „Escape-Zeichens“ zur Einleitung von zusätzlichen Zeichen). 67 Gunnar Teege, UniBW München 3.2. DATEN UND CODIERUNG • Unicode Ein neuer Standard (Unicode) codiert jedes Zeichen mit zwei Bytes. Damit sind 65536 verschiedene Zeichen möglich. Unicode verwendet diese Menge um Zeichen aus allen vorkommenden Alphabeten gemeinsam zu codieren. 3.2.4 Codierung von Bildern und Tönen Komplexe Informationen wie Bilder und Töne erfordern geeignete Vorgehensweisen bei der Codierung. Graphiken Man unterscheidet bei Graphiken zwischen Rastergrafik (Bilder) und Vektorgrafik Eigenschaft Dokument besteht aus Rastergrafik Folge von Pixeln Eignung Platzbedarf DIN A4, 16 Mio Farben, 600dpi Formate Fotos ca 95 MB BMP, GIF, JPG, PNG Vektorgrafik Menge von geometrischen Objekten Zeichnungen je nach Umfang ca 10 KB - 1 MB WMF, VSD, CDR Rastergrafik - Bilder Problem: Information gleichmäßig über Fläche verteilt. • Auflösung des Bildes in Rasterpunkte. Bei Bildern für Bildschirmdarstellung je nach Auflösungsgrad 60 bis 360 Bildelemente (pixel) pro Zoll (1 Zoll (inch) = 2,54cm). • Darstellung der Eigenschaften eines Pixels (Grauwert, Farbe, Helligkeit) durch eine Bitfolge (normalerweise ein oder zwei Byte). • Darstellung von Farbinformation mittels RGB (rot-grün-blau) oder anderen Codierungen. • VGA: 640 * 480 * (8bit pro Pixel / 8bit pro Byte) = 307200 Byte • SVGA: 1024 * 768 * (8bit pro Pixel / 8bit pro Byte) = 786432 Byte 68 Gunnar Teege, UniBW München 3.2. DATEN UND CODIERUNG • Graphics Interchange Format (GIF): häufig vorkommende Folgen von Bytes werden in Tabelle eingetragen; im Bild Verweis auf Tabelleneintrag. • Joint Photographic Expert Group (JPG): Farben des Bildes werden analysiert; weglassen von Information, die für menschliches Auge nicht wichtig erscheint (Achtung: Verlust von Information). Töne Information gleichmäßig über Zeitdauer verteilt. • Diskretisierung und Digitalisierung, je nach erforderlicher Qualität in 100, 1000 und mehr Werte pro Sekunde. Also Unterteilung der Amplitude in Bereiche, denen jeweils eine Bitfolge zugeordnet wird. Man spricht hier von einem PCM Verfahren, d.h. Pulse Code Modulation • Darstellung der Eigenschaften des Tonelements durch ein oder zwei Byte • Sprache wird beim Telefon 8000 mal pro Sekunde (8kHz) abgetastet. Damit ergibt sich eine Übertragungsrate von 64 kbit/s, d.h. ISDN Qualität. 8000 * 8 bit = 64 kbit. 3.2.5 Komprimierung Kompression von Daten (vor allem bei Bildern und Tönen) um Speicher- und Übertragungskosten zu reduzieren. 69 Gunnar Teege, UniBW München 3.3. DATENSTRUKTUREN • Verlustfreie Kompression Ausnutzung von Mustern und Redundanzen in den Daten; Ausnutzung der Häufigkeit von Symbolen durch Änderung der Codierung • Verlustbehaftete Kompression Ausnutzung von Medien- und Wahrnehmungseigenschaften, z.B. bei MP3 die Nutzung von psychoakustischen Eigenschaften und des Hörverhaltens von Menschen. 3.3 Datenstrukturen Informationen werden im Rechner als Daten gespeichert. Eine Menge von Daten eines bestimmten Typs zusammen mit den auf der Menge ausführbaren Zugriffsoperationen nennt man eine Datenstruktur. Zum Beispiel bilden die Menge der natürlichen Zahlen zusammen mit den Grundrechenoperationen (Addition, Subtraktion, ...) eine Datenstruktur. Datenstrukturen sind bei der Programmierung ein wichtiges Hilfsmittel, die Daten für die maschinelle Verarbeitung geeignet zu organisieren. 3.3.1 Listen Eine Liste ist eine Folge von Elementen, die eine Reihenfolge haben (d.h. jedes Element hat einen Vorgänger und Nachfolger). Anker definiert Verweis auf 1. Element. Referenz definiert Verweis auf nächstes Element. Beispiele • Wort: Liste von Zeichen. • Personaldaten: Liste von Datensätzen, wobei jeder Datensatz eine Person beschreibt. 70 Gunnar Teege, UniBW München 3.3. DATENSTRUKTUREN Operationen auf Listen Erzeugen einer Liste, Einfügen eines Listenelements, Suchen eines Listenelements mit bestimmten Eigenschaften, Löschen eines Listenelements. Reihungen (Arrays) Eine Reihung ist eine Liste mit bekannter (fester) Zahl von Elementen, wobei jedes Element eine Nummer hat. Die Nummer der Elemente bestimmt die Reihenfolge. Alle Elemente sind vom gleichen Typ. Eine Reihung kann als eine 1-spaltige Tabelle aufgefasst werden. Beispiele Deklaration durch: char buffer[]; Die Deklaration spezifiziert eine Reihung mit dem Namen "buffer". • Die Anzahl der Reihungselemente kann durch eine Initialisierung der Reihung festgelegt werden: char buffer[] = new char[500]; • Allgemeine Schreibweise Es gibt eine spezielle Schreibweise für Reihungs-Datentypen: reihungstyp ist: datentyp [ ] Für den Umgang mit Reihungen wird in Java eine spezielle Form der Variablen verwendet. Sie besteht im wesentlichen aus dem Namen der gesamten Reihung und einem Ausdruck für den Indexwert eines Elements. 71 Gunnar Teege, UniBW München 3.3. DATENSTRUKTUREN speicherplatz ist: ... oder speicherplatz [ ausdruck ] oder ... Der Datentyp des Ausdrucks muss einer von int, short, byte oder char sein. – In den meisten anderen Programmiersprachen gibt es spezielle Schreibweisen für Reihungs-Datentypen und die Deklaration einer Variablen besteht systematisch aus der Datentyp-Angabe und dem Variablennamen. • Abfrage der Reihungslänge Die aktuelle Länge (Anzahl der Elemente) einer Reihung reihung kann abgefragt werden mit: reihung.length • Reihungsindexe in Java In Java hat das erste Element einer Reihung stets den Index 0. In einer Reihung mit n Elementen können also die Indexe von 0 bis n-1 verwendet werden. Beispiel Die folgende Schleife ist eine typische Anweisung zur Bearbeitung aller Elemente in der davor deklarierten Reihung. int[] r = new int[100]; for (int i=0; i < r.length; i++) r[i] = 1; • Mehrdimensionale Reihungen in Java Eine Reihung entspricht mathematisch einem Vektor. Eine zweidimensionale Reihung entspricht einer Matrix. In Java werden mehrdimensionale Reihungen als „Reihung von Reihung“ realisiert: float[][] matrix = new float[3][2]; for (int i=0; i < 3; i++) for (int j=0; j < 2; j++) matrix[i][j] = i*j; Reihung der Länge 3, als Elemente Reihungen der Länge 2. 3.3.2 Zeiger und Zeigerstrukturen Die wichtigste Datentyp-Art für die Implementierung komplexerer Datenstrukturen sind die „Zeiger“. Zusammen mit Verbund-Datentypen lassen sich mit ihnen alle Datenstrukturen realisieren. 72 Gunnar Teege, UniBW München 3.3. DATENSTRUKTUREN Was ist ein Zeiger? Programmiersprachlich ist ein Zeiger ein Wert, der ein im Rechner gespeichertes Datenobjekt referenziert. Sobald man den Zeiger kennt, kann man auf das Datenobjekt zugreifen und es i.a. auch ändern. • Zeiger als Wert Ein Zeiger kann ebenso wie z.B. ein Zahlenwert in Variablen gespeichert und an Funktionen als aktueller Parameter übergeben werden. Das referenzierte Datenobjekt bleibt davon unberührt. • Dereferenzierung Die wichtigste Operation auf einem Zeiger ist der Zugriff auf das referenzierte Datenobjekt („Zeigerverfolgung“, „Dereferenzierung“). • Zeiger-Erzeugung Es gibt keine Konstanten für Zeigerwerte. Man erhält einen Zeiger durch Angabe eines gespeicherten Datenobjekts, i.a. in Form einer Variablen. – Zeiger-Berechnung In manchen Programmiersprachen lassen sich Zeiger auch berechnen. Wenn man weiß, wie groß ein Datenobjekt im Speicher ist, kann man durch Hinzuaddieren der Größe zu einem Zeiger auf das Objekt einen Zeiger auf das nachfolgend gespeicherte Objekt erhalten. Diese Zeigerberechnung ist nicht unproblematisch, da sie fehleranfällig ist und im Prinzip beliebigen Zugriff auf alle Datenobjekte eines Prozesses ermöglicht. • Leerzeiger Normalerweise existiert ein spezieller Zeiger, der kein Datenobjekt referenziert. Er kann wie alle anderen Zeiger gespeichert werden, der Versuch einer Dereferenzierung führt aber zu einem Fehler. Dieser Zeiger kann durch eine Konstante angegeben werden. • Implementierung von Zeigern Zeiger werden implementiert durch Hauptspeicheradressen, also Zahlenwerte. Sie unterscheiden sich von normalen Zahlenwerten nur durch ihre Verwendung. Jedes im Hauptspeicherbereich eines Prozesses gespeicherte Datenobjekt kann durch seine Anfangsadresse referenziert werden. Da manche Datenobjekte mehrere Speicherzellen belegen, ist umgekehrt nicht jede Adresse als korrekter Zeiger verwendbar. 73 Gunnar Teege, UniBW München 3.3. DATENSTRUKTUREN – Zeiger und Variable Zeiger und Variable sind sehr ähnliche Konzepte, beide bezeichnen Speicherstellen für Datenobjekte. Der Unterschied liegt darin, dass Variable durch Namen bezeichnet sind, die fest in einem Programm aufgeschrieben sind. Der Variablenname kann z.B. nicht seinerseits in einer Variablen gespeichert oder an eine Funktion übergeben werden. Zeiger dagegen sind selbst Datenobjekte, die bei der Ausführung des Programms manipuliert werden können. Zeiger in Java Java erlaubt keinen expliziten Umgang mit Zeigern. Technisch bilden Zeiger aber die Grundlage für die Relaisierung der nichtprimitiven Datentypen (Klassen und Reihungen) in Java. • Zeigerwerte Die Werte von Klassen- und Reihungsdatentypen sind in Wirklichkeit immer Zeiger, die auf den Speicherplatz zeigen, in dem das Objekt oder die Reihung liegt. Bei der Verwendung werden sie automatisch dereferenziert. • Leerzeiger Der Leerzeiger wird in Java durch die Konstante null angegeben. Er kann jeder Variablen, die als Datentyp einen Klassen- oder Reihungstyp besitzt, zugewiesen werden. • Deklaration Die Deklaration einer Variablen mit Klassen- oder Reihungstyp reserviert nur den Speicherplatz für einen Zeiger. Der Speicherplatz für die eigentlichen Daten wird erst durch die Verwendung einer Initialisierung mit dem Schlüsselwort new reserviert. Beispiel (Grafische Darstellung: Rechteck für Speicherzelle, schwarzer Punkt für Leerzeiger, schwarzer Punkt mit Pfeil auf Rechteck: Zeiger auf Speicherzelle.) float[] r; ergibt: 74 Gunnar Teege, UniBW München 3.3. DATENSTRUKTUREN float[] r = new float[5]; ergibt: • Zuweisung und Zeiger Wird ein Wert von einem Klassen- oder Reihungstyp an eine Variable zugewiesen, so wird nur der Zeiger in die Variable abgelegt, die eigentlichen Daten werden nicht transportiert. Beispiel Annahme: Deklaration und Vorbesetzung sei float[] r1 = new float[1], r2 = new float[1]; r1[0] = 1.5; r2[0] = 2.7; Dann: r1 = r2; ergibt: 75 Gunnar Teege, UniBW München 3.3. DATENSTRUKTUREN r1[0] = r2[0]; ergibt: Realisierung von Listen mit Hilfe von Zeigern Mit Hilfe von Zeigern und Verbunden lassen sich Listen variabler Länge implementieren. Jedes Listenelement wird dabei durch einen Verbund repräsentiert. Zeiger verketten die Verbunde zur Liste. Jeder Verbund enthält neben dem eigentlichen Listenelement einen oder mehrere Zeiger. Man unterscheidet einfach und doppelt verkettete Listen. • Einfache Verkettung Jeder Verbund enthält einen Zeiger, der auf den nächsten Verbund in der Liste zeigt. Am Ende der Liste ist ein Leerzeiger im Verbund enthalten. – Nachteil Einfach verkettete Listen können nur in einer Richtung durchlaufen werden. Beispiel-Verbunddatentyp für Liste in Java Die entsprechende Deklaration des Verbund-Typs lautet in Java: class List1 { eltyp elem; List1 next; } 76 Gunnar Teege, UniBW München 3.3. DATENSTRUKTUREN wobei eltyp der Datentyp für jedes Listenelement ist. Beispiel zum Aufbau einer Liste class List1 { float elem; List1 next; } List1 liste = new List1(); liste.elem = 3.14; liste.next = new List1(); liste.next.elem = 2.71; liste.next.next = new List1(); liste.next.next.elem = 15.3; liste.next.next.next = null; ergibt: Beispiel für Listenbearbeitung in Java Eine typische Anweisung zur Bearbeitung aller Elemente der Liste ist die folgende Schleife: for (List1 h = liste; h != null; h = h.next) h.elem *= 2; • Doppelte Verkettung Um den Listendurchlauf in beide Richtungen zu ermöglichen, enthält jeder Verbund zusätzlich einen Zeiger auf den vorangehenden Verbund in der Liste. Beispiel-Verbunddatentyp für doppelt verkettete Liste in Java Deklaration des Verbunds: class List2 { eltyp elem; List2 next, previous; } 3.3.3 Bäume Ein Baum ist eine dynamische Datenstruktur zur Darstellung hierarchischer oder rekursiver Beziehungen. Er ist ein zyklenfreier Graph mit einem ausgezeichneten Knoten (Wurzel), von dem aus man alle anderen Knoten auf genau einem Weg erreicht. • Rekursive Definition 77 Gunnar Teege, UniBW München 3.4. SUCHVERFAHREN – ein einzelner Knoten K ist ein Baum – sind K1 ... Kn (n > 1) Bäume, dann ist die folgende Struktur ein Baum. • Die K1 ... Kn heißen Unterbäume oder Teilbäume von K. Unterbäume, die nur aus einem Knoten bestehen, heißen Blätter (des Baumes). • Ein Knoten Ki, der direkt mit anderen Knoten K verbunden ist, heißt Kind bzw. Vater von K. • Höhe eines Knotens Ki: die Anzahl der Kanten, die auf dem Weg von der Wurzel K bis zum betreffenden Knoten Ki durchschritten wird. • Geordneter Baum: Die Reihenfolge der Unterbäume ist wichtig. • Implementierung als Zeigerstruktur Jeder Baumknoten wird als Verbund repräsentiert. Die Verbunde werden durch Zeiger zum Baum zusammengefügt. Die Zeiger auf die Unterbäume eines Knotens werden in einer Reihung verwaltet. Beispiel Verbunddeklaration: class Knoten { eltyp elem; Knoten[] child; } 3.4 Suchverfahren Ausgangspunkt ist eine Menge von Datensätzen. Es wird nach einem Datensatz mit einer bestimmten Eigenschaft gesucht. 78 Gunnar Teege, UniBW München 3.4.1 3.4. SUCHVERFAHREN Mengen von Datensätzen Eine Menge von gleichartigen Datensätzen wird üblicherweise in einer Reihung oder einer Liste gespeichert. Bei den folgenden Such- und Sortierverfahren gehen wir immer davon aus, dass die Daten in einer Reihung gespeichert sind. 3.4.2 Lineare Suche Die Reihung mit den Datenelementen wird der Reihe nach durchsucht, bis das gewünschte Element gefunden ist. • Beispiel: Suche nach dem Wert 100 int[] zahlen = new int[10]; ..... for (int i=0; i<zahlen.length; i++) if (zahlen[i] == 100) break; • Im schlimmsten Fall muss die gesamte Reihung durchsucht werden. Bei großen Datenmengen ist diese Vorgehensweise ungünstig und aufwendig. Die Zeichenkombination "==" bestimmt die Gleichheit zweier Zahlen. Die Reihung zahlen umfasst die Elemente zahlen[0] bis zahlen[9]. 3.4.3 Binäre Suche Voraussetzung ist eine Ordnung auf den Datenelementen. Die Elemente werden entsprechend ihrer Ordnung (z.B. entsprechend dem Wert von Zahlen) in einer Reihung gespeichert, d.h. sie müssen aufsteigend oder absteigend geordnet sein. • Sei int A[n] eine Reihung mit n Elementen, die aufsteigend sortiert ist. • Gesucht wird ein Element mit dem Wert x; gesucht wird x im Bereich A[0] bis A[n-1]. 0 ... n-1 sind die Nummern der Reihungselemente. 1. wähle m zwischen 0 und n-1; man wird m ungefähr in der Mitte zwischen 0 und n-1 wählen. 2. wenn A[m] == x, dann sind wir fertig, gib m als Ergebnis aus. 3. wenn x < A[m], dann suche weiter im Bereich A[0] bis A[m-1]; 4. wenn x > A[m], dann suche weiter im Bereich A[m+1] bis A[n-1] 79 Gunnar Teege, UniBW München 3.5. SORTIERVERFAHREN • Eine Verdopplung der Anzahl der Listenelemente führt bei binärer Suche zu einem zusätzlichen Vergleich, während es bei linearer Suche im schlimmsten Fall zu einer Verdopplung des Aufwandes führen kann. Suchverfahren Animation siehe online Version 3.5 Sortierverfahren Ziel ist es, eine Datenmenge entsprechend einem vorgegebenen Ordnungskriterium zu sortieren. 3.5.1 Sortierverfahren - Beispiel Bubble Sort Sortieren durch Vertauschen von Elementpaaren. Jeweils benachbarte Elemente werden vertauscht, wenn sie nicht wie gewünscht geordnet sind. Dabei steigt das relativ größte Element wie eine Blase (bubble) im Wasser auf. Beispielsweise falls Namen aufsteigend sortiert werden sollen, haben Worte, die mit einem Buchstaben beginnen, der weiter vorne im Alphabet steht, einen höheren Rang, d.h. sie werden nach vorne verschoben. • Vollständiges Sortieren mittels mehrerer Durchgänge. Bei n Elementen maximal n Durchgänge bis keine Vertauschungen mehr notwendig sind. • Beispiel: alphabetisches Sortieren einer Menge von Namen 1. Sortierdurchgang mit jeweils paarweisen Vergleich 80 Gunnar Teege, UniBW München 3.5. SORTIERVERFAHREN Original nach 1 nach 2 nach 3 Jochen Karin Franz Bernd Sepp Jim Maria Jochen Franz Bernd Karin Jim Maria Sepp Franz Bernd Jochen Jim Karin Maria Sepp Bernd Franz Jim Jochen Karin Maria Sepp 3.5.2 nach 4 Schritten Bernd Franz Jim Jochen Karin Maria Sepp Rekursives Sortierverfahren - Beispiel Quicksort • Prinzip Teilen der Reihung, Sortieren der Teilreihungen (mit demselben Verfahren, also rekursiv) und Wiedervereinigen der sortierten Teilreihungen. Algorithmus 1. wähle ein Element aus der Reihung aus, das sogenannte Pivot-element 2. teile die Reihung in zwei Teilreihungen, in denen nur Elemente enthalten sind, die größer bzw. kleiner dem gewählten Element sind (d.h. kopiere die Elemente so, dass in vorderen Teil der Reihung alle Elemente kleiner dem gewählten Element, im hinteren Teil der Reihung alle Elemente größer dem gewählten Element sind) 3. sortiere die erste Teilreihung. Hier wird rekursiv derselbe Algorithmus aufgerufen, jedoch nun auf der Teilreihung. 4. sortiere die zweite Teilreihung. Hier wird rekursiv derselbe Algorithmus aufgerufen, jedoch nun auf der Teilreihung. 5. vereinige die beiden Teilreihungen • Beispiel 81 Gunnar Teege, UniBW München 3.6. KOMPLEXITÄT • Quicksort läuft schneller und effizienter ab als Bubblesort (weniger Vergleiche und Vertauschungen). Sortierverfahren Animation siehe online Version 3.6 Komplexität Nicht alle Algorithmen lassen sich mit "vertretbarem" Aufwand durchführen (Grenze der Durchführbarkeit, Praktikabilität). Bei der algorithmischen Lösung eines gegebenen Problems ist deshalb auch die Effizienz des zu entwickelnden Verfahrens von großer Wichtigkeit. 3.6.1 Komplexität von Algorithmen • Ein Algorithmus ist umso effizienter, je geringer der Aufwand zu seiner Abarbeitung ist. • Aufwand bezieht sich auf bestimmte Ressourcen, z.B. Rechenzeit, Speicherplatz, Anzahl der Geräte • Nach der Ressource richten sich die verschiedenen Komplexitätsmaße. Am wichtigsten sind dabei Zeitkomplexität, und Speicherplatzkomplexität, d.h. wieviel Zeit und wieviel Speicherplatz wird benötigt. 82 Gunnar Teege, UniBW München 3.6. KOMPLEXITÄT • Zu unterscheiden ist Komplexität eines Algorithmus von Komplexität eines Problems. Problem bezieht sich hier auf das Ziel, das man erreichen will. Da es für dasselbe Problem viele Algorithmen zur Lösung gibt, setzt man Komplexität des Problems gleich mit Komplexität des besten bekannten Algorithmus zu seiner Lösung. Ein Beispiel ist das Problem des Sortierens und Quicksort als Algorithmus, der das Problem löst. • Das Komplexitätsmaß für einen Algorithmus ist immer eine Funktion abhängig von der Größe der Eingabewerte (mit geeigneter Definition dieser Größe). Damit wird der Aufwand der Verarbeitung relativ zur Menge der zu verarbeitenden Information gemessen. Dies ist ein geeignetes Maß für den durch das Verfahren bestimmten Aufwand. – Beispiel Das Komplexitätsmaß des Sortierens einer Liste ist beispielsweise abhängig von der Anzahl der zu sortierenden Elemente. Das Komplexitätsmaß des Brechens einer Verschlüsselung ist üblicherweise von der Länge des Schlüssels abhängig. • Algorithmen bewertet man relativ zu ihrer Komplexität. 3.6.2 Komplexitätsklassen Komplexitätsklassen drücken eine relative Größenordnung (abzüglich konstantem Faktor) von Komplexitätsmaßen aus. • Definition Sei f: N → N eine Funktion. Die Komplexitätsklasse O(f) ist definiert durch: O(f) := { g: N → N | ∃ c > 0, m ≥ 0: ∀ n > m: 0 ≤ g(n) ≤ cf(n) } • Übliche Komplexitätsklassen Hauptsächlich verwendete Komplexitätsklassen – logarithmisch O(log n) – linear O(n) – überlinear O(n log n) – quadratisch O(n2) – polynomial O(nk), k > 2 83 Gunnar Teege, UniBW München 3.6. KOMPLEXITÄT – exponentiell O(kn), k >= 2 • Nicht-polynomiale (oder Nicht-deterministisch-polynomiale) Probleme gelten als "harte" Probleme, die man nur in kleinen Bereichen lösen kann. Beispiele für Komplexität einiger Algorithmen Such- und Sortieralgorithmen auf Reihungen. Parameter n ist Anzahl der Elemente in der Reihung. Komplexitätsmaß: Anzahl der Vergleichsoperationen. • Suchalgorithmen – Lineare Suche Bei linearer (erfolgreicher) Suche muss im Mittel die halbe Reihung (n/2 Elemente) untersucht werden. Komplexität: O(n). 84 Gunnar Teege, UniBW München 3.6. KOMPLEXITÄT – Binäre Suche Mit jedem zusätzlichen Suchschritt kann eine doppelt so große Reihung bearbeitet werden. n = 2s ( s ist Schrittzahl), d.h. Komplexität O(log n). Beispiel Annahme: Ein Suchschritt dauert 1/10 Sekunde. Dann können in vorgegebener Zeit Reihungen folgender Größe durchsucht werden: Lineare Suche Binäre Suche 1 Sekunde 10 210 = 1024 1 Minute 600 2600 1 Stunde 36000 • Sortieralgorithmen – Bubblesort Bei Bubblesort sind insgesamt n-1 Durchläufe erforderlich, bei jedem Durchlauf werden n-1 Vergleiche durchgeführt, insgesamt n2 − 2n + 1, d.h. Komplexität O( n2 ). – SelectionSort Bei SelectionSort wird in jedem Durchgang das kleinste Element im noch zu sortierenden Teil gesucht und nach vorne geholt. Es sind n-1 Durchgänge erforderlich, beim ersten werden n-1 Elemente durchsucht, danach nimmt die Größe der zu durchsuchenden Reihung jeweils um 1 ab. Insgesamt: Pn−1 2 n(n−1) = n 2−n , d.h. Komplexität O( n2 ). i=1 i = 2 – InsertionSort Bei InsertionSort wird in jedem Durchgang das nächste Element an seinem Platz im bisher sortierten Teil eingefügt. Im Mittel muss der sortierte Teil dabei jeweils halb durchsucht werden, um den Platz Auf diese P zui finden. 2 n(n−1) Weise sind n-1 Elemente einzufügen. Insgesamt: n−1 = = n 4−n , i=1 2 4 d.h. Komplexität O( n2 ). Wird bei der Suche des Platzes P im sortierten n−1 Teil Binärsuche verwendet, ergibt sich ein Aufwand von: i=1 logi < (n − 1) logn, d.h. Komplexität O(n log n). – MergeSort Bei MergeSort wird die Reihung in jedem Durchgang halbiert, dies ergibt log n Durchgänge. In jedem Durchgang werden alle Teilreihungen der Größe paarweise gemischt, dazu sind n Vergleiche nötig. Komplexität: O( n log n). – Quicksort Quicksort teilt die Reihungen im Mittel ähnlich wie MergeSort. Komplexität O(n log n). 85 Gunnar Teege, UniBW München 3.6. KOMPLEXITÄT Beispiel Annahme: Ein Sortierschritt dauert 1 ms. Dann können in vorgegebener Zeit Reihungen folgender Größe sortiert werden: Komplexität O(n2) Komplexität O(n log n) 1 Sekunde ca. 32 1 Minute ca. 250 1 Stunde ca. 2000 ca. 150 ca. 5000 ca. 200000 O(n log n) ist minimal erforderliche Komplexität für Algorithmen zum Sortieren einer Reihung. 86 Kapitel 4 Software-Engineering Softwareerstellung als Ingenieurdisziplin. • Fragestellungen des Abschnitts: – Welche Vorgehensweisen erlauben eine ingenieursmäßige SoftwareErstellung? – Welche Schritte sind dabei auszuführen? – Welche Notationen werden dabei verwendet? – Was sind Qualitätsstandards und wie werden sie eingesetzt? 4.1 Software/Engineering - Definition des Ideals Die Aufstellung und Befolgung guter Ingenieur-Grundsätze und ManagementPraktiken, sowie die Entwicklung und Anwendung zweckdienlicher Methoden und Werkzeuge, mit dem Ziel, mit vorhersagbaren Mitteln, System- und SoftwareProdukte zu erstellen, die hohe, explizit vorgegebene Qualitätsansprüche erfüllen (nach A. Marco & J. Buxton, 1987) 4.2 4.2.1 Komplexität von Software-Projekten Maße für den Umfang von Software • Zahl der Quelltextzeilen der Programme, aus denen das Softwareprodukt besteht (LOC = Lines of Code). Dabei werden i.a. die Kommentarzeilen mit berücksichtigt. 87 Gunnar Teege, UniBW München 4.3. VORGEHENSMODELLE • Zeit, die benötigt wird, um eine Programm zu erstellen (Messung in BearbeiterJahre (BJ)). 4.2.2 Klassifikation von Software-Projekten Projektklasse sehr klein klein mittel groß sehr groß 4.2.3 Quelltext-Zeilen (LOC) 1 - 1.000 1.000 - 10.000 10.000 - 100.000 100.000 - 1 Mio. 1 Mio - ... Bearbeitungsaufwand (BJ) 0 - 0,2 0,2 - 2 2 - 20 20 - 200 200 - ... Hauptanforderungen bei der Softwareentwicklung • Entwicklung zuverlässiger (fehlerfreier) Software, d.h. Software verhält sich - relativ zu vorgegebenen Toleranzwerten für Abweichungen - gemäß den Anforderungen • Entwicklung so, dass Software später problemlos geändert werden kann (z.B. wenn Fehler entdeckt werden, neue Anforderungen gestellt werden, eine andere Hardwareumgebung gewählt wird, ...). Durch die Änderung sollen nicht mehr Fehler produziert werden, als behoben werden. 4.3 Vorgehensmodelle Eine zentrale Frage beim Software Engineering betrifft das Vorgehen im Projekt, das erstens eine Fortschrittskontrolle erlaubt und zweitens die Zusammenarbeit mehrerer Entwickler und der Entwickler mit dem Management und dem Kunden erlaubt und unterstützt. 4.3.1 Code and fix-Verfahren Unsystematische Vorgehensweise in der Frühzeit der Programmiertechnik: Die Programmentwicklung begann mit dem Schreiben von Code und endete mit dem langwierigen und mühseligen Austesten und Zusammenfügen der Programmbausteine. 88 Gunnar Teege, UniBW München 4.3.2 4.3. VORGEHENSMODELLE Wasserfall-Modelle Einteilung des Entwicklungsprozesses in sequentiell aufeinander folgende Phasen. Für jede Phase sind Ausgangspunkt und Vorgaben, durchzuführende Tätigkeiten und Ergebnisse genau festgelegt. • Problemanalyse und Anforderungsdefinition • Systemd Definition: fachlicher Entwurf des Datenmodells, Anwendungsmodells • Systementwurf: Festlegung der Struktur der zu entwickelnden Software • Implementierung: Programmierung und Modultest • System-Integration und Systemtest • Installation, Betrieb und Weiterentwicklung • Graphische Darstellung 89 Gunnar Teege, UniBW München 4.4. STRUKTURIERTE PROGRAMMIERUNG – jede Projektphase endet mit einem Validierungsprozess, in dem die Ergebnisse der Phase überprüft werden. Das Wasserfallmodell geht von einem sequentiellen Prozess aus; ein Rücksprung ist nur dann erlaubt, wenn sich die Ergebnisse der vorhergehenden Phase als fehlerhaft erweisen. Fatal ist es jedoch, wenn erst beim Systemtest festgestellt wird, dass die Systemdefinition fehlerhaft ist. 4.3.3 Prototyping und Spiralmodelle Systematische Abfolge von aufeinander aufbauenden Prototyp-Entwicklungen. Lineare Abfolge der Phasen Analyse, Design und Realisierung jeweils mit den Aktivitäten Zielbestimmung, Bewertung der Alternativen, Prototypentwicklung, Verifikation. 4.4 Strukturierte Programmierung Top-Down-Entwurf: Mit Hilfe einer schrittweisen Verfeinerung wird ein komplexes, nicht überschaubares Problem in mehrere Teilprobleme zerlegt. Dies wird rekursiv fortgesetzt, bis man überschaubare Teilprobleme hat. 4.4.1 Eigenschaften Top-Down-Entwurf ist generelle Vorgehensweise beim Entwurf von Softwaresystemen; man spricht auch gelegentlich von "divide-and-conquer" • betrachtet zunächst das gesamte Programm global als eine Funktion (Operation), die nach und nach in Teilfunktionen aufgeteilt (verfeinert) wird; • das Problem wird solange zerlegt, bis es beherrschbar wird; • späte Festlegung der Datendarstellung. 4.4.2 Vorteile • man löst Schnittstellenprobleme zuerst, d.h. Festlegung der Parameter von Funktionen/Methoden. Dabei werden jeweils die Schnittstellen zwischen Funktionen auf unterschiedlichen Ebenen und Funktionen auf der gleichen Ebene betrachtet; die interne Realisierung der Funktionen interessiert zu diesem Zeitpunkt nicht; 90 Gunnar Teege, UniBW München 4.5. MODELLIERUNG • vermeidet dadurch, dass gleichzeitig an verschiedenen Stellen eventuell widersprechende Schnittstellendefinitionen gemacht werden. • erzwingt klärende Strukturierung des Programms (erleichtert Wartung und Änderung). 4.5 Modellierung Die Erstellung von geeigneten Modellen vor der Realisierung des Softwaresystems ist ein zentraler Aspekt der Softwareentwicklung 4.5.1 Wozu Modellierung? Softwarefehler oder Fehlplanungen 1992: Rettungsleitstelle in London fällt 2-mal komplett aus: Schaden ca. 9 Mio Euro, mehrere Todesfälle 1993: Das Taurus-Projekt an der Londoner Börse (automatische Transaktionsabwicklung) wird nach 5 Jahren Laufzeit wieder eingestellt; Verlust 450 Pfund 1996: Ariane 5 muss wegen plötzlichen Neigens 39sec nach dem Start gesprengt werden. Verlust der Sonnensatelliten (850 Mio DM). 2002: Ariane 5 gerät außer Kontrolle und muss in 96 km Höhe mitsamt zweier Satelliten gesprengt werden (600 Mio. Euro) 2003: Toll Collect konnte wegen Unterschätzung der Komplexität der notwendigen Software nicht wie geplant in Betrieb gehen; Verlust mehr als 1 Milliarde Euro. Modellierung zwingt zu sauberer Planung des Systems. • Modellierung vor Programmierung Modellierung dient zur Strukturierung komplexer Systeme Modelle strukturieren Systeme unabhängig von speziellen (zufälligen) Rahmenbedingungen der Implementierungsplattform durch Abstraktion Konzentration auf relevanten Teile; Ausblenden von Details intuitive Darstellung ermöglicht Lösung komplexer Probleme kompakte Beschreibung des Systems; 5 - 10 Diagramme statt 20 Seiten Text 91 Gunnar Teege, UniBW München 4.5. MODELLIERUNG Übersichtlichkeit und Verständlichkeit erleichtern Realisierung, Wartung und Kommunikation über das System. 4.5.2 Was ist Modellierung in der Informatik Definition: Ein Modell ist eine abstrahierte Beschreibung eines realen oder geplanten Systems, welche die für eine bestimmte Zielsetzung wesentlichen Eigenschaften des Systems wiedergibt. Informatische Modellierung besteht aus Abgrenzen: Identifikation der Grenzen. Abstrahieren: Weglassen von nicht oder wenig bedeutsamen Details, Sonderfällen, speziellen Ausprägungen. Idealisieren: Korrigieren kleiner Abweichungen von idealen Eigenschaften in Richtung einer leichteren Beschreibung. Beschreiben: Anwendung spezieller Techniken zur Darstellung der wesentlichen Eigenschaften des Systems. Beispiel: Bankwesen Aufgabe: Gesucht sind die Adressen und Betreuer von Kunden, deren Kredit den Betrag von 1 Mio Euro übersteigt. • Abgrenzen: EDV Ausstattung, Werbeaktionen werden ignoriert Betrachtung der Vorgänge zwischen Kunden und Betreuer • Abstrahieren: Erscheinungsbild, Alter des Betreuers sind nicht relevant wichtig sind seine Abteilung, seine Kunden • Beschreiben: durch Diagramm 92 Gunnar Teege, UniBW München 4.6. MODELLE FÜR ANALYSE UND ENTWURF • Realisierung: mit Hilfe von Tabellen in einer Datenbank; Abruf von Information SELECT Kunde.Name FROM Kunde, Kredit WHERE (Kredit.Betrag > 10000 AND Kredit.Kundennr = Kunde.Nummer) Es werden aus der Datenbank alle Kunden mit Namen aufgelistet, deren Kredit über 10000 Euro ist. Falls zusätzliche Informationen gewünscht sind, z.B. Vorname, Adresse, müsste dies nach SELECT angegeben werden. 4.6 Modelle für Analyse und Entwurf Für die Analyse des Problems, das gelöst werden soll, und den Entwurf des Softwaresystems (vor der Programmierung) existieren eine Reihe unterschiedlicher Modelle. 4.6.1 Prozessmodell Das Prozessmodell spezifiziert die Aktionen und den Datenfluss zwischen den Aktionen. Es ergibt sich ein Datenflussdiagramm. Datenflussdiagramm beschreibt den Fluss der Daten, nicht den Kontrollfluss; daher keine Programmkonstrukte wie Alternative oder Iteration im Diagramm. • Beispiel 93 Gunnar Teege, UniBW München 4.6.2 4.6. MODELLE FÜR ANALYSE UND ENTWURF Datenmodell Das Datenmodell bestimmt die im System auftretenden Entitäten, z.B. Kunde, Auftrag, Kontonummer, Artikel; im Modell werden nur die Entitätstypen festgehalten, nicht jedoch die Instanzen (d.h. nicht jeder real auftretender Kunde mit Namen). Entitäten sind fassbar. Entitäten sind keine Aktionen, sondern die Einheiten, auf denen die Aktionen ausgeführt werden. Zusammen mit den Entitäten werden die Beziehungen (Relationen) zwischen ihnen dargestellt. „Entity-Relationship-Model“ • Beispiel Kunden-/Auftragsverwaltung 94 Gunnar Teege, UniBW München 4.6. MODELLE FÜR ANALYSE UND ENTWURF • Spezifikation der Beziehungen zwischen den Entitäten – 1 : 1 Beziehung: eine Entität vom Typ A ist genau mit einer Entität vom Typ B verbunden und umgekehrt, z.B. ein Studierender hat genau eine Matrikelnummer. – 1 : n Beziehung: eine Entität vom Typ A ist mit mehreren Entitäten vom Typ B verbunden, aber nicht umgekehrt, z.B. ein Kunde kann mehrere Aufträge erteilen, aber ein Auftrag kommt immer von einem Kunden. – n : m Beziehung: jede Entität vom Typ A ist mit mehreren Entitäten vom Typ B verbunden und umgekehrt, z.B. n Studierende können auf m verschiedene Dokumente im Internet zugreifen. 4.6.3 Dynamisches Modell Das dynamische Modell spezifiziert die Zustandsübergänge in dem Softwaresystem; sie spiegeln Veränderungen des Programmzustandes wider. Zustandsübergänge werden durch das Eintreten von Ereignissen ausgelöst, z.B. Eingang eines neuen Auftrags. Beispiel Auftragseingang 95 Gunnar Teege, UniBW München 4.6. MODELLE FÜR ANALYSE UND ENTWURF "kein Auftrag", "zu bestätigen" und "zu liefern" sind Zustände, während "Auftragseingang", "Bestätigung" und "Lieferung" Ereignisse repräsentieren. Beispiel Getränkeautomat 96 Gunnar Teege, UniBW München 4.6. MODELLE FÜR ANALYSE UND ENTWURF "Aus", "Wartezustand", "Geld erhalten" und "Getränk gewählt" sind Zustände des Getränkeautomaten. • Erläuterung der Darstellung Der Übergang von einem Zustand Z1 zu einem Zustand Z2 findet genau dann statt, wenn sich das System im Zustand Z1 befindet, und die auslösende Aktion a stattfindet, und unmittelbar vor dem Übergang die Bedingung b erfüllt ist. Dann wird mit dem Übergang auch die Aktion c ausgelöst. Abstraktion: Übergänge finden (im Vergleich zur Dauer der Zustände) in unendlich kurzer Zeit statt. 97 Gunnar Teege, UniBW München 4.7. 4.7 OBJEKTORIENTIERTE SOFTWARE-ENTWICKLUNGSMETHODEN Objektorientierte Software-Entwicklungsmethoden Es gibt spezielle Methoden für die Entwicklung objektorientierter Systeme. Charakteristisch dabei ist, dass das Datenmodell nicht getrennt von den Verarbeitungsoperationen entworfen wird, sondern beides gemeinsam in Form von Klassen. 4.7.1 Modellierungssprache UML Die wichtigste Notationsmethode für objektorientierte SW-Entwicklung ist die „Unified Modeling Language “ (UML). Sie erlaubt die graphische Darstellung aller Aspekte des Systems. Dazu verwendet sie verschiedene standardisierte Diagrammtypen. Klassenstrukturdiagramme In einem Klassenstrukturdiagramm werden Klassen, ihre Merkmale (Attribute und Operationen) und die Beziehungen untereinander (z.B. Verebung) oder zwischen den Instanzen dargestellt. Klassenstrukturdiagramme können damit u.a. das Datenmodell beschreiben. • Beispiel Darstellung von Klassen und Beziehungen für einige an einer Party beteiligte Objekte: 98 Gunnar Teege, UniBW München 4.7. OBJEKTORIENTIERTE SOFTWARE-ENTWICKLUNGSMETHODEN (Bildquelle: Rupp u.a.: UML 2 glasklar) Bedeutung Zusatzzeichen bei Attributen: / bedeutet berechnetes Attribut, +, ~, # bedeuten Zugriffseinschränkungen. Sequenzdiagramme In Sequenzdiagrammen wird exemplarisch der Ablauf einer Operation dargestellt. Das Diagramm zeigt die beteiligten Objekte und die Aufrufbeziehungen (Nachrichten) zwischen den Objekten in Bezug auf die (senkrechte) Zeitachse. • Beispiel Darstellung eines Alarms als Sequenzdiagramm: 99 Gunnar Teege, UniBW München 4.7. OBJEKTORIENTIERTE SOFTWARE-ENTWICKLUNGSMETHODEN (Bildquelle: Rupp u.a.: UML 2 glasklar) Bedeutung ausgefüllte Pfeilspitzen: Sender wartet auf Antwort. Bedeutung schwarzer Punkt: unbekannte Quelle / Ziel. Bedeutung gestrichelte Linie: Antwort bzw. Erzeugung. Zustandsdiagramm Mit Zustandsdiagrammen lässt sich der „Lebenszyklus “ (Folge der Zustände) für Objekte einer bestimmten Klasse darstellen. Das Diagramm enthält die möglichen Zustände, die Übergänge zwischen den Zuständen und die Ereignisse, die die Übergänge auslösen. Zustandsdiagramme können das dynamische Modell für die Objekte einer Klasse beschreiben. • Beispiel Darstellung der möglichen Zustände von Objekten der Klasse Fahrkartenautomat als Zustandsdiagramm: 100 Gunnar Teege, UniBW München 4.8. SOFTWARE-QUALITÄTSSICHERUNG (Bildquelle: Rupp u.a.: UML 2 glasklar) Weitere Diagrammtypen UML umfasst noch viele weitere Arten von Diagrammen für spezielle Aspekte objektorientierter Systeme. In der Regel werden aber für den Entwurf eines bestimmten Systems nur einige der verfügbaren Diagrammtypen benötigt. 4.8 Software-Qualitätssicherung Unter Software-Qualitätssicherung (kurz QS) versteht man die Gesamtheit der vorbereitenden und auf erarbeitete bzw. bereits vorliegende Ergebnisse 101 Gunnar Teege, UniBW München 4.8. SOFTWARE-QUALITÄTSSICHERUNG angewendeten Maßnahmen, die geeignet sind, die geforderte Qualität eines Softwareprodukts zu erreichen oder zu erhalten. 4.8.1 Qualitätskriterien • Korrektheit, Zuverlässigkeit • Modularität, Flexibilität, Interoperabilität • Testbarkeit, Wartbarkeit • Effizienz, Wirtschaftlichkeit • Durchsichtigkeit, Verständlichkeit • Verwendbarkeit, Dokumentation 4.8.2 Maßnahmen zur Qualitätssicherung • Aufstellung eines Qualitäts-Plans, der Anforderungen und Relevanz enthält • Zeitplan für abzuhaltende Reviews, Inspektionen und sonstige QS-Maßnahmen • Richtlinien, Standards und Muster für die zu erstellenden Ergebnisse verbreiten • Begleitung und Dokumentation des Entwicklungsprozesses • Reviews, Inspektionen 4.8.3 Qualitätsnormen und Zertifizierung Bewertung/Zertifizierung der Qualität des Herstellungsprozesses. Der Standard ist vergleichbar mit einem DIN-Standard. • Reifegrad-Modell Reifegrad-Modell (Capability Maturity Model - CMM) des US-amerikanischen Software Engineering-Instituts (SEI). Das Reifegradmodell definiert die Anforderungen an das Unternehmen und die Art, wie es seine Software produziert. – CMM 1 Initial: (Ad hoc, chaotisch) Es werden keine spezifischen Anforderungen an das Unternehmen gestellt. 102 Gunnar Teege, UniBW München 4.8. SOFTWARE-QUALITÄTSSICHERUNG – CMM 2 Repeatable: (Intuitiv) Prozesse sind unter gleichen Bedingungen wiederholbar, hängen aber von einzelnen Personen ab - Projektmanagement, Projektplanung. – CMM 3 Defined: (Qualitativ) Prozesse sind definiert und eingeführt Schulung, Review-, Testtechniken. – CMM 4 Managed: (Quantitativ) Wichtige Prozessparameter werden regelmäßig ermittelt und analysiert - Prozessmessung, Problemanalyse. – CMM 5 Optimizing: Ständige Prozessverbesserung auf Basis der ermittelten Parameter und Problemanalysen. • ISO 9000 Normenserie. Nicht spezifisch für Softwareentwicklung. 103 Kapitel 5 Datenbanken • Fragestellungen des Abschnitts: – Was unterscheidet Dateisysteme von Datenbanksystemen? – Wie kann die Struktur der Daten in einem Datenbanksystem dargestellt werden? – Was sind relationale Datenbanksysteme? 5.1 Dateisysteme Dateisysteme bieten die Möglichkeit, eine Menge von Bytes unter einem symbolischen Namen (Dateinamen) anzusprechen. • Neben lokalen Dateisystemen gibt es immer mehr verteilte Dateisysteme, die es Benutzern von mehreren Rechnern aus (teilweise über Web-Browser) erlauben, auf verteilt gespeicherte Dateien zuzugreifen. Zusatzfunktionen: Volltextsuche, Notifikation bei Änderungen, Workflowunterstützung, Dokumentenmanagementsysteme. • Strukturierte Daten können abgelegt werden, indem sie Datensatz für Datensatz (sequentiell) in die Datei geschrieben werden. Zum Auslesen muss wieder Datensatz für Datensatz gelesen werden. • Probleme mit Dateisystemen – Die Interpretation der Inhalte (und der Struktur) bleibt den einzelnen Anwendungen überlassen (Dateiformate). 104 Gunnar Teege, UniBW München 5.2. DATENBANKSYSTEME ∗ Das Modell für die Struktur ist fest in die benutzende Anwendung integriert, d.h. die Datenstrukturen und Programme sind voneinander abhängig. Eine Änderung der Datenstruktur zieht meist auch eine Änderung des Programms nach sich. ∗ Schwierigkeiten Dateien zwischen unterschiedlichen Anwendungen auszutauschen. Die Anwendungen müssen jeweils die interne Struktur kennen. ∗ Alle Anwendungen lösen wiederholt die gleichen Aufgaben: Speicherverwaltung, Änderungsdienst, Lesen und Speichern von Daten, Zugriffsschutz. – Neben diesem Hauptproblem mit Dateien ergeben sich besonders bei der Verwaltung großer Mengen strukturierter Daten weitere Probleme. ∗ Zugriff auf und Änderung von Daten ist nur ineffizient implementierbar (wegen Sequentialität der Daten). ∗ Ein gleichzeitiger Zugriff mehrere Benutzer (Prozesse) auf eine Datei ist nicht möglich. ∗ Für das Rücksetzen nach Systemabstürzen stehen nur die Sicherheitskopien der kompletten Datei zur Verfügung. ∗ Datenschutz nur auf die gesamte Datei anwendbar (nicht möglich ist beispielsweise, dass die Sekretärin nur Adressen in den Mitarbeiterdatensätzen sehen darf, nicht aber das Einkommen). 5.2 Datenbanksysteme Wir leben in einer Informationsgesellschaft. Zugriff, Verarbeitung, Ablage und Weitergabe von Information spielen in unserem Leben eine immer größere Rolle. Durch das rasante Anwachsen der angebotenen Informationsmenge wird es u.a. immer schwieriger, die gewünschte Information schnell und zielgerichtet zu beschaffen. Zur Lösung dieses Problems greift man deshalb verstärkt auf Datenbanksysteme zurück. 5.2.1 Allgemeines • Problem der Datenspeicherung und -organisation wird zentral (anwendungsübergreifend) gelöst. • Datenbank = Menge von Daten, für die ein globales Modell bzgl. ihrer Struktur festgelegt ist (Datenbankschema oder Datenmodell). 105 Gunnar Teege, UniBW München 5.2. DATENBANKSYSTEME • Datenbanksystem (DBS) besteht aus einer Sammlung gespeicherter Daten (Datenbank) sowie der Software, welche Dienste zur Speicherung und zum Zugriff auf strukturierte Daten bereitstellt. – Operationen zum Eintragen, Löschen, Suchen und Verknüpfen von Daten. Wichtig ist die Verwaltung Daten mit langer Lebensdauer sowie der effiziente Zugriff auf große Mengen von Daten (GBytes, TBytes). Ein grundlegendes Prinzip bei Datenbanksystemen ist die strikte Trennung von Daten und Datenbearbeitung. Ziel ist es dabei, den Benutzer von der eigentlichen Organisation der Daten innerhalb der Datenbank unabhängig zu machen und ihm eine einheitliche, komfortable Datenschnittstelle zur Verfügung zu stellen. Das Programm ist unabhängig von der Datenorganisation. – Logischer Aufbau – Datenbankmanagementsystem Das Datenbankmanagementsystem (DBMS) ist die Gesamtheit aller Programme für den Umgang mit den Daten. Es ist verantwortlich für ∗ die sichere und einheitliche Verwaltung persistenter (langlebiger) Daten, ∗ den Datenaustausch zwischen Datenbank und Anwendungsprogrammen, 106 Gunnar Teege, UniBW München 5.3. RELATIONALE DATENBANKSYSTEME ∗ die Verhinderung von unkontrollierten Zugriffen auf den Datenbestand und ∗ die effiziente Zugriffsmöglichkeit auf die in der Regel sehr großen Datenbestände. 5.2.2 Beispiele aus der Praxis • Universitätsdatenbank Die Universitätsdatenbank ist die Sammlung aller für die Abwicklung der an einer Universität anfallenden Verwaltungsaufgaben benötigten Daten. Eine Universität gliedert sich i.a. in mehrere Fachbereiche, denen sowohl die Studenten als auch die Professoren und Mitarbeiter zugeordnet sind. Die Studenten belegen verschiedene Vorlesungen von Professoren und legen bei ihnen Prüfungen ab. Typische Anwendungen sind z.B.: Immatrikulation der Studienanfänger, Rückmeldung der Studenten, Ausfertigen von Studentenausweisen und Studienbescheinigungen, Stundenplanerstellung und Planung der Raumbelegung, Ausstellen von (Vor-)diplomzeugnissen, Exmatrikulation, Statistiken über Hörerzahlen, Raumauslastung, Prüfungsergebnisse, etc. • Datenbank einer Fluggesellschaft Eine Fluggesellschaft fliegt verschiedene Flughäfen an. Auf diesen Flugstrecken werden Flugzeuge bestimmter Typen mit dafür ausgebildetem Personal eingesetzt. Die Piloten haben Flugscheine jeweils nur für einige wenige Flugzeugtypen. Außer den Piloten gibt es noch anderes Bord- sowie Bodenpersonal. Die Flugbuchungen der Passagiere sowie das Anfertigen der Passagierlisten werden ebenfalls automatisiert durchgeführt. Typische Anwendungen sind z.B.: Flugbuchungen von Passagieren, Personaleinsatzplanung, Materialeinsatzplanung, Flugplanerstellung, Überwachung der Wartefristen, Gehaltsabrechnung. 5.3 Relationale Datenbanksysteme Mit Entity-Relationship-Diagrammen läßt sich das logische Modell einer Datenbank darstellen. Wird diese Datenbank in einem DBS implementiert, dann ist dieses logische Modell in ein physikalisches Modell zu transformieren. Ein Beispiel für ein physikalisches Datenbankmodell ist das relationale Datenbankmodell. 107 Gunnar Teege, UniBW München 5.3.1 5.3. RELATIONALE DATENBANKSYSTEME Allgemeine Eigenschaften In relationalen Datenbanken "sieht" der Benutzer die Information in Form von Tabellen. Jede dieser Tabellen besteht aus Spalten, den sogenannten Attributen. • Die Daten werden in einer Menge von Tabellen gespeichert. Normalerweise eine Tabelle je Entitymenge und eine Tabelle je Relationship-Typ (bei manchen 1:1 und 1:n Relationships sind Optimierungen möglich, die ohne eine eigene Tabelle auskommen). • Jede Tabelle hat einen Tabellennamen ("Relationenname") sowie Spalten und Zeilen. • Jede Zeile repräsentiert einen zusammengehörigen Datensatz; Zeile wird als Tupel einer Relation aufgefasst; Spalten werden als Attribute bezeichnet. • Jede Tabelle hat einen Primärschlüssel, durch den eine Zeile (Datensatz) eindeutig identifiziert ist. z.B. jeder einzelner Kunde wird durch Kundennr identifiziert. • Die Ordnung der Zeilen ist ohne Bedeutung; durch ihre Reihenfolge wird keine für den Benutzer relevante Information ausgedrückt. • Die Ordnung der Spalten ist ohne Bedeutung, da sie einen eindeutigen Namen (Attributnamen) tragen. • Alle für den Benutzer bedeutungsvolle Informationen sind ausschließlich als Datenwerte in den Tabellen ausgedrückt. • Weisen zwei Tabellen eine Spalte auf, die das gleiche Attribut beschreiben, kann eine Beziehung zwischen den beiden Tabellen hergestellt werden. Damit können Daten verschiedener Tabellen einander zugeordnet werden. Man spricht im Fall von dem gemeinsamen Attribut von einem Fremdschlüssel. • Beispiel 108 Gunnar Teege, UniBW München 5.3. RELATIONALE DATENBANKSYSTEME – Tabelle Kunde Die Tabelle Kunde modelliert die Entitymenge Kunde, d.h. jede Zeile repräsentiert einen Kunden; Primärschlüssel ist die Kundennummer. – Tabelle Buch Die Tabelle Buch modelliert die Entity Buch, d.h. jede Zeile repräsentiert ein Buch; Primärschlüssel ist die Inventarnummer. – Tabelle Entleihe Die Tabelle Entleihe modelliert die Relationship "Kunde leiht Buch aus", d.h. jede Zeile repräsentiert ein von einem Kunden ausgeliehenes Buch; Primärschlüssel ist das Paar (Kundennr, Inventarnr). Kundennr. bzw Inventarnr. sind jeweils Verweise auf Zeilen in der Tabelle Kunde bzw. Buch. 109 Gunnar Teege, UniBW München 5.3.2 5.3. RELATIONALE DATENBANKSYSTEME Umsetzung des ER-Modells Jede Entitymenge wird zu einer eigenen Tabelle die Attribute der Entitymenge werden zu den Spalten. ein Attribut (oder eine Kombination von Attributen) wird als Schlüssel definiert. eine Tabellenzeile repräsentiert eine Instanz der Entitymenge (Objektinstanz) Umsetzung von Relationship-Typ: 1:1 Eine 1:1 Beziehung kann (wahlweise) in eine der beiden Tabellen der beteiligten Entitymengen eingebaut werden. Schlüsselattribut einer Tabelle wird als Attribut in die zweite Tabelle aufgenommen (Fremdschlüssel) Umsetzung von Relationship-Typ: 1:n Eine 1:n Beziehung wird direkt umgewandelt das Schlüsselattribut der 1-Seite wird als Fremdschlüssel in die Tabelle der n-Seite aufgenommen 110 Gunnar Teege, UniBW München 5.3. RELATIONALE DATENBANKSYSTEME Umsetzung von Relationship-Typ: n:m Jede n:m Beziehung muss in einer eigenen Tabelle dargestellt werden aufgebaut aus den Schlüsselattributen der Tabellen der beteiligten Entitymengen Zusätzlich können Attribute, die sich auf die Beziehung beziehen, hinzugefügt werden. 5.3.3 Sichten Oft benötigt man bei einer Anfrage aber nicht die Daten der ganzen Tabelle, sondern nur einen Ausschnitt daraus. In Sichten oder Views werden Teilmengen 111 Gunnar Teege, UniBW München 5.3. RELATIONALE DATENBANKSYSTEME der in der Datenbank gespeicherten Information bereitgestellt. Views kann man als "virtuelle Tabellen" auffassen, die ihre Einträge nicht selbst speichern, sondern bei Bedarf nach einer vorher festgelegten Vorschrift aus den Basistabellen oder anderen bereits existierenden Views berechnen. Beispiel für eine Sicht: Vorname und Nachname von Kunden, die in München wohnen. Views sind damit nichts anderes als benannte Such-Abfragen (z.B. SQL-Anfragen in MS ACCESS mit Namen). 5.3.4 Abfragesprache SQL "Structured Query Language": Suche und Ändern von Tabelleneinträgen; seit 1989 international genormt; für fast alle relationalen Datenbanken verfügbar; Abfrage liefert als Ergebnis alle gefundenen Lösungen (d.h. mengenorientiert). Daneben kann man mit SQL auch Tabellen erzeugen (Create Table) und löschen (Drp Table). Elementare Operationen bei Abfragen Bei der Auswertung von Datenbanken will man bestimmte Attributwerte aus bestimmten Datensätzen einer Tabelle oder einer Kombination von Tabellen Beispiele: • Liste der Wohnorte aller Kunden, • alle Kontonummern mit aktuellem Kontostand und Kundennummer • ISBN und Titelname aller Werke eines bestimmten Autors, etc. Relationen n-spaltige Tabellen repräsentieren Relationen, d.h. Relationen sind Mengen, auf denen die Mengenoperationen ausgeführt werden können. • Mengenoperationen dienen als Basis für die Definition von Zugriffsoperationen auf Datenbanken Ergebnis einer Mengenoperation auf einer oder mehreren Tabellen ist wieder eine Tabelle. 112 Gunnar Teege, UniBW München 5.3. RELATIONALE DATENBANKSYSTEME Beide Tabelle 1 und Tabelle 2 haben das Attribut b. Es werden in beiden Tabellen die Zeilen herausgesucht, wo die Attributwerte für b gleich sind. Diese Zeilen (zusammen mit den zugehörigen Werten für a und c) werden in die Ergebnistabelle übernommen. • Restriktion: Auswahl von Zeilen einer Tabelle über Prädikate, z.B. allen Zeilen mit Attribut Ort = ’München’ • Projektion: Auswahl der Spalten einer Tabelle, z.B. aus der Tabelle Kunde alle Nachnamen • Natürlicher Join: Gleichverbund über alle gleichen Attribute und Projektion über die verschiedenen Attribute; Attribute sind durch Übereinstimmungsbedingung gegeben. Einen Equi-Join, bei dem sich die Gleichheitsforderung auf Attribute bezieht, die in den beiden verbundenen Tabellen den gleichen Bezeichner tragen, nennt man Natürlicher (Natural) Join. SELECT (Abfrage) Finde alle Kunden, die in der Arcisstraße in München wohnen: SELECT Vorname, Nachname, Straße FROM Kunde WHERE Ort = ’München’ AND Strasse = ’Arcisstrasse’ INSERT (Einfügen) INSERT INTO Entleihe VALUES (300, 100, ’01/12/97’) 113 Gunnar Teege, UniBW München 5.3. RELATIONALE DATENBANKSYSTEME UPDATE (Aktualisierung) UPDATE Kunde SET PLZ = "80330" WHERE Strasse = ’Arcisstrasse’ 5.3.5 Beispielsysteme Microsoft Access, Microsoft SQL Server, Oracle, DB2 (IBM), Sybase, Informix Microsoft Access MS ACCESS stellt zum Erstellen von Tabellen, Abfragen usw. im Allgemeinen Assistenten zur Verfügung. Trotzdem ist auch das direkte Arbeiten mit SQL möglich! • Ansichten in MS Access MS ACCESS unterscheidet bei Tabellen und Anfragen grundsätzlich: – die Datenblattansicht: Anzeige der Instanz einer Basistabelle bzw. der Ergebnistabelle einer Anfrage; erlaubt auch die Eingabe, die Änderung und das Löschen von Daten in einer Basistabelle. – die Entwurfsansicht: interaktives Erzeugen von Tabellen bzw. Anfragen "ohne" SQL. – die SQL-Ansicht: direktes Arbeiten mit SQL. • SQL-Ansicht Die SQL-Ansicht erlaubt die Definition von Tabellen (CREATE TABLE), das Ändern von Tabellen (ALTER TABLE), das Löschen von Tabellen (DROP TABLE), das Einfügen von Daten in Tabellen (INSERT INTO), das Ändern von Daten in Tabellen (UPDATE), das Löschen von Daten in Tabellen (DELETE) und die Erstellung von SQL-Anfragen (SELECT). 114