Grundlagen der Informatik

Slides:



Advertisements
Ähnliche Präsentationen
Algorithmen und Datenstrukturen
Advertisements

Wesen und „Unwesen“ der binären, dezimalen und hexadezimalen Zahlen
Hash-Tabellen und -Funktionen Hash-Tabellen in Java
Grundlagen der Informatik Sommersemester 2007
Kapitel 3 Codes Damit Information in einem Rechner verarbeitet werden kann, muss sie in eine für den Rechner verarbeitbare Form transformiert werden. Dabei.
Motivation Bisher: Codes mit möglichst kurzer Codelänge.
Rekursion: Rekurrenz: Algorithmen rufen sich selbst (rekursiv) auf.
Eine dynamische Menge, die diese Operationen unterstützt,
2.3 Kodierung von Zeichen 2.4 Kodierung von Zahlen
Das duale Zahlensystem
Lineare Suche Divide-and-Conquer-Suche Kombinationssuche
6. Digitale Datendarstellung
Information - syntaktisch
Kapitel 6 Algorithmentheorie
Übung 2.1 Information Wieviele Fragen benötigen Sie beim „Zahlenraten“
Anhang F:Beispielklausur In diesem Kapitel wird ein Beispiel für eine Klausur vorgestellt. Dabei sind jeweils die Aufgaben und die Lösungen gegeben. Beachten.
Grundlagen der Informatik
Lösung 3.1 Zahlensysteme Betrachten Sie den mit der Hamming-Methode codierten Code für „1000“ P-Bits falsch => Fehler bei bit
Beispielklausur In diesem Kapitel wird ein Beispiel für eine Klausur vorgestellt. Dabei sind jeweils die Aufgaben und die Lösungen gegeben. Beachten Sie.
Anhang D: Zusammenfassung
Kapitel 1 Informatik 1962 wurde der Begriff „Informatique“(als Kombination der Begriffe „Information“ und „automatique“) von Philippe Dreyfus, einem französischen.
Kapitel 4 Datenstrukturen
Java: Objektorientierte Programmierung
Sortierverfahren Richard Göbel.
Java: Dynamische Datentypen
Sortierverfahren Richard Göbel.
Übung 6.1Turing-Maschine 1.Machen Sie sich mit der Funktionsweise des Busy Beaver-Programms vertraut Vollziehen sie die 11 Schritte der ersten Turing-Tabelle.
Das Halteproblem. Gibt es einen Algorithmus, mit dem man für jedes beliebig vorgegebene Programm R und für jede beliebig vorgegebene Eingabe E entscheiden.
Algorithmus. Ein Kochrezept, zum Beispiel: Kartoffelbrei.
Datentyp- umwandlung. Literale sind: Bezeichner mit einem festen Wert wie z.B:
Algorithmentheorie 04 –Hashing
Dynamische Programmierung (2) Matrixkettenprodukt
1 Vorlesung Informatik 2 Algorithmen und Datenstrukturen (02 – Funktionenklassen) Prof. Dr. Th. Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (02 – Funktionenklassen) Tobias Lauer.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (02 – Funktionenklassen) Prof. Dr. Th. Ottmann.
WS Algorithmentheorie 08 – Dynamische Programmierung (2) Matrixkettenprodukt Prof. Dr. Th. Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (27 – Kürzeste Wege) Prof. Th. Ottmann.
Informatik II, SS 2008 Algorithmen und Datenstrukturen Vorlesung 2 Prof. Dr. Thomas Ottmann Algorithmen & Datenstrukturen, Institut für Informatik Fakultät.
Vorlesung Informatik 3 Einführung in die Theoretische Informatik (17 –Turingmaschinen) Prof. Dr. Th. Ottmann.
Kapitel 1 Das Schubfachprinzip
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Vorlesung 2 SWS WS 99/00 Gisbert Dittrich FBI Unido
Imperative Programmierung
Christian Schindelhauer
Gymnasium Horn – Bad Meinberg
Zahlensysteme und Dualarithmetik copyleft: munz
Datenformate: Text und Bild
? Was ist Informatik? Was ist Informatik? Alexander Lange
LS 2 / Informatik Datenstrukturen, Algorithmen und Programmierung 2 (DAP2)
Information und Kommunikation
Polynome und schnelle Fourier-Transformation
Einführung in die Programmierung Wintersemester 2013/14 Prof. Dr. Günter Rudolph Lehrstuhl für Algorithm Engineering Fakultät für Informatik TU Dortmund.
Vortrag Gerhard Fobe - Index
Das Binär-System Alles ist davon abhängig, ob Strom fließt oder nicht!
Grundlegende Funktionsweise eines Computers
Grundlagen der Informatik
Grundlagen der Kommunikation in Verbindung mit der Codierung von Daten
Technische Informatik II Übung 2: Konvertieren von Zahlen
Datentypen: integer, char, string, boolean
BMEVIEEA100 Grundlagen der Programmierung
ENDLICHE KÖRPER RSA – VERFAHREN.
PHP: Operatoren und Kontrollstrukturen
1 Albert-Ludwigs-Universität Freiburg Rechnernetze und Telematik Prof. Dr. Christian Schindelhauer Informatik III Christian Schindelhauer Wintersemester.
Technische Informatik II Übung 1: Konvertieren von Zahlen
Analyse der Laufzeit von Algorithmen
Kapitel 5Strukturen Information aus der realen Welt werden in einem informationsverarbeitenden System als Daten abgelegt. Diese stellen also eine (vereinfachte)
Wann ist eine Funktion (über den natürlichen Zahlen) berechenbar?
Information - syntaktisch
Vertiefungsstoff zum Thema „Darstellung von Zahlen“
Programmiersprachen II Vorbesprechung Klausur Prof. Dr. Reiner Güttler Fachbereich GIS HTW.
Prof. J. Walter Bitte römische Zahlen im Geschichtsunterricht!
 Präsentation transkript:

Grundlagen der Informatik Prof. Dr. Peter Kneisel

Zum Kennenlernen Wie alt sind Sie ? Aus welchen (Bundes-)Ländern kommen Sie ? Wo wohnen Sie während des Studiums ? Welchen Bildungsweg sind Sie gegangen ? Wer hatte Informatik in der Schule ? Welches Fach studieren Sie ? Warum studieren Sie hier an der FH Gießen ? Wer besitzt einen Computer ? Wie lange sitzen Sie vor dem Computer ? Was machen Sie da ? Welche Programmiersprache können Sie ? Welche Betriebssysteme (OSe) kennen Sie ? Welche Anwendungen kennen Sie ? Was erwarten Sie (nicht) von dieser Vorlesung ? Was denken Sie, mit dieser Vorlesung anfangen zu können ?

Didaktik: Durchführung Diese Vorlesung ist formal 3-stündig mit einer Stunde Übungen Die Übungen werden in diesem Verhältnis, aber nur je nach Bedarf durchgeführt. Zur Vorbereitung werden Übungsblätter, je nach Vorlesungsverlauf zusammengestellt. Weitere Übungen sind im Foliensatz vorhanden und sollten selbständig und vollständig bearbeitet werden. Der Vorlesungsstoff ist an die Struktur und Inhalten der GDI-Vorlesung von Dr. Geisse angelehnt. Zur Vor- und Nachbereitung des Stoffes können Sie daher zusätzlich dessen Vorlesungsmitschrift (erhältlich in der Fachschaft) verwenden Da sich die Inhalte und insbesondere auch Schwerpunkte leicht verschieben ist dennoch ein Arbeiten mit meinem Foliensatz erforderlich Vorsicht ! Kommen Sie in alle Veranstaltungen - machen Sie die Übungen überschätzen Sie sich nicht - auch wenn Sie PC-Crack sind Schreiben Sie die Klausur nur, wenn Sie eine Chance haben ( Ich hasse es, Zeit mit dem Korrigieren hoffnungsloser Fälle zu vergeuden ;-)

Didaktik: Folien Der Vorlesungsstoff wird anhand von Folien dargelegt Die Folien bilden nur einen Rahmen für die Inhalte. Die Folien sollten daher mit Hilfe eigener Vorlesungsskizzen ergänzt werden - am besten in Form einer Vorlesungsnachbereitung max. 3 Tage nach der Vorlesung Zusätzlich zu den Folien werden Beispiele an der Tafel oder am Rechner gezeigt. Diese sollten Sie vollständig mitskizzieren. Zur vollständigen Nachbereitung, z.B. als Klausurvorbereitung, sind die Folien einheitlich strukturiert Es gibt genau drei Gliederungsebenen: Kapitel, Unterkapitel, Abschnitte Die Inhalte jedes Kapitels und jedes Unterkapitels werden jeweils motiviert und sind verbal beschrieben. Zusätzlich gibt es jeweils ein stichwortartiges Inhaltsverzeichnis der Unterkapitel, bzw. Abschnitte Die Vorlesung wird ständig überarbeitet, so dass sich die Foliensätze ändern können (und werden) Laden Sie sich zur endgültigen vollständigen Nachbereitung nochmals zusätzlich den kompletten Foliensatz herunter.

Literatur Diese Veranstaltung ist anhand (wirklich) vieler Bücher und einer Menge eigener Erfahrungen erstellt worden. Jedes Buch hat dabei Schwerpunkte in speziellen Bereichen und ist daher sinnvoll. Eine Auflistung aller dieser Bücher ist nicht sinnvoll. An dieser Stelle seien daher nur drei Bücher aufgeführt, die einen guten Einstieg in die Informatik darstellen. (Diese Liste ist identisch mit der von Dr.Geisse erstellten Liste) Ch. Horn, I.O. Kerner, P.Forlig Lehr- und Arbeitsbuch - Informatik, Band 1 Grundlagen und Überblick Fachbuchverlag Leibzig 2001 P. Reichenberg Was ist Informatik - Eine allgemeinverständliche Einführung Hanser Verlag München 1991 Fl. Bauer, G. Goos Informatik - eine einführende Übersicht Band 1+2 Springer Verlag Berlin 19991/92

Inhalt Wie jede Wissenschaft befasst sich die Informatik mit ihren eigenen „Objekten“. Was diese „Objekte“ sind und was man mit diesen Objekten machen kann - und wie - wird in dieser Vorlesung auf eher abstraktem Niveau, aber immer mit Beispielen aus der Realität eines Informatikers (oder einer Informatikerin), erläutert. Diese Vorlesung konzentriert sich auf den „Kern“ der Informatik. Vertieftere Einführungen in z.B die Bereiche der Programmierung, Rechnerarchitekturen, Betriebssysteme, etc. sollen daher bewusst den entsprechenden Veranstaltungen vorbehalten bleiben Inhalt Informatik Information und Codes Zeichen und Zahlen Datenstrukturen Algorithmenentwurf Algorithmentheorie Sprachen

Überblick und Einordnung Prg2 SWT1 DSt CB RA2 Typ2-Sprachen 7 Sprachen Typ3-Sprachen Syntax und Semantik Daten- strukturen 4 Prg1 Komplexität RA1 Dynamik (Algorithmik) 6 Korrektheit Zeichen 3 Statik (Struktur) Berechenbarkeit Zahlen Strukturierung Codes 2 5 Elemente Information Praktische Theoretische Technische 1 Informatik

Kapitel 1 Informatik 1962 wurde der Begriff „Informatique“(als Kombination der Begriffe „Information“ und „automatique“) von Philippe Dreyfus, einem französischen Ingenieur eingeführt und als „Informatik“ ins Deutsche übernommen. Als junge Wissenschaft ist die Informatik mittlerweile in viele Bereiche der älteren Wissenschaften eingezogen und hat viele eigene Bereiche neu erschlossen. Die Informatik ist damit mittlerweile wesentlich mehr, als der anglo-amerikanische Begriff „Computer-Science“ vermuten lässt. Dieses Kapitel möchte einen (kurzen) Überblick über exemplarische Inhalte, Struktur und Geschichte der Informatik geben Inhalt Motivation Definition Die Teilgebiete der Informatik Die Geschichte der Informatik Zusammenfassung des Kapitels

1.1 Motivation Die Beherrschung eines Computers macht Spaß und gibt der informationssüchtigen Gesellschaft das Gefühl persönlicher Freiheit (so wie vor Jahren ein roter Sportwagen) Die Beherrschung gibt Macht. Für das Funktionieren einer demokratischen Gesellschaft ist es wichtig, daß viele Menschen Computer verstehen und beherrschen. Der Computer schafft und vernichtet Arbeitsplätze und ist eine Herausforderung für die Gesellschaft Das Verstehen der Gesetzmäßigkeiten bei der Entwicklung von Computerprogrammen ist eine intellektuelle Herausforderung Das Umsetzen dieses Verständnisses ist eine intellektuelle Genugtuung. Der Computer schafft neue Betätigungsfelder und Lebensinhalte Der professionelle Umgang mit Computer ist im Beruftsleben eine nackte Notwendigkeit !

1.2 Was ist Informatik Jedes Lehrbuch der Informatik gibt seine Definition der „Informatik“. Auch der Duden beschreibt die Informatik als „Wissenschaft von der systematischen Verarbeitung von Informationen, besonders der automatischen Verarbeitung mit Hilfe von Digitalrechnern“. Durch die Beschränkung auf den Aspekt der „Verarbeitung“ geht diese Definition meines Erachtens nicht weit genug. Ich werde daher in diesem Unterkapitel eine eigene Definition wagen. Die dabei verwendeten Aspekte werden exemplarisch verdeutlicht, wobei bewusst in Grenzbereiche der Informatik gegangen wird . Was die Informatik wirklich ist, kann kein Lehrbuch erfassen. Sie werden - hoffentlich - am Ende Ihres Studiums eine sehr weitreichende Idee davon haben. Inhalt Definition Beispiele

Informatik 1.2.1 Definition Die Wissenschaft, die sich mit dem (automatisierten) Erfassen Transportieren Speichern Verarbeiten Umsetzen von Information befasst

1.2.2 Wissenschaft Informatik ist nicht die Wissenschaft vom Computer (sowenig, wie Astronomie die Wissenschaft vom Teleskop ist) Informatik ist eine Wissenschaft … und keine Bastelecke für Software-Spieler Aspekte der Informatik als „reine Lehre“ (verwandt mit der Mathematik) Naturwissenschaft: entdecken und beschreiben von „natürlichen“ Phänomenen Ingenieurwissenschaft - mit der typischen Vorgehensweise Problemstellung Analyse Teillösungen Synthese Lösung

1.2.3 Information Information ist die Bedeutung, die durch eine Nachricht übermittelt wird (nachrichtentechnische Definition)  Kapitel 2 Information ist eine elementare Kategorie Chemie: Stoffumwandlung Physik: Energieumwandlung Informatik: Informationsumwandlung

1.2.4 Erfassen Sensorik 300000 Datenmenge (Byte) 60000 (52,204,248) Bildverarbeitung 300000 Datenmenge (Byte) 60000 (52,204,248) (33,75,125,190,251) 3000 100

1.2.5 Transportieren Telekommunikation Telephonie ~5-25000 Hz 300 - 3400 Hz

1.2.6 Speichern Datenrepräsentation Abstrakte Datentypen (N. Wirth: Algorithmen und Datenstrukturen) Einfache Typen Aufzählungstypen Integer Real Boolean Char ... {rot, gelb, grün} [0,1,..,65535] [3,4e-038,..3,4e038] {TRUE, FALSE} {ASC(0),..,ASC(255)} Strukturierte Typen Array Record Varianten Record Menge ... array [n..m] of Type record Type 1: element 1 Type n: element n end set of Type Abstrakte Typen Listen Binäre Bäume Vielweg Bäume Graphen ...

1.2.6 Speichern Datenrepräsentation Objektrepräsentation (G. Booch: Objektorientierte Analyse und Design) Assoziation Vererbung Aggregation Verwendung Instantiierung Klassenname Attribute Operationen Einschränkungen Teil projekt Projekt Projektleiter Mitarbeiter n Buchhaltung Controlling Personalwesen 1

1.2.6 Speichern Datenrepräsentation Objektrepräsentation (B.Stroustrup: The C++ Programming Language) Teilprojekt Projekt Projektleiter Mitarbeiter n Buchhaltung Controlling Personalwesen 1 Assoziation Vererbung Aggregation Verwendung Instantiierung Class Teilprojekt: public Projekt { Projektleiter projektleiter; Mitarbeiter mitarbeiter[MAX_MITARBEITER]; public: Teilprojekt (Projektleiter); ~Teilprojekt (); } Teilprojekt::Teilprojekt(Projektleiter pl) { // some method-calls of Buchhaltung, Controlling, Personalwesen main { Teilprojekt1 = new Teilprojekt(Projektleiter1) // See Budget1 for buget details on Teilprojekt1 n 1

1.2.7 Verarbeiten Prozessmodelle Petri-Netze (C.A.Petri: Kommunikation und Automaten))

1.2.7 Verarbeiten Prozessmodelle Interaktionsdiagramme (G. Booch: Objektorientierte Analyse und Design) R1 R2 R3 R4 R5 N2 N1

1.2.7 Verarbeiten KI-Ansätze ai=F(Wij*Oj ,ai) a Aktivierungszustand W Verbindungsgewichtung O Ausgangswert F Aktivierungsfunktion f Ausgabefunktion Oj Oi=f(ai) Wij Neuronale Netze Axon Dendrite Synapsen

1.2.8 Umsetzen Aktorik Manipulatoren Anzahl Freiheitsgrade 25 9 2 (1)

1.2.9 Zusammenfassung Reduktion von Redundanz Strukturierung von Information Abbildung realer Prozesse auf Rechnerprozesse Abbildung von Rechnerprozessen auf reale Prozesse Abbildung von Datenstrukturen auf reale Strukturen

1.3 Die Teilgebiete der Informatik Wie viele Wissenschaften, ist die Informatik kein homogenes Gebilde, sondern lässt sich anhand unterschiedlicher Kriterien in Teilgebiete strukturieren. Dieses Kapitel beschreibt die wohl geläufigste Einteilung der Informatik in drei, bzw. vier Teilbereiche. Inhalte Technische Informatk Praktische Informatik Theoretische Informatik ( Angewandte Informatik )

1.3.1 Technische Informatik Konstruktion von Verarbeitungselementen Prozessoren, ... Konstruktion von Speicherelementen Hauptspeicher, ... Konstruktion von Kommunikationselementen Bussysteme Lokale Rechnernetze (LAN: Local Area Networks), Weitverkehrsnetze (WAN: Wide Area Networks), ... Mobilfunknetze, Satellitenkommunikation, ... Konstruktion von Peripherie Drucker, Scanner, .... Festplatten, Optische Platten, Diskettenlaufwerke, ... ...

1.3.2 Praktische Informatik Umgang mit Programmiersprachen Compilerbau ... Entwicklung von Software Analysemethoden Designmethoden Realisieruingsmethoden Testverfahren Unterstützung der Softwareentwicklung Projektmanagment von DV-Projekten Qualitätsmanagement in DV-Projekten

1.3.3 Theoretische Informatik Sprachen und Automaten Formale Sprachen Grammatiken Sprachdefinitionen Berechenbarkeitstheorie Komplexitätstheorie ...

1.3.4 Angewandte Informatik Anwendung in verwandten Wissenschaften Numerische oder stochastischer Verfahren in der Mathematik Simulationen in der Physik und der Chemie Bildverarbeitung in der Medizin Genanalyse in der Biologie Lehrprogramme für Natur-, Sozial- und Geisteswissenschaften ... Anwendungen im täglichen Leben. Computerspiele, Multimediaanwendungen, Textverarbeitung, Tabellenkalkulation, Datenbanken, ... Steuerung von technischen Prozessen Web-Anwendungen

1.4 Die Geschichte der Informatik Die Informatik ist eine junge Wissenschaft, hat aber, ähnlich wie andere Natur- und Ingenieurwissenschaften Wurzeln, die weit in die Menschheitsgeschichte hineinragen, Wie keine andere Wissenschaft wurde die Informatik jedoch von der Erfindung eines Gerätes, dem programmgesteuerten Rechner (später „Computer“) beeinflusst. Dieses Unterkapitel wird die Wurzel in der Menschheitsgeschichte und auch die Entwicklung des Rechners vorstellen. Inhalt Information in der Geschichte Automaten und Steuerungen Erleichterung der Rechenarbeit Pioniere der Informatik - Praktiker Pioniere der Informatik - Theoretiker Die Generationen

1.4.1 Information in der Geschichte Erfassung durch Sinnesorgane Transport durch akustische, optische, chemische Signale Speicherung durch Gene oder neuronale Elemente Verarbeitung über neuronale Elemente Umsetzung direkt oder indirekt über Gliedmaße Entwicklung von Wort,- Silben- und Buchstaben-schriften

1.4.2 Automaten und Steuerungen ca. 100 n. Chr. Automatische Tempeltore in Anhängigkeit von Opferfeuer (Heron von Alexandria) Mittelalter Mechanische Uhren mit Sonnen-, Mond- und Planetenbewegungen und Figurenumläufe an Kirchen und Rathäusern 17./18. Jhdt. Spieluhren, Schreib- und Schachspielautomaten 18./19. Jhdt. Fliehkraftregler für Dampfmaschinen, mechanischer Webstuhl mit Lochkartenbändert (Jacquart, 1805)

1.4.3 Erleichterung der Rechenarbeit Rechenbretter Seit dem Altertum China, Japan, Rußland Addition/Subtraktion ähnlich schnell wie Taschenrechner Lehre der Grundrechenarten Durch Zahlensystem schematisierbar Lehre an mittelalterlichen Universitäten Durch Rechenbücher weitere Verbreitung des Wissens (z.B. Adam Riese 1492-1559) Rückführung der Multiplikation/Division auf Addition/Subtraktion durch logarithmisches Rechnen mit Hilfe von Tabellen.

1.4.4 Mechanische Rechenmaschinen Wilhelm Schickart (1592-1635) Maschine für die Grundrechenarten (1623) Blaise Pascal (1623-1662) Gottfried Wilhelm von Leibniz (1646-1716) Arithmetik des Dualsystems Philipp Matthäus Hahn (1749-1790) Feinmechanische Rechenmaschinen 19./20. Jhdt: Sprossenradmaschine Hermann Hollerith Lochkartenstanzer/ -sortierer/-tabellierer

1.4.5 Pioniere der Informatik - Praktiker Charles Babbage (1791-1871) Difference Engine (1812). Überprüfung von Logarithmentafeln. Alle Merkmale eines programmierbaren Computers. Entwurf einer Analytical Engine (1836). Wurde nie gebaut Konrad Zuse (geb. 1910) Z1: mechanischer Rechner Z2 / Z3: Elektromechanischer Relaisrechner im Dualsystem mit Lochkartensteuerung. Erster voll funktionstüchtiger Computer (1941) Grundlegende Arbeiten zur Programmierung und algorithmischer Sprachen Howard Eiken Mark I, II, III, IV (1944) Dezimalrechnender Relaisrechner

1.4.6 Pioniere der Informatik - Theoretiker Kurt Gödel Theoretische Aussagen zum Algorithmenbegriff: Es gibt Aussagen die algorithmisch nicht entscheidbar sind (1931) Alan M. Turing (1911-1954) Definition des Algorithmenbegriffes über eine hypothetische Maschine (Turing-Maschine) John von Neumann (1903-1957) Grundlegende Arbeiten über Computerarchitektur: Speicherung der Daten und Programme auf dem gleichen Medium Definition von Registern insb. Indexregister

1.4.7 Die Generationen Generation Beispiel Technologie Speich./Geschw. Software Vorgenerat. Z3 Elektro- 0,0002 MIPS Verdrahtet 1941-1944 Mark1 mechanik 1.Generation ENIAC, Z22 Elektro- 0,02 MIPS Maschinen- 1946 - 1958 UNIVAC, IBM650 röhren 1-2 Kbyte sprache SIEMENS704 2. Generation IBM1400, AEG TR Transistoren 0,1 MIPS Assembler 1959 - 1964 CDC6600 Kernspeicher 32 KByte FORTRAN Siemens2002 Stapelbetrieb 3. Generation IBM370, PDP11 ICs 5 MIPS Hochsprachen 1965 - 1980 Siemens7000, Halbleiter- 1-2 Mbytes C, Pascal Cray 1 speicher 4. Generation PC, Gray XMP Mikro- 50 MIPS Sprachen der 1981-1999 Sperry1100, VAX prozessoren 8-32 MByte 4. Generation IBM309x Optische Sp. Parallelisierung Gegenwart Workstations Pentium, 100 MIPS Netzsoftware Hochleistungs- Power PC 1 GByte OO-Sprachen PCs Netze C++. JAVA 5. Generation supraleitende 1000 MIPS Keramiken viele GBytes

1.5 Zusammenfassung des Kapitels Die Informatik befasst sich mit der (automatisierten) Erfassung, dem Transport, der Speicherung, Verarbeitung und dem Umsetzen von Information Die Informatik ist eine „naturwissenschaftliche Ingenieurswissenschaft“ Die Informatik gliedert sich in Technische, Praktische, Theoretische und Angewandte Informatik Die Geschichte der Informatik beginnt im Altertum, besteht in Ihrer heutigen Form aber erst seit ca 1945. Zur Zeit befinden wir uns in der 4. Generation.

Kapitel 2 Information und Codes Information ist der grundlegende Begriff in der Informatik - dieses Kapitel erläutert diesen Begriff: Zunächst wird Information in ihrer Repräsentation als „Nachricht“ betrachtet und damit einige Maßzahlen definiert. Danach wird auf die Repräsentation von Information in der Informatik und deren Maßzahlen eingegangen. Schließlich wird auf die Möglichkeiten zur Umsetzung - Kodierung - von Information eingegangen Inhalt Was ist Information Definition nach Shannon Definition in der Informatik Codes

2.1 Was ist Information Nicht: Was ist Information ? Information ist eine elementare Kategorie wie z.B. Energie oder „Stoff“ Nicht: Was ist Information ? sondern: Wie ist Information ? Qualitativ: Repräsentationsformen der Information DNS (Aminosäuren in einem Doppelhelix) Verschaltung von Neuronen und deren Empfindlichkeit physikalisches Objekt (Atome im Raum) Bild (Bildpunkte auf einer Ebene) Energieverteilung (Energie im Raum) Folge von Zeichen (Zeichen in einer Zeichenkette) ..... Quantitativ: Maßzahlen für Information  später in diesem Kapitel

2.2 Definition nach Shannon Information hat vielfältige Repräsentationsformen. Noch vor Entstehen der Informatik als Wissenschaft hat Claude Elwood Shannon (1916-2001) wichtige Maßzahlen zur Erfassung von Information definiert. Dabei geht er von der nachrichtentechnischen Repräsentation von Information, der „Nachricht“ aus. Dieses Unterkapitel stellt diese Maßzahlen und deren Grundlagen dar. Inhalt: Nachricht Informationsgehalt einer Nachricht Informationsgehalt eines Zeichens Mittlerer Informationsgehalt

2.2.1 Definition: Nachricht sei Alphabet X: Menge von Symbolen/Zeichen X = {x1, x2, ... xn} Eine Zeichenkette (ein Wort) der Länge n über X ist eine Folge von n Zeichen aus X (ein n-Tupel über X) Beispiel: X={a,b} Worte über X: {a,b,ab,ba,aba,abb,baa,bbb, ...} Worte der Länge n mit n=3: {aba,abb,baa,bbb} Die Menge aller n-Tupel über X ist das n-fache Kreuzprodukt X  X  ...  X (n mal), bezeichnet als Xn |Xn| = | X  X  ...  X | = |X| * |X| * ... * |X| = |X|n Die Anzahl der Elemente alle Worte mit der maximalen Länge n ist |X|n Wird eine Zeichenkette übermittelt, so spricht man von Nachricht Nx

2.2.2 Definition: Informationsgehalt einer Nachricht Ein Maß für die Information (der Informationsgehalt) einer Nachricht Nn,x der Länge n (über ein Alphabet X) ist die Länge der Beschreibung, die notwendig ist, um die Nachricht Nn,x aus der Menge aller möglichen Nachrichten der Länge n zu ermitteln Beispiel: Information der Nachricht N8,{0,1} : Suche in |{0,1}|8 = 256 Wörtern Optimal mit binärem Suchen Anzahl Fragen: ld(|Xn|) = ld(|X|n) = n ld(|X|) obere Hälfte ? ja nein ... Der Informationsgehalt einer aus mehreren (voneinander unabhängigen) Zeichen bestehenden Zeichenkette ist gleich der Summe der Informationen der einzelnen Zeichen: 1 * ld(|X|) + 1* ld(|X|) + ... + 1* ld(|X|) = n * ld(|X|) = ld(|X|n)

2.2.3 Definition: Informationsgehalt eines Zeichens Idee: Der Informationsgehalt eines Symbols xi hängt von der Wahrscheinlichkeit seines Auftretens ab: Je seltener ein Symbol auftritt, desto höher ist sein Informationsgehalt: h(xi) = f(1/p(xi)) Definition nach Shannon (ca. 1950): Der Informationsgehalt h (Einheit bit) eines Symbols xi ist definiert als der Logarithmus dualis des Reziprokwertes der Wahrscheinlichkeit, mit der das Symbol auftritt: h(xi) = ld(1/p(xi)) = -ld p(xi)

2.2.4 Beispiel: Informationsgehalt Beispiel: Sei die Wahrscheinlichkeit von E = 0,5 und die von H = 0,25 Informationsgehalt des Zeichens „E“ : hE = ld (1/0.5) = 1 Informationsgehalt des Zeichens „H“ : hH = ld (1/0,25) = 2 Informationsgehalt der Zeichenkette „EHE“ hEHE = ld(2) + ld(4) + ld(2) = ld(2 * 4 * 2) = 4 bit log a b = log c b log c a mit a = 2, c = 10 gilt: ld b = lg b lg 2  3,322 lg b Umrechnungsregel des ld in den 10er-Logarithmus (lg)

2.2.5 Definition: Mittlerer Informationsgehalt Kennt man die Einzelwahrscheinlichkeiten aller möglichen Symbole einer Symbolsequenz, so ist der mittlere Informationsgehalt Hs der Symbole s (Entropie der Quelle) definiert als: Hs = S p(xi) * h(xi) = S p(xi) * ld(1/p(xi)) = - S p(xi) * ld(p(xi)) Der mittlere Informationsgehalt Hs,n einer Symbolkette der Länge n ist: Hs,n = Hs * n Beispiel d.h. die Symbole haben einen mittleren Informa- tionsgehalt von 1,5 bit. Hs = 0,5 * 1 + 0,25 * 2 + 0,25 * 2 = 1,5 bit

2.2.6 Informationsaufnahme des Menschen Beim Lesen erreicht der Mensch eine Geschwindigkeit von ca. 25 Zeichen/sec das entspricht 25 * 2 Bit (mittleren Informationsgehalt) = 50 Bit/sec dieser Wert ist unabhängig vom Alphabet - kann also auch z.B. im chinesischen erreicht werden. Nachrichten, die mit anderen Medien dargestellt werden, können ca. genauso schnell verarbeitet werden. Aufnahme des Menschen Bewusst aufgenommen werden ca. 50% von 50 Bit/sec also 25 bit/sec Bei einer Aufnahmedauer von ca. 16 Stunden am Tag ergibt sich eine Lebensinformationsmenge von ca. 3 * 1010 Bit die Speicherkapazität des Gehirns ist mit ca. 1012 Bit auch in der Lage, diese Informationsmenge zu speichern (sogar 100 Mal) Die Lebensinformationsmenge findet auf einer CD-ROM Platz und ist über Glasfaserkabel in wenigen Sekunden zu übertragen.

2.3 Definition in der Informatik Die Wurzeln der Informatik liegen weniger in der Nachrichtentechnik, als vielmehr in der Mathematik. Darum ist die Repräsemtation von Information als Nachricht weniger relevant als die Darstellung von Zahlen (in binärer Repräsentation) und algebraischen (bool‘schen) Objekten. In diesem Unterkapitel geht es um diese Repräsentationen. Inhalt Das Bit in der Informatik Die Darstellung des Bit Beispiel Das Byte und mehr

2.3.1 Das Bit in der Informatik Definition aus der Informatik: Ein Bit ist die Informationsmenge in einer Antwort, auf eine Frage, die zwei Möglichkieten zuläßt: ja /nein wahr/falsch schwarz/weiß ... Der Informationsgehalt eines Zeichens einer zweielementigen Alphabetes mit gleicher Auftretungswahrscheinlichkeit ist (nach Shannon) h = -ld p = -ld 0,5 = 1

2.3.2 Die Darstellung des Bit Diese zwei Möglichkeiten werden meist mit 0 bzw. 1 codiert Die technische Darstellung erfolgt u.a. mit Hilfe von: Ladung 0 = ungeladen 1 = geladen Spannung 0 = 0 Volt 1 = 5 Volt Magnetisierung 0 = nicht magnetisiert 1 = magnetisiert Licht 0 = kein Licht 1 = Licht

2.3.3 Beispiel: Bitfolge Aus welcher Himmelsrichtung weht der Wind (N, O, S, W) ? Bei anzunehmender Gleichverteilung der Antworten ist der mittlere Informationsgehalt H = S p(xi) * ld(1/p(xi)) = (0,25*2)*4 = 2 Die Frage läßt sich in zwei Fragen umsetzen Weht der Wind aus N oder O (ja/nein) ? Weht der Wind aus O oder W (ja/nein) ? Eine mögliche Antwort: 1 Frage=ja, 2 Frage=nein läßt sich durch die Bitfolge 10 darstellen und bezeichnet eindeutig Norden als die Windrichtung 10 = Norden 11 = Osten 01 = Westen 00 = Süden Nimmt man noch die Zwischenrichtungen NO, SO, SW und NW hinzu, so können die 8 Zustände mit 3 Bit codiert werden (wie?)

2.3.4 Das Byte und mehr Aus bestimmten Gründen Geschwindigkeit von Lese- und Schreiboperationen Darstellungsmöglichkeit „häufiger“ Zeichen (z.B. Alphabet) Darstellungsmöglichkeiten von Zahlen, etc. werden in der Informatik oft Vielfache von 8Bit-Gruppen verwendet (8Bit, 16Bit, ...) Eine 8-Bitsequenz heißt ein Byte. Bestimmte 2er-Potenzen werden in der Informatik häufig als Maßzahlen (z.B. für Speichergrößen) verwendet: 1 kByte = 210 = 1024 Byte (1 Kilobyte) 1 Mbyte = 210 * 210 Byte (1 Megabyte) 1 Gbyte = 210 * 210 * 210 Byte (1 Gigabyte) 1 Tbyte = 210 * 210 * 210 * 210 Byte (1 Terabyte)

2.4 Codes Damit Information in einem Rechner verarbeitet werden kann, muss sie in eine für den Rechner verarbeitbare Form transformiert werden. Dabei kann man sich beliebig ungeschickt anstellen. Dieses Unterkapitel beschreibt, wie eine solche Transformation funktionieren kann, welche Möglichkeiten man dabei hat und gibt ein Maß für die Qualität einer Transformation an. Inhalt Was ist ein Code Willkürliche Codes Codes zur Optimierung der Codelänge Codes zur Fehlererkennung und –korrektur Redundanz

2.4.1 Was ist ein Code Definition: Seien X,Y zwei Alphabete Eine Codierung ist eine Abbildung C:XnYm aller n-Tupel aus X nach m-Tupel aus Y. oft ist n=1 oft ist Y = {0,1} Die Worte aus Ym werden Code genannt. Die Umkehrrelation C-1 bezeichnet man als Dekodierung Definition: Ein Code heißt vollständig, wenn alle Wörter aus Xn mit Hilfe des Codes abgebildet werden können. Definirion: Ein Code heißt eindeutig, wenn der Code aller Wörter aus Xn unterschiedlich ist, ansonsten heiß er mehrdeutig

2.4.2 Willkürliche Codes Codes sollten so beschaffen sein, dass sie bei der Decodierung eindeutig sind. Beispiel: z p h h * p c l l * p A 0,2 5,00 2,32 101 3 0,60 E 0,3 3,33 1,74 01 2 I 100 O 0,25 4,00 2,00 11 0,50 U 0,05 20,00 4,32 11100 5 R=L-H=0,38 H = 2,17 L = 2,55 Problem Dekodierung: 10111100100 = 101 11100 100 (aui) 101 11 100 100 (aoil)

2.4.2 Willkürliche Codes: Fano-Bedingung Kein Codewort darf Anfang eines anderen Codewortes sein Beispiel: z c A 101 E 01 I 100 O 11 U 11100 z c A 00 E 10 I 010 O 11 U 011 Die Fano-Bedingung ist hinreichend aber nicht notwendig Beispiel: a  1, b  10

2.4.3 Huffman-Codierung Oft ist es wichtig, einen Code möglichst kurz zu gestalten Idee Häufige Symbole – kurze Codes, Seltene Symbole – lange Codes Kodierung Die Häufigkeit des Auftretens der Bitmuster (Bytes) wird bestimmt Die am häufigsten auftretenden Bytes werden mit kurzen Bitfolgen (Huffmann-kode) kodiert Der Huffmann-code wird zur Kodierung der Bitfolge verwendet Dekodierung Dekodierer besitzt identischen Huffmann-kode (oder bekommt die Zuordnungstabelle explizit übertragen) Dekodierer setzt den Huffmann-code in Bytefolge um

2.4.3 Huffman-Codierung: Vorgehen Der Baum wird von oben nach unten mit den zwei Buchstaben (oder Buchstabengruppen) mit den jeweils kleinsten Wahrscheinlichkeiten schrittweise aufgebaut P(C)=0,09 P(E)=0,11 P(CE)=0,2 1 P(D)=0,13 P(A)=0,16 P(AD)=0,29 1 sei P(A) = 0,16 P(B) = 0,51 P(C) = 0,09 P(D) = 0,13 P(E) = 0,11 Kodierung A = 000 B = 1 C = 011 D = 001 E = 010 P(CEAD)=0,49 1 P(B)=0,51 P(BCEAD)=1,0 1

2.4.3 Huffman-Codierung: Verbesserung Codierung ist optimal, wenn sich die Wahrscheinlichkeiten der Zeichen „geschickt“ ergeben „geschickt“ sind Wahrscheinlichkeiten mit negativen 2er-Potenzen. Durch Betrachtung (und Codierung) von Zeichenpaaren, -drillingen, ... , n-Tupeln können solche „geschickten“ Wahrscheinlichkeiten gefunden werden Die Redundanzen lassen sich sogar beliebig verkleinern, weil die Einzelwahrscheinlichkeiten von n-Tupeln beliebig klein werden und dadurch immer „geschickter“ kombiniert werden können Beispiel: z p A 0,80 B 0,20 z p AA 0,64 AB 0,16 BA BB 0,04 z p AAA 0,512 AAB 0,032 ABA 0,128 ... BBB 0,008 ... Produkt der Einzelwahrscheinlichkeiten

2.4.3 Huffman-Codierung: Beispiel z p h h * p c l l * p A 0,80 0,32 0,26 1 B 0,20 2,32 0,46 R = 0,26 H = 0,72 L = 1,00 z p h h * p c l l * p AA 0,64 1,56 0,41 1 AB 0,16 6,25 0,42 10 2 0,32 BA 110 3 0,48 BB 0,04 25,00 0,19 111 0,12 R = 0,12 H = 1,44 L = 1,56

2.4.4 Hamming-Codierung Manchmal ist es wichtig, Fehler in einem Code zu erkennen und ggf. zu korrigieren. (z.B. bei der Übertragung) Idee Gezielter Einsatz von Redundanz Nicht alle möglichen Codeworte sind daher gültig Kodierung Dem Code werden zusätzliche Bits hinzugefügt. Die Werte der zusätzlichen Bits szehen in Bezug zu den ursprünglichen Bits Beispiel aus der natürlichen Sprache “Ich studiere in Gießer” – Fehler kann erkannt und behoben werden “Ich liebe rich” – Fehler kann erkannt, aber nicht behoben werden

2.4.4 Hamming-Codierung: Beispiel ASCII Paritätsbit bei der 7-bit ASCII-Codierung wähle das 8te Bit so, dass immer eine gerade Anzahl von Bits gesetzt ist (gerade Anzahl = „even parity“, ungerade Anzahl = „odd parity“) Zeichen Binär mit even Parity @ 100 0000 1100 0000 A 100 0001 0100 0001 B 100 0010 0100 0010 C 100 0011 1100 0011 erhält man eine Nachricht mit ungerader Anzahl, so weiß man, dass (mindestens) ein Bit verkehrt ist. man weiß allerdings nicht welches man weiß auch nicht, ob nicht mehr als ein Bit verkehrt ist man weiß bei richtigem parity-Bit auch nicht, ob nicht mehr als 1 Bit verkehrt ist Idee: den „Abstand“ gültiger Worte so groß wie nötig wählen

2.4.4 Hamming-Codierung: Hamming-Distanz Definition: Der Hamming-Abstand (die Hamming-Distanz D) zwischen zwei Wörtern ist die Anzahl der Stellen, an denen sich zwei Worte gleicher Länge unterscheiden. Beispiel: Hamming-Abstand von 1100 0000 (A) und 0100 0001 (B) = 2 Definition: Der Hamming-Abstand (die Hamming-Distanz D) eines Codes ist der minimale Hamming-Abstand zwischen zwei beliebigen Wörtern des Codes. Beispiel: Hamming-Abstand von ASCII (mit even parity) = 2 Einige Konzequenzen: Codes mit Hamming-Distanz = 0 sind nicht eindeutig Bei Codes mit Hamming-Distanz = 1 kann das „Kippen“ eines Bits zu einem anderen gültigen Codewort führen (muss nicht) Bei Codes mit Hamming-Distanz = 2 kann ein Ein-Bit Fehler erkannt werden.

2.4.5 Hamming-Codierung: Fehlererkennung Fehler, bei denen höchstens D-1 Bits gestört sind, können sicher erkannt werden einige andere Fehler können, müssen aber nicht erkannt werden (genau dann, wenn die Hamming-Distanz zwischen zwei Wörtern eines Codes größer als die Distanz des Codes ist) Fehler werden erkannt, wenn ein Codewort ungültig ist gültiges Codewort erkennbares Codewort korrigierbares Codewort A B 1-Bit-Fehler 2-Bit-Fehler

2.4.5 Hamming-Codierung: Fehlerkorrektur Fehler, bei denen höchsten (D-1)/2 Bits gestört sind, können sicher korrigiert werden einige andere Fehler können, müssen aber nicht korrigiert werden können (genau dann, wenn die Hamming-Distanz zwischen zwei Wörtern eines Codes größer als die Distanz des Codes ist) Falsches Codewort wird em „nächstmöglichen“ Codewort (d.h. dem mit der minimalen Distanz) zugeordnet. gültiges Codewort erkennbares Codewort A B korrigierbares Codewort 1-Bit-Fehler 2-Bit-Fehler

2.4.5 Hamming-Codierung: Hamming Idee Jedes Prüfbit stellt die gerade Parität einer gewissen Menge von Bits (einschließlich sich selbst) sicher Jedes Datenbit kann in mehreren dieser Mengen einbezogen sein P D ... 1 8 Die Hamming-Methode Es werden an der 1,2,4,8,... Stelle Prüfbits eingeführt Jedes Prüfbit hat damit in seiner dualen Stellennummer genau eine Stelle mit einer 1 (1,2,4,8,... = 1,10,100,1000,...) Alle Stellen im Wort, die an derselben Stelle eine 1 haben (und an den anderen 1 oder 0) werden aufsummiert 1  001,011,101,111, ... also 1,3,5,7, ... Stellen 10  010,011,110,111, ... also 2,3,6,7, ... Stellen 100  100,101,110,111, ... also 4,5,6,7, ... Stellen Das entsprechende Parity-Bit wird als even-parity Bit gesetzt

2.4.5 Hamming-Codierung: Beispiel Hamming zu kodieren: 1011 Prüfbit 1 (001) relevant 011,101,111 also Bit 3,5,7 Summe = 3  Bit setzen Prüfbit 2 (010) relevant 011,110,111 also Bit 3,6,7 Summe = 2  Bit löschen Prüfbit 4 (100) relevant 101,110,111 also Bit 5,6,7 Summe = 2  Bit löschen kodiert: 1010101 1 P 7 1 P 1 P 1

2.4.5 Hamming-Codierung: Beispiel Hamming Fehlerhafter Code: 1000101 Verfahren prüfe alle Parity-Bits k = Summe der fehlerhaften Bitnummern k gibt die Nummer des gestörten Bits an (nur bei 1-Bit Fehler zuverlässig) Hier: Bit1 prüft 3,5,7: falsch Bit2 prüft 3,6,7: ok Bit4 prüft 5,6,7: falsch  k = 1 + 4 = 5  Bit5 muss getauscht werden 1 7

2.4.6 Genetische Codierung Beim Menschen ist die Desoxyribonukleinsäure (DNS, engl. DNA) der Träger der genetischen Information und Hauptbestandteil der Chromosomen. Die DNS ist ein kettenförmiges Polymer aus Nukleotiden, die sich in ihren Stickstoffbasen unterscheiden (Thymin/Cytosin bzw. Adenin/Guanin,) das Alphabet des Codes ist also: {Thymin, Cytosin, Adenin, Guanin,} oder auch { T, C, A, G } Je drei aufeinanderfolgende Basen bilden ein Wort Es gibt also 43 = 64 Kombination die Wortlänge ist also ld(64) Bit = 8 Bit Ein Gen enthält etwa 200 Worte Ein Chromosom enthält ca. 104 bis 105 Gene Die Anzahl der Chromosomen pro Zellkern ist beim Menschen 46 Die pro Zellkern gespeicherten Daten haben damit ein Volumen von 8 Bit * 200 * 105 * 46 = 73600 Bit * 105  104 MBit  1 GByte

2.4.6 Definition: Mittlere Wortlänge Codiert man die Zeichen eines Alphabetes binär (also mit Sequenzen eines 2-Zeichen-Alphabetes, z.B. 0 und 1) , so versteht man unter der mittleren Wortlänge L eines Codes die mit den Auftrittswahrscheinlichkeiten gewichtete Summe der Längen l(xi) der den einzelnen Symbole entsprechenden Codewörtern L = S p(xi) * l(xi) Beispiel 011100011 yxxzyx H = 1,5 Bit L = 1,5 Bit

2.4.6 Definition: Redundanz Die mittlere Wortlänge eines Binärcodes ist immer größer oder gleich dem mittleren Informationsgehalt. Die Differenz zwischen mittlerer Wortlänge und mittlerem Informationsgehalt wird als Redundanz R des Codes bezeichnet: R = L - H Die Redundanz bezogen auf die Wortlänge nennt man relative Redundanz r: r = R / L Redundanz ist also ein Maß für die Qualität einer Kodierung (insofern die Länge eines Codes als Qualität angesehen wird)

2.5.6 Redundanz – Beispiel Beispiel 011100011 yxxzyx H = 1,5 Bit L = 1,5 Bit H = 1,156 Bit L = 1,3 Bit H = S pi * hi = - S pi * ld(pi) = 0,360+0,464+0,332 = 1,156 L = S pi * li = 0,7+0,4+0,2 = 1,3 R = L - H = 1,3 - 1,156 = 0,144 r = R / L = 0,144 / 1,3 = 0,111

2.5 Zusammenfassung des Kapitels Was ist Information Definition nach Shannon Informationsgehalt eines Zeichens (x) h(x) = ld (1/p(x)) = - ld (p(x) einer Nachricht (n) h(n) = h(n1) + h(n2) + h(n3) + ... Mittlerer Informationsgehalt eines Zeichens (x) H(x) = S p(xi) * h(xi) einer Nachricht (n) |n| * H(x) Definition in der Informatik Bits und Bytes Codes mittlere Wortlänge L = S p(xi) * l(xi) Huffman Hamming Redundanz R = L - H Achtung: Nicht verwechseln !

Kapitel 3 Zeichen und Zahlen Auch wenn Objekte der realen Welt beliebig komplex in Zusammen-setzung uns Struktur sind, so werden sie in den meist auf zwei einfache Repräsentationen - als Abstraktion - abgebildet: Zeichen und Zahlen. Dieses Kapitel beschreibt, wie diese Objekte in eine für den Rechner verarbeitbare Form kodiert werden können. Inhalt Kodierung von Zeichen Darstellung von Zahlen

3.1 Kodierung von Zeichen Die Wurzeln der Informatik liegen in der Mathematik. Die ersten „Computer“ waren Rechner im wörtlichen Sinne, deren Aufgabe die Verarbeitung von Zahlen war. Mittlerweile hat sich der Aufgaben-schwerpunkt in Richtung „Elektronischer Datenverarbeitung“ ver-schoben, wobei als Datum immer weniger Zahlen im Mittelpunkt stehen, als vielmehr Texte. Dieses Unterkapitel beschreibt verschiedene Möglichkeiten die „Atome“ eines Textes, die Buchstaben, zu kodieren. Inhalt ASCII EBCDIC UNICODE

3.1.1 ASCII -Tabelle (7Bit) American Standard Code for Information Interchange

3.1.1 ASCII - Sonderzeichen Bedeutung der Sonderzeichen im ASCII-Code

3.1.2 EBCDIC - Tabelle Extended Binary Coded Decimals Interchange Code

3.1.2 EBCDIC - Sonderzeichen Die Bedeutung der Sonderzeichen

3.1.3 Unicode Aktuelle Version 4.0.0 (siehe auch www.unicode.org) Buchstaben und Symbole aus allen wichtigen geschriebenen Sprachen der Welt Amerika, Europa, Mittlerer Osten, Afrika, Indien, Asien, Pazifik Symbole Satzzeichen Sonderzeichen Wird genormt in ISO/IEC 10646 Kompatibilität mit ASCII 0000 - 007F: identisch mit 7-bit ASCII 007F - 00FF: Latin-1 Supplement (nationale Sonderbuchstaben) 2500 - 25FF: Blockgraphikzeichen (Box Drawing: ╘╚╞╬└┴├...)

3.1.3 Unicode: Beispiele 05F1 FA0E 2603 20AC xxD0 - xxDF Rejected 22.5.2001

3.2 Darstellung von Zahlen Die Darstellung von Zahlen spielt in der Informatik nach wie vor eine wichtige Rolle. Dabei gibt es unterschiedliche Mengen von Zahlen und auch unterschiedliche Operationen auf Zahlen. Dieses Unterkapitel beschreibt die Grundlagen der Zahlenkodierung, gibt für alle Mengen von Zahlen eine konkrete Kodierung an und führt in die Computerarithmetik ein. Inhalt Zahlensysteme Konvertierung Arithmetik Ganze positive Zahlen Ganze negative Zahlen Gebrochene Zahlen Gleitpunktzahlen Standards

3.2.1 Zahlensysteme Nicht systematische Zahlendarstellungen, z.B.: Strichliste: I, II, III, IIII, IIII, IIII I, ... römische Zahlen: MIM, IX, .... Systematische Zahlendarstellungen in einem Stellenwertsystem Jede Zahl N läßt sich als Sequenz von Zeichen a i darstellen Die Anzahl der notwendigen unterscheidbaren Zeichen ist B N = S a i * B i Im Dezimalsystem ist B = 10 und die unterscheidbaren Zeichen sind: 0,1,2,3,4,5,6,7,8,9 Im Binärsystem ist B = 2 und die unterscheidbaren Zeichen sind: 0,1

3.2.1 Zahlensysteme - Beispiele Dezimalsystem: 199910 = 1*103 + 9*102 + 9*101 + 9*100 Binärsysten: 199910 = 1*210+1*29+1*28+1*27+1*26+1*23+1*22+1*21+1*20 111110011112 Hexadezimalsystem (Sedezimalsystem) Zeichen: 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F 199910 = 7*162 + 11*161 + 15*160 = 7BF16 = 0x07BF = H‘07BF 4 Zeichen einer Binärzahl lassen sich durch eine Hexadezimal-ziffer darstellen (4 Binärziffern nennt man auch NIBBLE) Oktalsystem Zeichen: 0,1,2,3,4,5,6,7 199910 = 3*83 + 7*82 + 1*81 + 7*80 = 37178 3 Zeichen einer Binärzahl lassen sich durch eine Oktalziffer darstellen

3.2.2 Konvertierung: „Intuitivmethode“ Addition von geigneten Zweierpotenzen (Dezimalzahl  Dualzahl) positive Zweierpotenzen für Vorkommaanteil negative Zweierpotenzen für Nachkommaanteil Vorgehen (getrennt nach Vor- und Nachkommateil) Suche größte Zweierpotenz, die noch in die Zahl passt Subtrahiere die Zweipotenz von der Zahl daraus ergibt sich die neue Zahl für die Suche der Zweierpotenz Dieses Vorgehen terminiert ... ... beim Vorkommateil: wenn die Zahl = 0 ... beim Nachkommateil: wenn die Zahl erreicht ist, vielleicht nie Beispiel: 39 25 39 - 32 = 7 7 22 7 - 4 = 3 3 21 3 - 2 = 1 1 20 1 - 1 = 0 100111 0,8125 2-1 0,8125 - 0,5 = 0,3125 0,3125 2-2 0,3125 - 0,25 = 0,0625 0,0625 2-4 0,0625 - 0,0625 = 0 0,1101

3.2.2 Konvertierung: Restwertmethode Erzeugen des Hornerschemas (Ausklammern der Basis b) c0 = anbn + an-1bn-1 + ... + a2b2 +a1b1 + a0b0  c0 = (( ... (anb + an-1) b + ... + a2) b +a1) b + a0  c0 / b = c1 Rest a0 , mit c0= ( ... (anb + an-1) b + ... + a2) b +a1 , c1 / b = c2 Rest a1 , mit c1= ... (anb + an-1) b + ... + a2 , ... cn / b = 0 Rest an ( terminiert mit cn+1 = 0 ) Konversion der Nachkommastellen (folgt aus Hornerschema): Multiplikation mit Basis (bis ganzzahliges Ergebnis oder gewünschte Genauigkeit) Abspalten der Vorkommastelle des Ergebnisses, weiter mit 1. Beispiel 19 : 2 = 9 Rest 1 9 : 2 = 4 Rest 1 4 : 2 = 2 Rest 0 2 : 2 = 1 Rest 0 1 : 2 = 0 Rest 1 0,6875 * 2 = 1,375 1 abspalten 0,375 * 2 = 0,75 0 abspalten 0,75 * 2 = 1,5 1 abspalten 0,5 * 2 = 1 1 abspalten 10011 0,1011

3.2.2 Arithmetik Addition Subtraktion Multiplikation Division 0 + 0 = 0 0 + 1 = 1 1 + 0 = 1 1 + 1 = 0 Übertrag 1 0 - 0 = 0 0 - 1 = 1 Übertrag 1 1 - 0 = 1 1 - 1 = 0 0 * 0 = 0 0 * 1 = 0 1 * 0 = 0 1 * 1 = 1 1011 + 1110 1 1 1 Überträge 11001 1101 - 1010 1 Überträge 0011 1101 * 11 + 1101 1 1 Überträge 100111 100111 : 11 = 01101 100 -11 00

3.2.3 Ganze positive Zahlen Positive ganze Zahlen werden meist direkt in ihrer binären Darstellung kodiert. Die BCD (Binäry Coded Digits) - Darstellung von Zahlen ist eine Mischform aus Dezimal- und Binärdarstellung: Jede Ziffer der Dezimalzahl wird binär dargestellt. Die Darstellung jeder Ziffer erfolgt mit 4 Bits. Die Reihenfolge der Ziffern bleibt erhalten. Beispiele: 7 0111 53 0101 0011 1234 0001 0010 0011 0100 1999 0001 1001 1001 1001 0 0000 1 0001 2 0010 3 0011 4 0100 5 0101 6 0110 7 0111 8 1000 9 1001 1010 1011 1100 1101 1110 1111 Pseudotetraden

3.2.4 Ganze negative Zahlen: Probleme Darstellung des Vorzeichens im ersten Bit, z.B. 0000 = 0 1000 = 0 0001 = 1 1001 = -1 0010 = 2 1010 = -2 0011 = 3 1011 = -3 0100 = 4 1100 = -4 0101 = 5 1101 = -5 0110 = 6 1110 = -6 0111 = 7 1111 = -7 Nachteil durch Redundanz der Darstellung der 0 Nachteil durch Probleme beim formalen Addieren 1011 -3 + 0001 +1 1100 -4

3.2.4 Ganze negative Zahlen: Zweierkomplement Zweierkomplementdarstellung -2n ... +(2n-1) Negative Zahl durch bitweise Komplementierung und Addition von 1. 0000 = 0 1000 = -8 Beispiel: 3 0001 = 1 1001 = -7 0011 Binärdarstellung 0010 = 2 1010 = -6 1100 Komplement 0011 = 3 1011 = -5 1101 Komplement + 1 = -3 0100 = 4 1100 = -4 0101 = 5 1101 = -3 0110 = 6 1110 = -2 0111 = 7 1111 = -1 Vorteile Darstellung des Vorzeichens im ersten Bit Abdeckung von 16 Zahlen, also keine Redundanz Kein Nachteil durch Probleme beim formalen Addieren Subtraktion durch Addition des Zweierkomplements (Überlauf weglassen) -3 1101 -1 1111 +1 +0001 -1 +1111 -2 1110 -2 11110  1110 (Überlauf weggelassen)

3.2.5 Gebrochene Zahlen: Binärdarstellung Darstellung mit Vor- und Nachkommateil Beispiele Gebrochene Binärzahl Gebrochene Dezimalzahl 0.1 0,5 0.01 0,25 111.111 7,875 0.0001 1001 1001 1001 .... 0,1 Mit 32 Bit lassen sich nur 232 verschiedene Zahlen darstellen. Problem: extrem große und extrem kleine Zahlen lassen sich mit wenigen Bits nicht darstellen Bei 8 Bit mit 4 Vorkomma und 4 Nachkommastellen (ohne Vorzeichen): 0000.0001 < n < 1111.1111 0,0675 < n < 15,9425

3.2.5 Gebrochene Zahlen: Exponentialdarstellung Anforderung sehr große und sehr kleine Zahlen sollen darstellbar sein Masse Elektron = 9 * 10-28 g Anzahl Moleküle pro Mol = 6,022 * 1023 die relativen Genauigkeiten sind wichtiger als die absoluten Ältere Quellen geben die Anzahl der Moleküle pro Mol mit 6,065 * 1023 an Eine Änderung in der Mantisse von  0,04 entspricht einer Toleranz von 6,065 / 6,022  1,0071 also ca. 0,7%. Fixkommadarstellung wäre große Verschwendung zur Darstellung dieser beiden Größen wären 194 Bit nötig 87 Bit Vorkommateil 107 Bit Nachkommateil Idee: Signifikante Stellen und Größenordnung werden getrennt Signifikant Masse Elektron: 9 Größenordnung Masse Elektron: 10-28

3.2.5 Gleitpunktzahlen: Real Darstellung Darstellung durch Real-Zahlen, bestehend aus drei Teilen: Vorzeichenbit V Gibt an, ob die Zahl positiv oder negativ ist Mantisse M Wird mit dem Exponenten multipliziert Die Normalform wird erreicht, indem das Komma soweit nach links oder rechts geschoben wird, bis die erste Stelle nach dem Dezimalpunkt die erste von Null verschieden Ziffer ist. Der Exponent wird entsprechend der Verschiebungen erhöht oder vermindert. Exponent E Potenz einer Basiszahl (2) mit der die Mantisse multipliziert wird wird oft in „BIAS“-Darstellung abgelegt, d.h. wird mit 126 addiert um negatives Vorzeichen zu vermeiden. Vorsicht: 126 (nicht 128). Asymmetrisch, da 21 bei der Normalisierung zweimal geschoben wird, 2-1 gar nicht Vorsicht: Bei manchen Maschinen wird so normalisiert, dass die erste Stelle vor dem Komma gleich 1 wird, dann ist der BIAS 127

3.2.5 Gleitpunktzahlen: Umwandlung Umwandlung Dezimalzahl in binäre Gleitpunktzahl (nach IEEE 754) Umwandlung der Dezimalzahl in Binärzahl mit Nachkommateil Verschieben des Kommas nach links oder rechts bis zur Normalform Damit ist erste Nachkommastelle = 1 und daher redundant, kann also in der Mantisse weggelassen werden. 2 * größere Genauigkeit der Mantisse Addition des BIAS =126 (um negative Exponenten zu vermeiden) Umwandlung in binäre Form Das Vorzeichen der Mantisse wird bestimmt: positiv 0, negativ 1 IEEE 754 sieht noch eine optionale Rundung der Mantisse vor Nicht jede gebrochene Dezimalzahl lässt sich endlich als gebrochene Binärzahl darstellen (und umgekehrt). Dadurch entstehen Rundungsfehler

3.2.5 Gleitpunktzahlen: Beispiele Konvertieren: 10010100,101 Normalisieren: 10010100,101 = 0,10010100101*2+8 Exponent ist 8. M = 0010100101 (die führende 1 ist in Normalform redundant) Bias addieren E = 12610 + 810 = 13410 = 100001102 Vorzeichen V = 0 Ergebnis: VEEEEEEEEMMMMMMMMMMMMMMMMMMMMMMM 01000011000101001010000000000000 Beispiel: -2,7510 Konvertieren: 10,11 Normalisieren: 10,11 = 0,1011*2+2 Exponent ist 2. M = 011 (die führende 1 ist in Normalform redundant) Bias addieren E = 12610 + 210 = 12810 = 100000002 Vorzeichen V = 1 Ergebnis: VEEEEEEEEMMMMMMMMMMMMMMMMMMMMMMM 11000000001100000000000000000000

3.2.5 Gleitpunktzahlen: Arithmetik Addition/Subtraktion Die Exponenten werden angeglichen, indem die Mantisse des Operanten mit dem kleineren Absolutbetrag entsprechend verschoben wird. Anschließend werden die Mantissen addiert Beim Verschieben können Stellen verloren gehen. Multiplikation Die Mantissen der Operanten werden multipliziert Die Exponenten werden addiert Sind die Exponenten zu groß, kann es zu Exponenten-Overflow kommen Division Die Mantissen der Operanten werden dividiert Der Exponent ergibt sich aus der Differenz des Dividenden und Divisors Ist der Divisor zu klein und/oder der Dividend zu groß kann es zu einem Exponenten-Underflow kommen. Das Ergebnis wird dann zu 0, alle Ziffern sind verloren Nach allen Operationen wird die Normalform ggf. wiederhergestellt

3.2.6 Standards Short -128 ... 127 (8Bit) Integer -32768 ... 32767 (16Bit) Unsigned Int 0 ...65535 (16Bit) LongInt -2147483648 ... 2147483647 (32Bit) Real nach IEEE 754 Float 1 VZ-Bit, 8 Bit E, 23 Bit M (32Bit) Double 1 VZ-Bit, 11 Bit E, 52 Bit M (64Bit) zwei Varianten 0,5 M < 1 bzw. 1 M < 2 Number sign exponent mantissa normalized number 0/1 01 to FE any value denormalized number 0/1 00 any value zero 0/1 00 0 infinity 0/1 FF 0 NaN 0/1 FF any value but 00

3.2.6 Standards: Beispiel (Delphi) In Borlands Delphi (Pascal) sind folgende Typen festgelegt: Typ Bereich Signifikant Größe Real48 2,9 x 10^-39 1,7 x 10^38 11-12 6 Single 1,5 x 10^-45 3,4 x 10^38 7-8 4 Double 5,0 x 10^-324 1,7 x 10^308 15-16 8 Extended 3,6 x 10^-4951 1,1 x 10^4932 19-20 10 Comp -2^63+1 2*63-1 19-20 8 Currency -922337203685477.5808 19-20 8 +922337203685477.5808 Der generische Typ Real ist in der aktuellen Implementierung mit dem Typ Double identisch.

3.3 Zusammenfassung des Kapitels Kodierung von Zeichen ASCII EBCDIC UNICODE Darstellung von Zahlen Zahlensysteme Konvertierung Arithmetik Ganze positive Zahlen Ganze negative Zahlen Gebrochene Zahlen Gleitpunktzahlen Standards

Kapitel 4 Datenstrukturen Information aus der realen Welt werden in einem informationsver-arbeitenden System als Daten abgelegt. Diese stellen also eine (vereinfachte) Abstraktion der Wirklichkeit dar und spiegeln in vielen Fällen die Strukturen der Wirklichkeit wider. In diesem Kapitel wird ein Überblick über die wichtigsten abstrakten Datenstrukturen gegeben, wobei dieser Begriff zum Begriff des „Datentyps“ erweitert wird. Inhalt Datenstrukturen - Datentypen Datentypen: Ein Überblick Konkrete Datentypen Abstrakte Datentypen

4.1 Datenstrukturen - Datentypen In der Literatur wird meist der Begriff „Datenstruktur“ verwendet. In diesem Unterkapitel soll der Unterschied ziwschen diesem Begriff und dem Begriff des „Datentyps“ erläutert werden. Inhalt Datenstrukturen Datentypen Variablen eines Datentyps

4.1.1 Datenstrukturen In der Informatik werden Objekte der realen oder abstrakten Welt erfasst Bei der Erfassung beschränkt man sich möglichst auf die für den weiteren Transport / Speicherung/Verarbeitung/Umsetzung notwendige Information Zur internen Repräsentation werden diese Objekte abstrahiert Zur Abstraktion gehört die Erkennung von Strukturen - im Sinne einer Aggregation. Also Aus welchen Teilobjekten bestehen Objekte ? In welchem Verhältnis stehen die Teilobjekte zueinander ? Welches sind die „atomaren“ Teilobjekte ? Anschließend werden diese Objekte typisiert. Typisierung ist die Einteilung von abstrakten internen Objekten in Gruppen mit gleichen oder ähnlichen Eigenschaften.

4.1.2 Datentypen Typen sind also nicht die intern repräsentierten Objekte, sondern beschreiben die Eigenschaft einer Gruppe von Objekten. Zu diesen Eigenschaften gehören: Struktur Wertebereich anwendbare Operatoren, Funktionen, Relationen Beziehungen zu anderen Typen interne Repräsentationsweise … Beispiel: Imaginäre Zahlen Einige Anmerkungen:: Der Begriff „Datentyp“ ist weitergehend als der Begriff „Datenstruktur“ In der Objektorientierten Programmierung wird statt „Datentyp“ auch der Begriff „Klasse“ verwendet (Klassen beschreiben mehr Eigenschaften) Konkrete Repräsentanten eines Datentyps werden (u.a) „Variable“ oder - bei oo-Sprachen - „Instanz“ genannt

4.1.3 Variable eines Datentyps Einen speziellen Repräsentanten eines Datentyps bezeichnet man als Variable. Die Festlegung, von welchem Datentyp eine Variable ist, bezeichnet man als Variablendeklaration. Die Zuordnung eines Typs „Typ“ an eine Variable X wird (zunächst) wie folgt notiert: X : Typ; Eine Variable hat alle Eigenschaften eines Datentyps. Zusätzlich dazu hat eine Variable: einen konkreten Wert. Der Wert muss aus dem Wertebereich des Datentyps sein (oder undefiniert) Die Zuweisung eines Wertes „Wert“ an eine Variable X sei (zunächst) wie folgt notiert: X = Wert; einen konkreten Speicherplatz Dieser Speicherplatz ist so dimensioniert, dass die Struktur der Variable abgebildet werden kann Dieser Speicherplatz wird (meist) implizit durch die Deklaration zugeordnet Beispiel: x : Datentyp; // x ist vom Typ: „Datentyp“ X = 531; // Zuweisung von 531 an X

4.2 Datentypen: Überblick Nachdem sich nun der Begriff des „Datentyps“ als Oberbegriff der „Datenstruktur“ erwiesen hat, konzentrieren wir uns im Rest des Kapitels auf wichtige Datentypen. In diesem Unterkapitel wird ein Klassifikationssystem für die in der Informatik verwendeten Datentypen aufgestellt und kurz erläutert Inhalt Klassifikation der Datentypen Erläuterung der Klassifikation

4.2.1 Klassifikation der Datentypen Konkrete Abstrakte Idealisierte Einfache Pointer(Zeiger) Strukturierte Ordinale Real (Fließkomma) Array (Feld) Record (Verbund) Union (Variantenverb.) ... Boolean (Wahrheitswert) Integer (Ganzzahl) Char (Zeichen) Enumeration (Aufzählung)

4.2.2 Erläuterung der Klassifikation Idealisierte Datentypen aus der Mathematik bekannte Datentypen: R, N, Z, ... Variablen dieser Typen sind oft nicht endlich darstellbar (Bsp: 2) In einem Computer-Algebra-System symbolisch darstellbar (Bsp: 2^( 1/2)) Konkrete Datentypen in einem Rechner von Hard- oder Software bereitgestellte Datentypen entweder vordefiniert oder durch den Benutzer definierbar Abstrakte Datentypen verbergen ihren inneren Aufbau vor dem Benutzer bestehen aus beliebigen Strukturen über konkrete/idealisierte Datentypen, sowie aus Zugriffsfunktionen bzw. Prozeduren Beispiel: Baum 2 12 15 79 6 61 13 insert (Element) delete (Element) search (Element)

4.3 Konkrete Datentypen Die am häufigsten abstrahierten Objekte der realen Welt sind, zumindest was die für eine weitere Verarbeitung notwendigen Informationen betrifft, einfach strukturiert und lassen sich demnach mit konkreten Datentypen abbilden. Dieses Unterkapitel gibt einen Überblick über alle konkreten Datentypen und beschreibt diese. Inhalt Einfache Datentypen Strukturierte Datentypen Verweise Abstrakte Datentypen

4.3.1 Einfache: boolean (Wahrheitswert) zur Darstellung von Wahrheitswerten Wertebereich: true, false intern in manchen Programmiersprachen als 1 bzw 0 dargestellt Operatoren: und, oder, nicht, Vergleiche, ... Operatoren entsprechend der bool‘schen Algebra oft auch allgemeine arithmentische Operationen möglich Vorsicht vor Integer-Arithmetik mit boolean-Variablen Notation: booleanVar : boolean; Beispiel: switch : boolean; switch = false; // = 0 switch = not(switch); // = not(0) = 1 switch = switch and not(switch); // = 1 and 0 = 0 switch = switch or not (switch); // = 0 or 1 = 1

4.3.1 Einfache: integer (Ganzzahl) zur Darstellung ganzer Zahlen mit oder ohne Vorzeichen Wertebereich: Unterschiedlich unsigned integer: Ganze Zahlen ohne Vorzeichen ( 0... 65535 ) oft 16 bit bzw. 32 bit als shortInt bzw. longint bezeichnet Vorsicht: 16 bit Integer ist verdammt wenig ((± 32267) Speicherplatz ist nicht mehr teuer  benutzen Sie longInt (Ausnahmen bestätigen die Regel) Operatoren: Grundrechenarten, Vergleiche Operatoren entsprechend der „klassischen“ Algebra Notation: integerVar : integer; Beispiel: i : integer; i = 1; // = 1 i = i + 32;´ // = 1 + 32 = 33 i = i / 17; // = 33 / 17 = 1 ! i = i + 65535; // bei unsigned Int.: Fehler !

4.3.1 Einfache: char (Zeichen) zur Darstellung von Zeichen Vorsicht: Typischerweise wird die ASCII-Codierung zugrundegelegt, kann aber auch Unicode sein Wertebereich: Alle Zeichen Intern codiert als ASCII oder - neuerdings immer öfter - als Unicode ASCII: 8 Bit (7 benutzt), Unicode: 16 Bit Intern oft als integer repräsentiert Operationen: Vergleich oft auch allgemeine arithmentische Operationen möglich Vorsicht vor Integer-Arithmetik mit boolean-Variablen Notation: charVar : char; Beispiel: symbol : char; symbol = „A“; // = „A“ symbol = symbol + 32;´ // = „A“ + 32 = „a“ symbol = symbol - 128; // = „a“ - 128 = Fehler

4.3.1 Einfache: enum (Aufzählung) zur Darstellung endlicher benutzerdefinierter Wertebereich Es ist guter Stil, Mengen mit (garantiert) kleiner Mächtigkeit (<10) als enum-Type zu deklarieren, anstatt sie z.B. als Integer zu kodieren. Intern werden enum-Werte oft als integer abgelegt Operatoren: Vergleich oft auch allgemeine arithmentische Operationen möglich Vorsicht vor Integer-Arithmetik mit enum-Variablen Notation: enumVar : enum { Wertemenge }; Beispiel: ampelfarbe : enum {gruen,gelb,rot} ; ampelfarbe = gruen; // = gruen ampelfarbe = ampelfarbe +1 ; ´ // = gruen + 1 = gelb ampelfarbe = ampelfarbe +1 ; ´ // = gelb + 1 = rot ampelfarbe = ampelfarbe +1 ; ´ // = rot + 1 = Fehler !

4.3.1 Einfache: real (Fließkomma) zur näherungsweisen Darstellung reeller Zahlen Wertebereich: Unterschiedliche Genauigkeiten und Wertebereiche Wertebereich entspricht typischerweise der IEEE 754 Norm, also: Float: 32 bit Double: 64 bit Operationen: Grundrechenarten, erweiterte Arithmetik, Vergleich Notation: realVar : real; Beispiel: //--- Variable-declaration -------------------------- pi, flaeche, radius : real; // all real ! //--- Initialisation -------------------------------- pi = 3,141; // needs not to be more accurate radius = 5; // might be changed by user //--- Computation of surface ------------------------ flaeche = 2 * pi * (radius ^ 2); // common formula

4.3.2 Strukturierte: Array (Feld) Arrays sind eine Aggregationen von Daten des gleichen Typs (des „Basistyps“) Die Grenzen des Arrays sind (meist) statisch bestimmt Operation: Auswahl Die Auswahl eines Datenelemtes über erfolgt über einen ganzzahligen Index über den (Auswahl-)Operator „ [ ] “ Vorsicht: Zugriff außerhalb des deklarierten Bereiches führt zu Fehlern Notation: ArrayVar : array[min .. max] of Datentyp Beispiele Eindimensionales array: Vektor : array[1..4] of real; Zweidimensionales array: Matrix : array[1..3] of array[1..2] of real; Operator m : array[1..3] of array[1..2] of real; v : array[1..4] of real; v[3] = 5,03; v[4] = 4,12; m[1][2] = v[3] * 12 - v[4];

4.3.2 Strukturierte: Record (Verbund) Verbunde sind Aggregationen von Daten möglicherweise unter-schiedlichen Typs manchmals auch „structure“ oder „struct“ genannt Operation: Auswahl Die Auswahl erfolgt durch Angabe den des Komponentennamens (durch einen Punkt vom Variablennamen getrennt) Notation: recordVar : record { komponent1 : type1; ... }; Beispiel: d : record { tag : Integer; monat : Integer; }; d.monat = 10; d.tag = 20;

4.3.2 Strukturierte: Variant Record (Variantenverb.) Verbunde, deren Struktur mögliche Alternativen zulassen manchmals auch „union“ genannt lassen „Varianten“ eines Record-Types zu Operation: Auswahl (wie bei records über Punkt-Operator) Notation: varrecVar : record { komponent1 : type_1; ...; TAGGED TYPE case variant (variant1,...) of { (implizit) variant1 : type_n; ... } } Unterelement „variant“ implizit definiert bei „tagged type“ Nur ein Unterelement aus variant1, ... (sinnvoll) verwendbar Beispiel: adam,eva : record { name : array [1..20] of char; adam.sex = m; case sex (m,f) of { adam.muscle = 20,5; f: {IQ: integer}; eva.sex = f; m: {muscle: real}; // in cm eva.IQ = 132; }

4.3.2 Strukturierte: Variant Record adam,eva : record { name : array [1..20] of char; adam.sex = m; case sex (m,f) of { adam.muscle = 20,5; f: {IQ: integer}; eva.sex = f; m: {muscle: real}; // in cm eva.IQ = 132; } Umsetzung: name sex IQ / muscle Variant Records mit „Untagged Types“ (z.B. C, C++ : Union) (2. Variante) struct { char[20] name; enum {m,f} sex; adam.sex = m; union { adam.muscle = 20,5; int IQ; eva.sex = f; real muscle; // in cm eva.IQ = 132; } adam, eva;

4.3.3 Verweis: Pointer (Zeiger) Mit einfacher Datentypen und mit den konkreten Datentypen „Liste“ und „Verbund“ lassen sich nur statische Struktur aufbauen d.h. Strukturen, deren Speicherbedarf beliebig aber fest sind Bem.: Die Beliebigkeit ist begrenzt durch die Gesamtspeicherkapazität Mit Zeiger-Datentypen lassen sich Strukturen aufbauen, die sich dynamisch auf- und abbbauen lassen d.h. Strujturen, deren Speicherbedarf sich dynamisch verändern kann Bem.: Auch hier ist die Beliebigkeit begrenzt durch die Gesamtspeicher-kapazität Beispiel: knoten : record { symbol : char; links : Verweis; rechts : Verweis; } B C E D A Huffman (Bsp. aus Kap.2)

4.3.4 Vereinfachung der Notation („typedef“) Person : record { surname : array [1..20] of char; forename : array [1..20] of char; birthday : record { year: integer; month : enum {jan,...}; day : integer; }; }; Akt_Datum : record { year: integer; month : enum {jan,feb,...}; day : integer; }; In (fast) allen Programmiersprachen ist es möglich, beliebig strukturierte Datentypen neu zu bezeichnen und diese Typ-Bezeichner wie vordefinierte Typen zu verwenden: Notation: typedef NeuTyp : Typ; Beispiel: typedef Datum : record { year: integer; month : enum {jan,feb,...}; day : integer; }; Person: record { surname : array [1..20] of char; forename : array [1..20] of char; birthday : Datum }; Akt_Datum: Datum;

4.3.5 Beispiel: Kombination von Datentypen Um nun beliebig komplexe Strukturen der „realen“ Welt in einem Rechensystem abbilden zu können, kann man die vorgestellten Datentypen beliebig miteinander Kombinieren Beispiel.: typedef Person : record { surname : array [1..20] of char; forename : array [1..20] of char; birthday : record { year: integer; month : enum {jan,feb,...}; day : integer; }; next : Verweis; previous : Verweis; };

4.4 Abstrakte Datentypen Datenstrukturen Grundsätzlich lassen sich alle Objekte der realen Welt ausschließlich mit Hilfe einfacher Datentypen abbilden. Diese Abbildung ist aber meist „unnatürlich“, weil sie die Struktur realer Objekte nicht ausreichend berücksichtigt. Abhilfe schaffen hier strukturierte Datentypen, die allerdings grundsätzlich nur endliche Objektmengen repräsentieren können. Hier schaffen Zeigertypen Abhilfe. Kann man nun mit diesen Mitteln Strukturen realer Objekt natürlich abbilden, so fehlen diesen Datentypen einige der Eigenschaften, die Datentypen von Datenstrukturen unterscheiden, dies sind insb. Operationen und Beziehungen zu anderen Typen. Einen vertieften Einblick in die bunte Welt abstrakter Datentypen bietet die Vorlesung des 2. Semesters Datenstrukturen

4.5 Zusammenfassung des Kapitels Datentypen Idealisierte Abstrakte Konkrete Einfache Strukturierte Pointer(Zeiger) Boolean (Wahrheitswert) Integer (Ganzzahl) Char (Zeichen) Enumeration (Aufzählung) Ordinale Real (Fließkomma) Array (Feld) Record (Verbund) Union (Variantenverb.) ... Wir sind damit auch an die Grenzen dessen gelangt, was in dieser Vorlesung über die „Statik“ von Objekten gesagt werden soll und wenden uns einem noch spannenderem Themenbereich zu ;-)

Kapitel 5 Algorithmenentwurf In den vorangegangenen Kapiteln wurde, aufbauend auf dem Begriff der Information, beschrieben, wie die statischen Objekte der Informatik aussehen und notiert werden können. In diesem Kapitel wird aufgezeigt, wie man die Verarbeitung dieser Objekte (also die Dynamik) beschreiben kann. Wesentlicher Begriff dabei ist der Begriff des Algorithmus Inhalt Ein Beispiel Definition Die Struktelemente Strukturierung Blockung Iteration und Rekursion Teile dieses Kapitels sind aus: R.Manthey: Vorlesung Informatik 1, Uni Bonn, 2001

5.1 Ein Beispiel Zunächst soll ein kleines Beispiel in eine mögliche Aufgabenstellung aus dem (bekannten) Bereich der Mathematik einführen und dadurch auch eine (eingeschränkte) Vorstellung über die Aufgaben und Elemente eines Algorithmuses geben. Inhalt Das Problem (Beispiel) Ein Algorithmus I Ein Algorithmus II Vergleich der Algorithmen Ein Algorithmus III Fragestellungen Ein weiterer Algorithmus

5.1.1 Das Problem x2 + 8x + 7 = 0 x2 + px + q = 0 x1,2= -p/2 p2/4 - q Eine quadratischen Gleichung: Allgemeine Darstellung der quadratischen Gleichung Allgemeine Lösung der quadratischen Gleichung Lösung der quadratischen Gleichung x2 + 8x + 7 = 0 x2 + px + q = 0 x1,2= -p/2 p2/4 - q + - x1,2 = -8/2 82/4 - 7 = -4 3 + - x1 = -1 x2 = -7

5.1.3 Ein Algorithmus I x1,2= -p/2 p2/4 - q - Ein Algorithmus + Eingaben Zuweisungen Berechnungen 1. Lies die Zahlen p und q ein 2. Berechne die Zahl w = p2/4 - q 3. Berechne die Zahl x1 = -p/2 + w 4. Berechne die Zahl x2 = -p/2 - w 5. Gib x1 und x2 als Ergebniss aus Konstante Ausgaben Variable

5.1.4 Ein Algorithmus II x1,2= -p/2 p2/4 - q - Ein zweiter Algorithmus x1,2= -p/2 p2/4 - q + - 1. Lies die Zahlen p und q ein 2. Berechne die Zahl p/2; Nenne diese Zahl a 3. Berechne die Zahl a2 ; Nenne diese Zahl b 4. Berechne die Zahl b-q ; Nenne diese Zahl c 5. Berechne die Zahl c ; Nenne diese Zahl d 6. Berechne die Zahl -a ; Nenne diese Zahl e 7. Berechne die Zahl e + d ; Nenne diese Zahl x1 8. Berechne die Zahl e - d ; Nenne diese Zahl x2 9. Gib x1 und x2 als Ergebniss aus FHSymbol1 Es gibt (oft unendlich) viele Algorithmen zur Lösung eines Problems

5.1.5 Vergleich der Algorithmen Berechne die Zahl w = p2/4 - q Berechne die Zahl x1 = -p/2 + w Berechne die Zahl x2 = -p/2 - w Berechne die Zahl p/2; Nenne diese Zahl a Berechne die Zahl a2 ; Nenne diese Zahl b Berechne die Zahl b-q ; Nenne diese Zahl c Berechne die Zahl c ; Nenne diese Zahl d Berechne die Zahl -a ; Nenne diese Zahl e Berechne die Zahl e + d ; Nenne diese Zahl x1 Berechne die Zahl e - d ; Nenne diese Zahl x2 A1 A2 Anzahl Berechnungen 10 7 Anzahl Zuweisungen 3 7 Anzahl Variablen 5 9 Welcher Algorithmus ist besser ? Warum ? FHSymbol1

5.1.6 Ein Algorithmus III Problem: Negatives Wurzelargument 5.b Wenn c negativ ist gehe zu Schritt 1 1. Lies die Zahlen p und q ein 2. Berechne die Zahl a = p/2 3. Berechne die Zahl b = a2 4. Berechne die Zahl c = b-q 5.a Wenn c negativ ist brich den Algorithmus ab Ansonsten mache mit nächstem Schritt weiter 6. Berechne die Zahl d = c 7. Berechne die Zahl e = -a 8. Berechne die Zahl x1 = e + d 1 9. Berechne die Zahl x2 = e - d 10. Gib x1 und x2 als Ergebniss aus Bedingte Ausführung Schleife

5.1.7 Fragestellungen Welche offenen Fragen bestehen noch ? Wer gibt p und q ein ? Wie wird p und q eingegeben ? Werden p und q in endlicher Zeit eingegeben ? Sind p und q im richtigen Format ? Ist Variable a im richtigen Format ? Gibt es die Quadrat-Funktion ? Ist c positiv ? Ist Variable e im richtigen Format ? Sind die restlichen Variablen im richtigen Format Reicht die Genauigkeit der Darstellung ? Wo wird das Ergebnis ausgegeben ? Ist ausreichend Variablenkapazität für den Algorithmus vorhanden ? Läuft der Algorithmus schnell genug ? ... 1. Lies die Zahlen p und q ein 2. Berechne die Zahl a = p/2 3. Berechne die Zahl b = a2 4. Berechne die Zahl c = b-q 6. Berechne die Zahl d = c 7. Berechne die Zahl e = -a 8. Berechne die Zahl x1 = e + d 1 9. Berechne die Zahl x2 = e - d 10. Gib x1 und x2 als Ergebniss aus Welche offenen Fragen bestehen noch ? FHSymbol1

5.1.8 Ein weiterer Algorithmus

5.2 Definition Der Begriff des Algorithmus ist zentral in der Informatik und soll in diesem Unterkapitel formal definiert werden Inhalt Herkunft Der Algorithmus Beispiel: Algorithmenbeweis Weitere Prinzipien Algorithmen und Programme Ausflug: Algorithmus und WinOSe

5.2.1 Herkunft Muhammad ibn Musa abu Djafar al-Choresmi (ca. 780-850 n.Chr) arabischer Mathematiker, geboren in Choresmien (heute: Usbekistan) lebte und wirkte in Bagdad im „Haus der Weisheit“ war beteiligt an der Übersetzung der Werke griechischer Mathematiker ins Arabische schrieb ein „Kurzgefasstes Lehrbuch für die Berechnung durch Vergleich und Reduktion“ die lateinische Übersetzung dieses Buches („liber algorismi“) kam durch Kreuzfahrer nach Europa verfasste auch ein Buch mit dem Titel „Al-Mukhtasar fi Hisab al-Jahr va l-Muqabala“ Algorithmus Algebra

Erwarten Sie nie, dass ein Computer für Sie mitdenkt 5.2.2 Der Algorithmus Definition: Ein Algorithmus (algorithm) ist die Beschreibung eines Verfahrens, um aus gewissen Eingabegrößen bestimmte Ausgabegrößen zu berechnen. Dabei müssen folgende Bedingungen erfüllt sein Spezifikation Durchführbarkeit Korrektheit Verfahren ohne Verständnis des Problemes FHSymbol1 Erwarten Sie nie, dass ein Computer für Sie mitdenkt

5.2.2 Der Algorithmus : Spezifikation Eingabespezifikation: Es muss genau spezifiziert sein, welche Eingabegrößen erforderlich sind und welchen Anforderungen diese Größen genügen müssen, damit das Verfahren funktioniert EINGABE Algorithmus Ausgabespezifikation Es muss genau spezifiziert sein, welche Ausgabegrößen (Resultate) mit welchen Eigenschaften berechnet werden

5.2.2 Der Algorithmus : Durchführbarkeit Endliche Beschreibung das Verfahren muss in einem endlichen Text vollständig beschrieben sein Effektivität Jeder Schritt des Verfahrens muss effektiv (d.h. tatsächlich) „mechanisch“ ausführbar sein Bem.: „Effektivität“ ist nicht zu verwechseln mit „Effizienz“ („Wirtschaftlichkeit“) Determiniertheit Der Verfahrensablauf ist zu jedem Zeitpunkt fest vorgeschrieben

5.2.2 Der Algorithmus : Korrektheit partielle Korrektheit Jedes berechnete Ergebnis genügt der Ausgabespezifikation, sofern die Eingaben der Eingabespezifikation genügt haben Terminierung Der Algorithmus hält nach endlich vielen Schritten mit einem Ergebnis an, sofern die Eingaben der Eingabespezifikation genügt haben

5.2.2 Der Algorithmus : Zusammenfassung Definition Ein Algorithmus (algorithm) ist die Beschreibung eines Verfahrens, um aus gewissen Eingabegrößen bestimmte Ausgabegrößen zu berechnen, der gekennzeichnet ist durch: Spezifikation der Ein- und Ausgabegrößen eine endliche Beschreibung des Verfahrens effektive Ausführbarkeit der Verfahrensschritte Determiniertheit der Verfahrensschritte partielle Korrektheit Terminiertheit Bemerkung: Algorithmen, die eine oder mehrere dieser Eigenschaften nicht besitzen werden dann als Nicht-<Eigenschaft> Algorithmen bezeichnet. Bsp: Nicht-Deterministische Algorithmen.

5.2.3 Beispiel: Algorithmenbeweis In gängiger mathematischer Notation könnte ein Verfahren zur Berechnung der Modulus-Funktion a mod b wie folgt aussehen:  a falls a < b mod(a,b) =   mod(a-b,b) falls a  b Um festzustellen, ob diese Berechnungsvorschrift einen Algorithmus im Sinne der Definition darstellt, müssen folgende Punkte beachten werden: Spezifikation Eingabe Ausgabe Durchführbarkeit Endliche Beschreibung Effektivität Determiniertheit Korrektheit Partielle Korrektheit Terminierung

5.2.3 Beispiel: Spezifikation Lassen sich die möglichen Ein- und Ausgabewerte genau spezifizieren ?

5.2.3 Beispiel: Durchführbarkeit Ist der Algorithmus durchführbar ?

5.2.3 Beispiel: Korrektheit (partielle) Ist der Algorithmus korrekt (im Sinne der Spezifikation)

5.2.3 Beispiel: Korrektheit (Terminierung) Terminiert der Algorithmus ? Bemerkung: Es gibt kein Verfahren, das zu einem beliebigen Algorithmus angibt, ob er terminiert oder nicht („Halte-Problem“)

5.2.3 Weitere Prinzipien Neben den in der Definition angegebenen Eigenschaften gibt es weitere wichtige Prinzipien, die bei der Erstellung eines Algorithmuses zu beachten sind: Effizienz Der Algorithmus soll möglichst wenig Aufwand verursachen Das Ergebnis mit möglichst wenig Rechenschritten (oder mit möglichst wenig Speicherbedarf) erzielen Korrektheit beweisbar? Ein nicht-korrekter Algorithmus ist nach unserer Definition kein Algorithmus! Trotzdem sind nicht-korrekte Verfahren eher die Regel als die Ausnahme

5.2.4 Algorithmen und Programme: Der Weg Problem Algorithmus Programm Spezifizieren Verifizieren Testen Algorithmierung Programmierung gegeben: das Problem durch Spezifizieren wird das Problem formal beschrieben Durch Algorithmierung (Algorithmenentwurf) wird ein Algorithmus erzeugt durch Verifizieren kann der Algorithmus auf Übereinstimmung mit der Spezifikation überprüft werden Durch Programmieren wird aus den Algorithmus ein Programm erzeugt durch Testen kann das Programm auf Übereinstimmung mit der Spezifikation und dem Algorithmus überprüft werden.

5.2.4 Algorithmen und Programme: Beziehungen Algorithmus Programm Programmierung Problem Algorithmierung Programmieren setzt Algorithmenentwicklung voraus Kein Programm ohne Algorithmus ! Jedes Programm repräsentiert einen bestimmten Algorithmus. Ein Algorithmus kann durch viele Programme repräsentiert werden. Problem Algorithmus1 Algorithmus2 Programm21 Programm22 ...

5.2.5 Ausflug: Algorithmus und WinOSe Klassische Programmierung Windows Programmierung Eventqueue OS Algorithmus OS

5.3 Strukturelemente Um die Dynamik - also die Abfolge von Aktionen - eines Algorithmu-ses zu beschreiben, benötigt man formale Beschreibungsmittel, sowie eine Festlegung, wie diese Beschreibungmittel zu notieren und zu interpretieren sind. Dieses Unterkapitel stellt die formalen Beschreibungsmittel für Algorithmen vor. Diese Beschreibungsmittel sind dabei gleichzeitig Strukturierungselemente für Algorithmen, denn sie definieren die Struktur von Algorithmen. Inhalt: Die Elemente Folge Auswahl Wiederholung

5.3.1 Die Elemente: Aus dem Beispiel EINGABE Zuweisungen Berechnungen Mathematische Grundoperationen komplexe Funktionen ... Bedingte Ausführungen Schleife Variable Texte Zahlen ... Konstanten (Literale) AUSGABE

5.3.1 Die Elemente: Notation Für die Beschreibung von Algorithmen gibt es viele Möglichkeiten Alltagssprache Konkrete Programmiersprache Dazwischen gibt es eine Vielzahl von Notationen, die den Übergang zwischen Problembeschreibung und Programm erleichtern sollen Eine mögliche - eindimensionale - Notation ist Pseudocode: // Dies ist eine Zuweisung x = 42; Kommentare werden (hier) mit vorangestellten Slashes „//“ gekennzeichnet Aktionen werden (hier) mit Semikolon „;“ getrennt Visualisierung durch graphische - zweidimensionale -Notation Flussdiagramme Struktogramme (=Nasi-Schneidermann-Diagramme) Aktion

5.3.1 Die Elemente: atomare Elemente Anweisungen sind die atomaren Elemente eines Algorithmus‘, die Elemente also, aus denen ein Algorithmus aufgebaut ist. Es gibt (zunächst) drei Arten dieser „atomaren“ Elemente Zuweisung: Pseudocode X = y; Auf der linken Seite der Zuweisung steht eine Variable auf der rechten Seite der Zuweisung steht entweder eine Variable, ein Literal oder eine Berechnung aus Varaibelen und Literalen Eingabe Pseudocode: x << <Eingabegerät> ; Als Eingabegerät kann ein geeignetes physikalisches Gerät (Tastatur, Schnittstelle, ...) angegeben werden. Ausgabe Pseudocode: x >> <Ausgabegerät> ; Als Ausgabegerät kann ein geeignetes physikalisches Gerät (Bildschirm, Drucker, Schnittstelle, ...) angegeben werden Ein- und Ausgabe können auch als Zuweisung verstanden werden.

5.3.1 Die Elemente: Kontrollelemente Die atomaren Elemente eines Algorithmuses können durch drei einfache Strukturierungsmethoden, den „Kontrollelementen“, zueinander in Beziehung gesetzt werden: 1. Folge (Sequenz) 2. Auswahl (Selektion, Fallunterscheidung) 3. Wiederholung (Iteration, Schleife) Die Kontrollelemente bestimmen die Reihenfolge von Aktionen in Algorithmen Eine Aktion (Ai) - auch Verarbeitung genannt - ist ein atomares Element oder eine durch die Strukturmethoden zusammengefasste Menge mehrerer Aktionen

5.3.2 Folge Folgen bestimmen die lineare Reihenfolge von Aktionen in Algorithmen: Flussdiagramm Struktogramm Pseudocode: A1 A1 { A1; A2; ... An; } A2 . A2 An . An

5.3.3 Auswahl : bedingte Verarbeitung Eine Aktion wird, in Abhängigkeit einer bool‘schen Bedingung ausgeführt oder nicht auch „einarmiges if“ genannt. Flussdiagramm Struktogramm Pseudocode: f B B if B then A1; w f w A1 A1 Beispiel: if (x<0) then x = -x;

5.3.3 Auswahl : einfache Alternative In Abhängigkeit einer bool‘schen Bedingung wird entweder eine Aktion oder eine andere Aktion ausgeführt auch „zweiarmiges if“ genannt. Flussdiagramm Struktogramm Pseudocode w f B B if B then A1 else A2; w f A1 A2 A1 A2 Beispiel: if (x<0) then x:=-x else x=0;

5.3.3 Auswahl : mehrfache Alternative In Abhängigkeit einer Bedingung (mit mehreren möglichen Werten w1, w2, ..., wn) wird eine Aktion aus einer Menge möglicher Aktionen ausgewählt und ausgeführt Flussdiagramm Struktogramm Pseudocode B w1 B switch B: { case w1: A1; case w2: A2; ... case wn: An; } wn w1 w2 wn A1 A2 An A1 A2 An Beispiel: switch x: { case 0: x = x/2; case 1: x = x+1; } Oft auch mit „else“-Alternative (statt wn)

5.3.4 Schleife: mit vorausgehender Prüfung Solange eine bool‘sche Bedingung erfüllt ist, wird eine Aktion ausgeführt. Die Bedingung wird vor der ersten Ausführung der Aktion geprüft heißt auch: abweisende Schleife (While-Schleife) Flussdiagramm Struktogramm Pseudocode f while B { A1 } B B A1 w A1 Beispiel: while x < 100 { x = x + 1; }

5.3.4 Schleife: mit nachfolgender Prüfung Solange eine bool‘sche Bedingung erfüllt ist, wird eine Aktion ausgeführt. Die Bedingung wird (erst) nach der ersten Ausführung der Aktion geprüft heißt auch: Do-While-Schleife Manchmal auch als Variante „Repeat-Schleife“ - z.B. in Pascal - aber: Die „repeat-Schleife“ wird solange ausgeführt bis eine bool‘sche Bedingung erfüllt ist. Flussdiagramm Struktogramm Pseudocode do { A1 } while B A1 B A1 f B w Beispiel: do { x = x + 1; } while x <= 100

5.3.4 Schleife: Beispiel (abweisende Schleife) Untersuche ob eine gegebene natürliche Zahl Primzahl ist. p > 2 ist Primzahl, falls sie durch kein t mit 1<t<p teilbar ist (p mod t  0) Idee: wenn p Primzahl, dann ist p ungerade es genügt, nur ungerade t zu untersuchen es genügt, nur solche t zu untersuchen die kleiner p sind, Algorithmus: p << Tastatur; if ((p>2) and (p mod 2 != 0)) then { t = 3; // initialize t while ((t*t<p) and (p mod t != 0)) { t = t + 2; } // nach Schleife ist t*t >=p oder p mod t == 0 if (t*t>p) then „p ist Primzahl“ >> Bildschirm; else „p ist keine Primzahl“ >> Bildschirm; } else { „p <= 2 oder p gerade“ >> Bildschirm; } // Primzahl ?

5.3.4 Schleife: Beispiel (Vergleich while  do-while) Sind diese Schleifen im Ergebnis identisch ? while x < 100 do { { x = x + 1; x = x + 1; } } while x < 100 und jetzt ? if (x < 100) then { do { x = x + 1; } while x < 100 } Welche Lösung ist eleganter ? aber: oft wird eine erstmalige Aktion benötigt, um ein Datum überhaupt überprüfen zu können.

5.3.4 Schleife: Beispiel (Vergleich do-while  while) Suchen eines Zeichens do { x << Datei; } while ( x != SearchChar && x != eof ) ... das Ganze als while-Schleife ? while ( x != SearchChar && x != eof ) { x << Datei; } Noch‘n Versuch: x << Datei; while ( x != SearchChar && x != eof ) { x << Datei; }

5.3.4 Schleife: Beispiel (Schleife mit Zählern) Sehr häufig werden Schleifen verwendet, deren Bedingung abhängig von Zählerwerten sind. Die Zählerwerte werden vor Eintritt in die Schleife initialisiert Die Bedingung prüft den Zählerwert Im Schleifenkörper wird der Zähler erhöht (increase) oder erniedrigt (decrease) Vorsicht mit: dem Zählertyp, dem Additionswert, der Bedingung Algorithmus: // --- Initialisierung ------------------------------ s = 0; i = 1; // Initialisierung des Schleifenzählers // --- Schleife (Berechnet Summe 1..n) ------------- while ( i <= n ) { s = s + i; i = i + 1; // Erhöhung des Schleifenzählers (oft um 1) }

5.2.4 Schleife: Die „For“-Schleife Da Schleifen mit Zähler sehr häufig auftreten, stellen viele Programmiersprachen ein eigenes sprachliches Mittel dafür zur Verfügung: Die „For“ Schleife Pseudocode: Beispiel: for var=start_value to end_value for i=1 to 10 { { A; x = x + i; } } Der Zähler (var) wird pro Schleifendurchlauf implizit um 1 erhöht (Bei manchen Sprachen - z.B. Basic, C, C++ - kann man dies ändern) Dieser Code ist äquivalent mit folgender Schleife: i = start_value while i <= end_value { A; i = i+1; }

5.3.4 Schleife: Beispiel (Endlosschleife) Manchmal macht es Sinn, Schleifen endlos laufen zu lassen: z.B. bei der zyklischen Abprüfung von Systemzuständen (Windows Event-Queue) manchmal macht das keinen Sinn - passiert aber trotzdem ;-) Flussdiagramm Struktogramm Pseudocode while true { A1 } B A1 A1 Beispiel: while true { „Druckerpapier ist teuer“ >> Drucker; }

5.4 Strukturierung Mit Hilfe atomarer Elemente und der Kontrollelemente lassen sich Algorithmen strukturieren. In diesem Kapitel sind einige Begriffe zur Strukturierung erläutert. Insbesondere wird ein weiteres - viertes - Kontrollelement vorgestellt (und auch gleich wieder verworfen) Inhalt Control Flow Strukturierung durch Sprung Strukturiert-iterative Beschreibungsform Strukturierungstypen

5.4.1 Control Flow Mithilfe der Kontrollelemente können die „atomaren“ Elemente (Anweisungen) strukturiert werden Die Anordnung der Anweisungen (als atomare Elemente) eines Algorithmus, die bestimmt, in welcher Reihenfolge Dinge geschehen, heißt control flow (Steuerungsverlauf, Kontrollfluss) des Algorithmus genannt Manchmal wird auch der Programmablauf oder Kontrollfaden (thread of control, thread), also die tatsächlich abgespulten Schritte und Anweisungen so bezeichnet

5.4.2 Strukturierung durch Sprung Bei der Vorstellung der Kontrollelemente wurde (aus hinterhältig, didaktischen) Gründen auf ein viertes Element verzichtet: Der Sprung („Goto“-Anweisung) Die Konstruktion „fahre fort mit Schritt x“ (goto x) stellt einen solchen Sprung (jump) im Steuerungsverlauf dar Zur Anwendung von goto werden Schritte mit einer Marke (Label) versehen, um das Ziel des Sprunges zu kennzeichnen Dies ist die elementarste Form, eine Wiederholung oder sonstige Verzweigung im Ablauf auszudrücken Dadurch erhalten wir die elementar-iterative Beschreibungsform von Algorithmen, die die Strukturierung mit ein-/mehrfacher Auswahl und Schleifen funktional abdeckt. Beispiel: while x<100 { 1: if x>100 goto 2 x = x+1 x = x+1; } goto 1; 2: ...

5.4.2 Strukturierung durch Sprung Anwendung von Sprüngen ist sehr gefährlich! Sprünge strukturieren komplexe Programm nicht ausreichend - der Steuerungsverlauf kann verworren und unübersichtlich sein Um den Steuerungsverlauf auch bei komplexen Algorithmen übersichtlich zu halten, schränkt man die Sprünge ein: Schleifen der Flussdiagramme sind höchstens ineinander geschachtelt Schleifen überkreuzen sich nicht! Bei gut strukturierten Algorithmen würde man z. B. nur wieder eine geschlossene Schleife oder einen (vorzeitigen) Sprung bedingt durch die Behandlung des Trivialfalls erlauben Wir sprechen in diesem Fall von strukturierten Sprüngen im Gegensatz zu freien Sprüngen, die prinzipiell beliebige Ziele haben können

5.4.3 Strukturiert-iterative Beschreibungsform Sprünge können die bestimmte „höhere“ Strukturierungsarten funktional abzubilden. Hier gilt auch der Umkehrschluss In der strukturiert-iterativen Beschreibungsform kommen Sprünge nur noch implizit bei der Ausführung höherer Iterationsstrukturen vor Dieses sind Fallunterscheidungen (Auswahl) wie if-then-else oder insbesondere Schleifenkonstrukte Diese bewirken, dass der Programmfluss In einer Auswahl zu genau einer Auswahl geht. in einer Schleife von einer Prüfung zu den Aktionen des Schleifenkörpers und wieder zurück zur Prüfung geht. Viele höhere Programmiersprachen (Pascal, C, C++) erlauben jedoch die Verwendung von Sprüngen Aus Optimierungsgründen (Nähe zur Maschinensprache) Aus Strukturierungsgründen)

5.4.4 Strukturierungstypen Beispiel: Schemen einiger Kontrollflüsse Strukturiert-iterativ Elementar-iterativ Spaghetti-Code

5.4.5 Strukturierung durch Blockung Idee: Eine Zusammenfassung von Aktionen bekommt einen Namen und kann durch das Nennen des Namens (Aufruf) aktiviert werden. In einen Block können Daten formal hinein und herausgelangen. Ein Block kann eigenen Daten besitzen. Vorteile: Gliederung des Algorithmus‘ durch hierarchische Dekomposition („Divide et impera: Teile und herrsche“) Wiederverwendbarkeit durch mehrfachen Aufruf statt durch mehrfaches notieren. universeller ( Anzahl muss nicht bekannt sein) fehlerunanfälliger Kapselung unwichtiger Details („information Hiding“) Vorteile bei der Organisation von Programmiertätigkeit durch Verteilbarkeit der Aufgaben.

5.5 Zusammenfassung des Kapitels Ein Beispiel Drei Algorithmen im Vergleich zur Lösung einer quadratischen Gleichung Definition des Algorithmenbegriffes Definition und dessen Anwendung im Beispiel. Weitere Prinzipien und der Zusammenhang von Algorithmen und Programmen. Strukturelemente: Die „atomaren“ Elemente und die Konstruktionselemente Folge, Auswahl, Wiederholung Strukturierung Der Begriff des Control Flows, das Problem der Strukturierung mit Sprung und Blockung

Kapitel 6 Algorithmentheorie Im vorangegangenen Kapitel wurde beschrieben, mit welchen Elementen Algorithmen aufgebaut werden, und was man dabei zu beachten hat. Dieses Kapitel geht nun darauf ein, ob ein Problem überhaupt algorithmisch fassbar ist, ob eine gefundener Algorithmus auch das tut was er soll und wieviel Zeit bzw. Platz er dafür benötigt. Inhalt Berechenbarkeit Korrektheit Komplexität Teile dieses Kapitels sind aus: R.Manthey: Vorlesung Informatik 1, Uni Bonn, 2001

6.1 Berechenbarkeit Wir haben den Begriff und die Elemente eines Algorithmus vorgestellt und Algorithmen zur Lösung von Problemen verwendet. In diesem Unterkapitel werden nun einige Fragen zur Anwendbar- und Sinnhaftigkeit von Algorithmen gestellt und beantwortet. Inhalt: Einige Fragen Das Entscheidungsproblem Die Turing-Maschine Berechenbarkeit Rekursive Funktionen Church‘sche These H. Ernst:“Grundlagen und Konzepte der Informatik“,Vieweg-Verlag,2000

6.1.1 Einige Fragen Kann jedes Problem durch einen Algorithmus beschrieben werden, d.h. prinzipiell - bei genügender Sorgfalt - gelöst werden ? Kann jeder Algorithmus in ein Programm übertragen werden ? Welchen Anforderungen muss eine Programmiersprache genügen, damit jeder Algorithmus damit formuliert werden kann ? Ist ein Computer grundsätzlich in der Lage, einen bekannten, als Programm formulierten Algorithmus auszuführen ? Ist ein solcher Computer formalisierbar ? Wie sieht ein solches abstraktes Model aus ? Gibt es genau ein Model oder mehrere ? Sind diese Modelle äquivalent ? Gibt es andere Modelle oder Beschreibungsformen, die diesem formalisierten Computermodell entsprechen ? Frage 1 und Frage 4 sind wesentlich für den Begriff der Berechenbarkeit, Frage 2 wird im anschließenden Kapitel behandelt, Frage 4 ist Gegenstand der Vorlesung „Compilerbau“

6.1.2 Das Entscheidungsproblem Bis weit ins 20ste Jahrhundert war die Mehrzahl der Mathematiker (insb. David Hilbert: 1862-1942) der Ansicht, dass man von jeder Aussage algorithmisch beweisen könne, ob sie wahr oder falsch sein. Anders ausgedrückt: Es sei entscheidbar, ob ein Problem lösbar oder unlösbar ist. Die Frage, ob dies entscheibar ist oder nicht ging als Entscheidungs-problem in die Geschichte der Mathematik (und Informatik) ein. Kurt Gödel wies in seinem Unvollständigkeits-Theorem 1931 nach, dass alle widerspruchsfreien axiomatischen Formulierungen der Zahlentheorie unentscheidbare Aussagen enthalten. damit wurde insb. belegt, dass streng algorithmisch arbeitende Computer prinzipiell nicht jedes Problem lösen können. Auf fast schon philosophischer Ebene wurde damit auch belegt, dass Wahrheit eine andere Qualität als Beweisbarkeit besitzt. nicht alle „wahren“ Aussagen können auch bewiesen werden.

6.1.3 Die Turing-Maschine: Definition Als abstraktes Modell eines Computers beschrieb Alan Turing (1912-1954) 1963 - also noch vor der Erfindung des Digitalrechners - eine nach ihm benannte abstrakte Maschine Formal kann eine Turing-Maschine wie folgt beschrieben werden: Alphabet: A = {a0, ... , an}, der Zeichenvorrat der Turing-Maschine, wobei a0 das Leerzeichen ("blank") darstellt (Oft: a1=0, a2=1) Bandinschrift: B: Z  A eine Zuordnung, die jeder Stelle des rechtsseitig unendlichen Bandes ein Zeichen zuordnet. Dabei wird festgesetzt, dass B(k) = a0 für alle bis auf endlich viele . Kopfposition: k  Z Zustände: eine endliche Menge von Maschinenzuständen.Q = {q0, ..., qm} Darunter sind q0, der Anfangszustand und H  Q , die Menge der Haltezustände, ausgezeichnet. Statt Haltzustände wird oft auch eine Halteaktion angegeben Turing-Tabelle: eine Übergangsrelation: d : A  Q  A  Q  {r, l, n, h}, das jedem (gelesenen) Zeichen in Abhängigkeit eines Zustandes ein neues Zeichen, einen Folgezustand und eine Aktion (r,l,n,h} zuordnet

6.1.3 Die Turing-Maschine: Programm ... a6 falls so ist die Maschine im Zustand das unter dem Kopf gelesene Zeichen das neue Zeichen die Aktion der neue Zustand q ak al r oder l q‘ Die Aktionen: r (right): das Verschieben des Kopfes nach rechts l (left): das Verschieben des Kopfes nach links optional n (none): keine Bewegung des Kopfes optional h (halt): Impliziter Übergang in einen Endzustand

6.1.3 Die Turing-Maschine: Beispiel Das „Busy beaver“-Problem: Wieviele „1“-en kann ein terminierendes Touring-Programm auf einem leeren Band mit einer vorgegebenen Anzahl von Zuständen maximal erzeugen. In dieser Notation wird statt eines Übergangs in den Haltezustand (z.B. q5) die Aktion „halt“ ausgeführt. 11 Schritte, 6 Einsen 96 Schritte, 13 Einsen Der Rekord für |Z|=5 liegt bei 4096 „1“en (J.Buntrock, H.Marxen, 1989) Es wurde gezeigt, dass es möglich ist, mehr als 4098 „1“en zu generieren - allerdings nicht wie.

6.1.4 Definition: Berechenbarkeit Ein Problem ist genau dann algorithmisch lösbar, wenn es durch eine Turing-Maschine darstellbar ist. Eine Funktion f(x) heißt berechenbar, genau dann wenn es einen Algorithmus (eine Turing-Maschine) gibt, der bei gegebenem x das Ergebnis f(x) liefert Ein Computer ist äquivalent zu einer universellen Turing-Maschine. d.h. ein Computer ist äquivalent zu einer Turing-Maschine, die jede andere Turing-Maschine simulieren kann. Zur Simulation einer beliebigen Turing-Maschine muss auf dem Eingabeband eine Beschreibung der zu simulierenden Maschine codiert werden und außerdem deren Eingabeband gespeichert sein. Die Menge verschiedener universeller Turing-Maschinen ist abzählbar - denn das Band ist binär codiert, jede Kombination lässt sich auf eine natürliche Zahl abbilden. Die Menge aller Funktionen f(x) ist überabzählbar (z.B. Funktionen die auf eine reelle Zahl abbilden)  Es gibt (unendlich viele) nicht berechenbare Funktionen

6.1.5 Beispiel: Das Halteproblem Nicht berechenbare Probleme sind also keine Probleme, die noch nicht gelöst sind, sondern solche, für die es keine Lösung gibt. Das wohl bekannteste dieser Probleme ist das Halteproblem: Es gibt kein Programm, das für ein beliebiges gegebenes Programm, und für beliebige gegebene Eingabeparameter entscheidet, ob das gegebene Programm anhält. Beweis: Geg. Programm P mit Quelltext(P) als Eingabe Annahme: Es gibt ein solches Programm (Test) stoppe Test = ja y n Test(P) Test(P) Test1(P) ja nein P stoppt mit P y n Test(Test1)=ja  Test1(Test1) läuft endlos  Test(Test1)=nein Widerspruch !

6.1.6 Rekursive Funktionen Es gibt innerhalb der mathematischen Funktionen zwei Unterklassen: primitiv-rekursive Funktionen: jede primitiv-rekursive Funktion ist berechenbar es gibt berechenbare Funktionen, die nicht primitiv-rekursiv sind primitiv-rekursive Funktionen lassen sich genau mit Algorithmen ohne Schleifenkonstrukte (aber mit Blockung) darstellen. -rekursive Funktionen jede -rekursive Funktion ist berechenbar es gibt berechenbare Funktionen, die nicht -rekursiv sind -rekursive Funktionen lassen sich mit Algorithmen mit Schleifenkonstrukte (und Blockung) darstellen. Es gilt folgende Beziehung innerhalb von Funktionen: -rekursive Funktionen primitiv-rekursive Funktionen berechenbare Funktionen

6.1.6 Church‘sche These Wir haben bislang verschiedene Äquivalenzen gefunden: Primitiv und -rekursive Funktionen sind Teilmengen von berechenbaren Funktionen. Eine Funktion ist genau dann berechenbar, wenn es eine Turing-Maschine zu deren Berechnung gibt,. Die Darstellung mit Hilfe einer Turing-Maschine ist äquivalent mit der einer universellen Turingmaschinm, die wiederum eine Abstraktion eines Computers darstellt Dies legt die Formulierung einer der Church‘schen These nahe: Alle im intuitiven Sinn vernünftigen Formalisierungen von Problemlösungen sind äquivalent Wenn ein Problem nicht durch eine Turing-Maschine gelöst werden kann, so ist es algorithmisch überhaupt nicht lösbar Da Begriffe wie „intuitiv“ und „vernünftig“ nicht definiert sind, ist die Church‘sche These nicht beweisbar.

6.2 Korrektheit Wir haben diskutiert, ob man jede (mathematische) Funktion berechnen kann und haben dabei die Äquivalenz eines Algorithmus‘ mit berechenbaren Funktionen gesehen. In diesem Unterkapitel geht es nicht mehr nur darum, ob eine Funktion berechenbar ist, bzw. ein Algorithmus für deren Berechnung existiert, sondern ob der gegebene Algorithmus tatsächlich das macht, was er machen soll Inhalt Ansatz Definition Logik zur Verifikation (C.A.R. Hoare) Regeln Terminierung Beispiele Beweis des Euklid‘schen Algorithmus Kritische Anmerkungen U.Kastens:“Modellierung“, Vorlesung WS‘00/‘01, Uni Paderborn

6.2.1 Ansatz Wir haben zu Beginn des Kapitels den Begriff der Korrektheit definiert: partielle Korrektheit: Jedes berechnete Ergebnis genügt der Ausgabespezifikation, sofern die Eingaben der Eingabespezifikation genügt haben Terminierung: Der Algorithmus hält nach endlich vielen Schritten mit einem Ergebnis an, sofern die Eingaben der Eingabespezifikation genügt haben Zum Beweis der Korrektheit gehen wir also von der Eingabespezifi-kation aus und versuchen, mit den Aktionen (Statements) des Algorithmus die Ausgabespezifikation abzuleiten. Die Eingabespezifikation wird dabei als Vorbedingung P(V) oder {P} und die Ausgabespezifikation Q(V) oder {Q} als Nachbedingung mathematisch formuliert Über die Aktionen des Algorithmus wird die Vorbedingung über Zusicherungen Zi(V) zur Nachbedingung abgeleitet Also: P(V)  Z1(V)  ...  Zn(V)  Q(V)

6.2.2 Definition: Korrektheit Beispiel: Lösung der quadratischen Gleichung qugl (IN: p,q: real, OUT x1,x2:real) // Vorbedingung: (p*p)/4 > q // Nachbedingung: x1 = (-b + sqr(p*p/4-q)) / (2*a)  // x2 = (-b - sqr(p*p/4-q)) / (2*a) { w : real; w = sqr(p*p/4 - q); x1 = -p/2 + w; x2 = -p/2 - w: } Ein Algorithmus heißt korrekt bezüglich seiner Spezifikation, wenn für jeden Aufruf, der die Vorbedingung erfüllt, nach dem Aufruf des Algorithmus‘ die Nachbedingung erfüllt ist (und er terminiert) Achtung: Die Vorbedingung ist vom Aufrufer zu erfüllen, die Nachbedingung ist durch den Algorithmus (bzw. den Implementierer) zu erfüllen.

6.2.3 C.A.R. Hoare: Logik zur Verifikation C.A.R. Hoare formulierte 1969 ein Kalkül zum Beweis von Aussagen über Algorithmen und Programme damit sind - im Gegensatz zum Testes - statische Aussagen über Zustände des Algorithmus ( Werte der Variablen) möglich. Diese Aussagen gelten für alle Ausführungen des Algorithmus Durch logisch Schlüsse über die Elemente eines Algorithmus kann gezeigt werden, dass an einer bestimmten Stelle im Algorithmus eine bestimmte Aussage gilt. eine Aussage an jeder Stelle eines Teils des Algorithmus invariant gilt Schleifen terminieren. Also: ein Algorithmus aus jeder zulässigen Eingabe die geforderte Ausgabe berechnet

6.2.3 C.A.R. Hoare: Beispiel min (IN: a,b: integer, OUT min:integer) // Vorbedingung: a,b > 0 (nicht unbedingt notwendig) // Nachbedingung: (min=a  min=b)  (mina)  (minb) { if a<b then { //  Z1: a<b min = a; //  Z2: a<b  min=a  Z3: min=a  mina  minb } else { //  Z4: ba min = b; //  Z5: ba  min=b  Z6: min=b  minb  mina } //  Z7: (min=aminaminb)  (min=bminbmina) //  Z8: (min=a  min=b)  (mina)  (minb) = Q } Damit ist aus der Vorbedingung P mit Hilfe der Anweisung in min() die Nachbedingung Q formal abgeleitet worden.

6.2.3 C.A.R. Hoare: Vorgehen Aussagen über den Algorithmenzustand, über Werte von Variablen werden in den Algorithmus eingefügt: { P } A1 { Q } A2 { R } bedeutet: Q gilt immer zwischen der Ausführung von A1 und der Ausführung von A2 Beispiel: { i + 1 ³ 0} i := i + 1; { i ³ 0 } a [i] := k; {...} Zur Verifikation eines Algorithmus muss für jede Anweisung S ein Nachweis geführt werden: { Vorbedingung P } S { Nachbedingung Q } nachweisen: Wenn vor der Ausführung des Schrittes S die P gilt, dann gilt Q nach der Ausführung von S, falls S terminiert. Beispiel: { i + 1 ³ 0} i := i + 1; {i ³ 0} mit Zuweisungsregel nachweisen Die Aussagen werden entsprechend der Struktur von S verknüpft. Für jede Anweisungsform wird eine spezielle Schlussregel angewandt. Die Spezifikation liefert Vorbedingung und Nachbedingung des gesamten Algorithmus:

6.2.4 Regel: Zuweisung Die Zuweisung x = expr wertet den Ausdruck expr aus und weist das Ergebnis der Variablen x zu. Es gilt dann: {P[x/expr]} x := expr {P} oder {P(x)} x = f(x) {P(f--1(x))} P[x/expr] steht für die Substitution von x durch expr in P Die Nachbedingung P erhält man dadurch, dass man jedes Vorkommen von expr in der Vorbedingung durch x (die linke Seite der Zuweisung) ersetzt Wenn man also zeigen will, dass nach der Zuweisung eine Aussage P für x gilt, muss man zeigen, dass vor der Zuweisung dieselbe Aussage P für expr gilt. Beispiele: {a>0} x = a {x>0} {i+1>0} i=Succ(i) {i>0}: f(x)=Succ, f-1(x)=Pred(x), {P(Pred(x+1)}=(i+1-1>0) {i+1>0} i = i+1 {i>0}

6.2.4 Regel: Zuweisung - Beispiele {P[x/expr]} x := expr {P} alle Aussagen der Vorbed. für expr, gelten für x in der Nachbedingung Aussagen der Vorb. über x gelten in der Nachbedingung nicht mehr Die Nachbedingung P erhält man dadurch, dass man jedes Vorkommen von expr in der Vorbedingung durch x ersetzt ggf. ist die Vorbedingung so umzuformen, dass expr explizit Teil der Vorbedingung ist (auf der linken Seite einer Aussage) „Alles was vorher für die rechte Seite der Zuweisung galt, gilt hinterher für die linke - Alles was vorher für die linke galt, gilt nicht mehr - Alle anderen Aussagen gelten weiterhin“ {y=5} x=y {x=5} {a>0  x>7} x=a {x>0  x>7} falsch wg. Punkt 2 {a>0  z>0} x=a {x>0  z>0} z>0 ist nicht betroffen {i+1>0} i=i+1 {i>0} {i0}  {i+1>0} i=i+1 {i>0} passend umformen {i=2}  {i+1=3} i=i+1 {i=3} passend umformen {z=5} x=1 {z=5  x=1} z nicht betroffen, x neu

6.2.4 Regel: Konsequenz Abschwächung der Nachbedingung wenn gilt und dann gilt auch {P} S {R} {R}  {Q} {P} S {Q} Beispiel {a+b>0} S {x>0} {x>0}  {X0} {a+b>0} S {X0} Verschärfung der Vorbedingung {P}  {R] {R} S {Q} {P} S {Q} Beispiel (Notation: Im Algorithmus können Implikationen in Ausführungsrichtung eingefügt werden) {a+b>0} x = a+b; {x>0}  {2*x  0} y = 2 * x {y0}

6.2.4 Regel: Sequenz Folgendes Schema lässt sich auf eine Sequenz von Aktionen (Statements) anwenden: wenn gilt und dann gilt auch {P} S {R} {R} S2 {Q} {P} S1,S2 {Q} Beispiel: {x>0  y>0} {x>0  y>0} a = x; a = x; {a>0  y>0}  {a>0  y>0}  {a>0  y>0} b = y; b = y; {a>0  b>0} {a>0  b>0} Bei trivialen Ableitungen können die Zwischenschritte (Zusicherungen, Aussagen) demnach auch weggelassen werden: {x>0  y>0} a = x; b = y; {a>0  b>0}

6.2.4 Regel: Bedingte Anweisung Schema: wenn gilt und dann gilt auch {P B} S {Q} {PB}  {Q} {P} if B then S {Q} Um die Nachbedingung einer bedingten Anweisung zu beweisen, muss aus der Vorbedingung und der Anweisungs-Bedingung über die Anweisung die Nachbedingung nachgewiesen werden aus der Vorbedingung und der Negation der Anweisung die Nachbedingung direkt folgen Beispiel: Gegeben: if a<0 then a = -a Beweise, dass der Algorithmus a0 für alle a liefert: {P  a<0}  {P -a>0} a=-a {P  a>0}  {P  a 0} {P  (a<0)}  {P  a 0} dann gilt auch {P} if a<0 then a=-a {P  a 0}

6.2.4 Regel: Bedingte Anweisung - Notation Beispiel: Gegeben: if a<0 then a = -a Beweise, dass der Algorithmus a0 für alle a liefert: {P  a<0}  {P -a>0} a=-a {P  a>0}  {P  a 0} {P  (a<0)}  {P  a 0} dann gilt auch {P} if a<0 then a=-a {P  a 0} Notation: {P} if a<0 then {P  a<0}  {P -a>0} a = -a {P  a>0}  {P  a 0} // leere Alternative: {P  (a<0)}  {P  a 0} {P  a 0}

6.2.4 Regel: Einfache Alternative Schema: wenn gilt und dann gilt auch {P B} S1 {Q} {PB} Ss {Q} {P} if B then S1 else S2 {Q} Aus der gemeinsamen Vorbedingung P muss für beide Alternativen dieselbe Nachbedingung Q nachweisbar sein Beispiel: Gegeben: a>0, b>0, ab und ein Algorithmus (s.u) Beweise, dass nach den Operationen immer noch gilt: a>o, b>0 {a>0  b>0  ab} if a>b then {a>0  b>0  ab  a>b}  {b>0  a-b>0} a = a-b; {b>0  a>0} else {a>0  b>0  ab  ab}  {a>0  b-a>0} b = b-a; {a>0  b>0} {a>0  b>0}

6.2.4 Regel: Schleife Schema: wenn gilt dann gilt auch {P  I B} S {I} {I} while B { S } {I  B  Q} // I = Schleifeninvariante Schleifeninvarianten sind Zusicherungen in Schleifen, die beim Durchlaufen des Schleifenkörpers erhalten bleiben. Es gelte P Zusicherung über Variable vor Schleifeneintritt Q Zusicherung über Variable nach Schleifenende I Schleifeninvariante B Wiederholbedingung der Schleife S Statements (Aktionen) im Schleifenkörper Die Nachbedingung einer Schleife ist über die Invariante nachgewiesen, wenn gilt: P  I die Invariante muss vor Schleifeneintritt wahr sein (I B)  I die Invariante darf in Schleife nicht verändert werden (I B)  Q die Nachbedingung muss sich nach Verlassen der Schleife aus der Invariante nachweisen lassen

6.2.4 Regel: Schleife - Schema Das Schema der Gültigkeit von Aussagen sei anhand des Flussdiagramms für Schleifen verdeutlicht: I muss aus P ableitbar sein  P Um Q(V) zu beweisen, muss man I(V) so wählen, dass Q(V) aus I(V)  B(V) ableitbar ist  I I  B B ? Q(V) f w I  B  Hier muss man beweisen, dass sich I in S aus I  B ableiten lässt S I

6.2.4 Regel: Schleife - Beispiel Algorithmus zum Potenzieren // Vorbedingung: b  0 (positive Exponenten) // Nachbedingung: z = ab x=a, y=b, z=1; { x=a, y=b, z=1; y  0} {INV: z * xy = ab  y0} while y>0 { { INV  y>0  z*x(y-1)+1=ab  (y-1)+1 > 0 } y = y-1; { z*xy+1=ab  y+1>0 }  { ((z*x)/x)*xy+1 = ab  y  0 } z = z*x; { z/x*xy+1 = ab  y  0 }  { z * xy = ab  y  0  INV } } { INV  B  z * xy = ab  y0  y0  z*x0 = z = ab  Q } B ? S P I I  B f w I  B Q

6.2.4 Regel: Schleife - Schleifeninvariante Das Finden der „richtigen“ Invariante kann ganz schön kniffelig sein: Ein paar „Tips“: Wenn die Nachbedingung nicht gegeben ist, versuche die Semantik des Algorithmus‘ zu verstehen, z.B. anhand von Beispielen. Betrachte die Anweisungen in der Schleife: Meist wird etwas vergrößert (z.B. die Variable der Abbruchbedingung), während etwas anderes verkleinert wird - oder umgekehrt. Kombiniere diese: z * xy Setze Ein- und Ausgabevariablen in Bezug zueinander z * xy = ab Verwende die Schleifenbedingung zum „Einklemmen“ der Schleifenvariable. Beachte, dass aus INV und B(V) Q(V) ableitbar sein soll Das bedeutet, dass man die Invariante aus der Nachbedingung konstruieren kann, indem man die negierte Bedingung mit berücksichtigt z * xy = ab  y=0  z*x0 = z = ab  Q

6.2.5 Terminierung Die Terminierung einer Schleife muss separat nachgewiesen werden Beweis der Terminierung Gib einen ganzzahligen Ausdruck E an über Variablen, die in der Schleife vorkommen und zeige, dass E bei jeder Iteration durch S verkleinert wird Zeige, dass E nach unten begrenzt ist, z.B. dass 0E eine Invariante der Schleife ist Zeige, dass die Grenze auch erreicht wird. E kann auch monoton vergrößert und nach oben begrenzt sein Beweis der Nicht-Terminierung: Beweise, dass RB eine Invarianz der Schleife ist (also R in die Schleife geht) und dass es eine Variablenbelegung gibt, so dass RB vor der Schleife gilt dass R einen speziellen Zustand charakterisiert, in dem die Schleife nicht anhält Es gibt Schleifen, für die man nicht entscheiden kann, ob sie für jede Vorbedingung terminieren.

6.2.5 Terminierung - Beispiele { a>0  b>0 } while ab { while a>b { a=a-b } while a<b { b=b-a } } // terminiert { a>0  b>0 } while ab { while ab { a=a-b } while a<b { b=b-a } } // terminiert nicht immer (a = 2*b) { n  n>1 } while n>1 if n gerade then n = n/2 else n=3*n+1 // Terminierung unbewiesen

6.2.6 Beispiel: Multipl. durch fortgesetze Addition // Vorbedingung P: a0  b0, Beh.: Nachbedingung Q: z = a*b x = a; y = b; z = 0; { x0  b0  z=0 } // Auch hier: Die Summe von x*y+z bleibt konstant a*b { INV: z+xy = ab, x,y0 } while x > 0 { { INV  x>0 }  { (z+y)-y+xy = ab, x>0,y0 } z = z + y; { z-y+xy = ab, x>0,y0 }  { z-y+((x-1)+1)y = ab, (x-1)+1>0,y0 } x = x - 1; { z-y+(x+1)y = ab, x+1>0,y0 }  { z-y+xy+y = z+xy = ab, x,y0 }  INV } { INV  B = (z+x*y=a*b)  (x=0)  z+0*y=a*b  Q } B ? S P I I  B f w I  B Q

6.2.6 Beispiel: Die ägyptische Bauernmultiplikation // Vorbedingung P: a0  b0, Beh.: Nachbedingung Q: z = a*b x = a; y = b; z = 0; { x,y0  z=0  x=a  y=b } // Schleife verdoppelt x und halbiert y: Invariante:  INV INV = { z+x*y = a*b  x,y0 } while x > 0 { { INV  x>0 } if (odd(x) then { (z+y)-y+x*y = a*b)  x>0,y0 } z = z+y; { odd(x)  z-y+x*y = a*b  x>0,y0 } // leere Anweisung { even(x)  z+x*y = a*b  x>0,y0 } { ( odd(x)  z-(2y/2)+x*(2y/2) = a*b  x>0,(2y/2)0 )  ( even(x)  z+x*(2y/2) = a*b  x>0,(2y/2)0 ) } y = y * 2; { ( odd(x)  z-y/2+x*y/2 = a*b  x>0,y/20 )  ( even(x)  z+x*y/2 = a*b  x>0,y/20 ) }  { (odd(x)  z-y/2+(2(x div 2)+1)*y/2 = a*b  (2(x div 2)+1)>0,y0 )  (even(x)  z+(2(x div 2))*y/2 = a*b  2(x div 2) >0,y0 ) } x = x div 2; // div = Ganzzahldivision { ( odd(2x+1)  z-y/2+(2x+1)*y/2 = a*b  (2x+1)>0,y/20 )  ( even(2x)  z+ 2x *y/2 = a*b  2x >0,y/20 ) } { (z-(y - y(2x+1))/2 = z-(y-2xy-y)/2 = z-(-2xy/2)= z+xy = a*b ) (z + 2x * (y*2) = z+xy = a*b )}INV } { INV  B = (z+x*y=a*b)  (x=0)  z+0*y=a*b  Q }

6.2.7 Kritische Anmerkungen Die Verifikation entspricht einer mathematischen Beweisführung und kann entsprechend kniffelig, aufwändig, wenn nicht gar unmöglich sein. Durch formale Überprüfung der Korrektheit, lassen sich Schlüsselstellen eines Algorithmus‘ (eines Programmes) verifizieren Durch das Denken mit Zusicherungen, Invarianten und mathematische Folgerungen wird die Erstellung fehlerfreier Programme gefördert. Auch wenn es semi-automatische Systeme zur formalen Verifikation von Algorithmen gibt, ist es praktisch nicht möglich, auch nur halbwegs komplexe Programmsysteme damit zu verifizieren Selbst wenn es möglich wäre, Algorithmen vollständig formal zu beweisen, so wäre dies keine Garantie, dass ein Programmsystem entsprechend den Wünschen eines „Kunden“ funktioniert. Dazu gehören alle Mechanismen eines ordentlichen Software-Engineerings.

6.3 Komplexität In diesem Kapitel haben wir den Begriff „Berechenbarkeit“ definiert als all das, was algorithmisch beschreibbar ist. Wir haben eine Methode vorgestellt, mit der man (meist) zeigen kann, dass ein Algorithmus das tut was er soll. Was noch fehlt - und hier behandelt werden soll - ist die Frage nach dem Zeit- und Platzbedarf eines Algorithmus. Inhalt Wie „gut“ ist ein Algorithmus Die O-Notation Häufige O-Ausdrücke Einige Regeln Quantitatives Platzbedarf

6.3.1 Qualität eines Algorithmus Die Abarbeitung eines Algorithmus benötigt „Resourcen“, vor allem: Zeit Laufzeit des Algorithmus Platz Speicherplatzbedarf des Algorithmus Problem bei der Resourcenermittlung - der Resourcenbedarf ist Abhängig von: der Problemgröße (z.B. Multiplikation einer 10x10 bzw. 100x100 Matrix) der Eingabewerte (z.B. Sortieren einer bereits sortierten Menge) der Fragestellung (bester, mittlerer, schlechtester Fall) der Güte der Implementierung (z.B. (un)geschickte Typwahl) der Hard- und Software (z.B. Schneller Rechner, optimierter Compiler) Es gibt auch Qualitätsmerkmale eines Algorithmus, der sich nicht am Resourcenbedarf festmachen (aber das ist eine andere Geschichte ...) Wartbarkeit Robustheit „Eleganz“ ...

6.3.2 Die O-Notation: Definition Definition: Eine Funktion g(n) wird O(f(n)) genannt („Die Laufzeit, der Aufwand, die Zeitkomplexität von g(n) ist O(f(n))“), falls es Konstanten c und n0 gibt, so dass: g(n)  cf(n), für fast alle n > no ist f(n) ist damit eine obere Schranke für die Laufzeit des Algorithmus (allerdings nur ab einem bestimmten c und n0) Beispiel: Bei der Analyse eines Algorithmus hat sich herausgestellt, dass die Laufzeit g(n) = 3n2 + 7n - 1 ist. Behauptung: Die Laufzeit von g(n) ist O(n2), also f(n)=n2, Beweis: Es muss Konstanten c und n0 geben, so dass gilt 3n2+7n-1  c n2, für alle n > n0 setze n0=7 und c=4, dann gilt: 3n2+7n-1  3n2+7n  3n2+n2 = 4n2

6.3.2 Die O-Notation: Schranken Die Notation gibt nur eine obere Schranke der Komplexität , das muss nicht notwendigerweise die beste Schranke sein. Beispiel: Eine weitere obere Schranke für g(n) = 3n2 + 7n - 1 ist auch O(n3), welche sicher nicht die beste ist. Bei der Suche nach der Größenordnung von f(n) wird man versuchen, das kleinste f(n) zu finden, für das g(n) < c . f(n) Dieses ist dann eine kleinste, obere Schranke für den Aufwand Zur Bestimmung des tatsächlichen asymptotischen Aufwands wird man also noch eine größte, untere Schranke h(n) = (g(n)) suchen für die gilt: limn h(n)/f(n) = 1 Eine untere Schranke ist die Zeit, die jeder Algorithmus (ab einem n>n0) benötigt Das ist im Allgemeinen viel schwieriger !

6.3.2 Die O-Notation: Achtung Achtung ! Die Konstanten c und n0 werden üblicherweise nicht angegeben und können sehr groß sein Beispiel: Algorithmus A habe eine Laufzeit von O(n2) Algorithmus B für das gleiche Problem eine Laufzeit von O(1,5n) Welcher Algorithmus ist besser ? schnelle Antwort: A (das stimmt auch für große n) bessere Antwort: Wie groß ist n ? Wie groß sind die Konstanten ? z.B. für cA=1000 und cB=0,001 n cAn2 cB1,5n 1 103 1,5  10-3 10 105 1,8  10-2 20 4  105 3,3 50 2,5  106 6,4  105 100 107 4,1  1014 Bis hier ist B besser als A

6.3.3 Häufige O-Ausdrücke: O(1) Teile von Ausdrücken, die eventuell ein „paar“ Mal durchlaufen werden, wobei die (maximale) Anzahl der Durchläufe nicht abhängig von den Eingabewerten sind, haben konstante Laufzeit: O(1) Beispiel: max, i, y : integer; max = 0; y << Tastatur; if (y < 20) then max=10 else max=100; for i=1 to max { y = y+1; } Die Anzahl der Schleifendurchläufe ist zwar abhängig von y (entweder 20 oder 100), die maximale Anzahl aber nicht (immer 100, egal wie groß oder klein y ist)

6.3.3 Häufige O-Ausdrücke: O(log n) - rekursiv Rekursive Algorithmen, die in jedem Schritt die Menge der Eingabedaten halbieren haben eine Laufzeit von O(log n) eigentlich O(ld n), aber da ld n  3,322 log b = c log b ist O(ld b)=O(log n) Beispiel: Suche in einem sortierten Binärbaum search (IN: x:integer; tree:*node; OUT: found:boolean) { if tree == nil then { // there is no tree to search => x not found found = false; return; // ATTENTION: return already here } if (x < node.value) then search(x,node.left, found) else if (x > node.value) then search(x,node.right,found) else if (n == node.value) found=true; }

6.3.3 Häufige O-Ausdrücke: O(log n) - Zeitbedarf Block mit rekursivem Aufruf der/s halben Eingabemenge/-Wertes rek_block (IN: Eingabemenge OUT: Ausgabewert) { if ( Trivialfall) then { Ausgabewert = Trivialwert } // optional: Aktionen mit konstantem Aufwand rek_block (Eingabemenge / 2); } Bestimmung des Zeitbedarfs Der Zeitbedarf für das Durchlaufen ergibt sich aus: Abfrage des Trivialfalls und (optional) Aktionen  O(1) Rekursiver Aufruf mit Eingabemenge/Wert die/der halb so groß ist, also n/2. also : Tn = 1 + Tn/2 (Tn = Zeitbedarf für n, n2) T1= 0 (eigentlich 1, kann aber vernachlässigt werden) Annahme (o.B.d.A.): Eingabemenge/-wert ist Potenz von 2 also n = 2k, Diese Annahme kann man machen, denn falls n keine Zweierpotenz ist, erhöht man die Eingabemenge/-wert auf die nächste 2er Potenz und bekommt noch immer eine obere Schranke. T2k = T2k-1 +1 = T2k-2 +1+1 = ... = T20 + k = k  T2k = k  Tn= k = ldn

6.3.3 Häufige O-Ausdrücke: O(n) - rekursiv Rekursive Algorithmen, die in jedem Schritt die Menge der Eingabedaten halbieren aber dazu jedes Element betrachten müssen haben eine Laufzeit von O(n) Beispiel: Suche in einer sortierter Liste (array) mit 0 am Ende search (IN: x:integer; list:*liste; OUT: found:boolean) { i : integer; if (list[1]==0) then found = false; // list with no element i=1; while (list[i] <> 0) i=i+1 // get length of list if (x==list[i/2]) then found = true; else if (x<list[i/2]) then { list[i/2+1]=0; search(x,&list[1],found} }; else search(x,&list[i/2+1],found); } Zeitbedarf: Tn = Tn/2+ n (Tn = Zeitbedarf für n, n2, T1=0) Annahme (o.B.d.A.): n = 2k, T2k = T2k-1 + n = T2k-2 + n/2+n = ... = T20 +n/2+n/4 + ... + 0 = 2n-2 O(n)

6.3.3 Häufige O-Ausdrücke: O(n) - iterativ Iterative Algorithmen die eine lineare Liste durchlaufen deren Länge abhängig von der Menge der Eingabeelemente ist (einfache Schleife), haben die Laufzeit O(n) Beispiel: Suche in einer sortierter Liste (array) mit 0 am Ende search (IN: x:integer; list:*liste; OUT: found:boolean) { i : integer; found = false; // initialize OUT-value i=1; while ((list[i] <> 0) and (not found)) { i=i+1; if (list[i]==x) then found = true; } } Anmerkung: Dieser Algorithmus funktioniert auch mit unsortierten Listen Warum dann einen rekursiven, teilenden Algorithmus ? Anzahl „eingeschränkter“ Vergleiche O(n) Anzahl „vollständiger“ Vergleiche O(log n)

6.3.3 Häufige O-Ausdrücke: O(n) - rekursiv Rekursive Algorithmen, die die Eingabedaten in zwei Hälften aufspalten, und beide Hälften getrennt abarbeiten, haben eine Laufzeit von O(n) Beispiel: Erstellen eines „Lineals“ (siehe auch: Skript Dr. Geisse) linael (IN: links,rechts,höhe:integer) { mitte : integer; if (höhe>0) then { mitte = (links + rechts) / 2; zeichne (mitte,höhe); lineal (links,mitte,höhe-1); lineal (mitte,rechts,höhe-1); } } Zeitbedarf: Tn = 2Tn/2+ 1 (Tn = Zeitbedarf für n, n2, T1=0) Annahme (o.B.d.A.): n = 2k, T2k = 2T2k-1 + 1  1/2 T2k = T2k-1 + 1/2 = 2T2k-2 + 1 + 1/2  1/4 T2k = T2k-2 + 1/2 + 1/4  ...  1/2k T2k = T20 + 1/2 + 1/4 + ... + 1/2k = 1 - 1/2k  T2k = 2k-1  Tn = n-1  Laufzeit O(n)

6.3.3 Häufige O-Ausdrücke: O(n log n) Rekursive Algorithmen, die die Eingabedaten in zwei Hälften aufspalten, und die Eingabedaten einmal durchlaufen (davor, währenddessen, oder danach), haben eine Laufzeit von O(n log n) Beispiel: Sortieren einer Liste a : array[1..max] of integer (C.A.R. Hoare) Quicksort (IN:l,r:integer) { // l left, r right index i,j,x : integer; // i,j: indexes, x,y: elemets i=l; j=r; // initialize i with left, j with right index x = a[(l+r)/2}] // get element in the middle do { // walk with i from left, with j from right while a[i]<x { i=i+1 } // skip smaller elements from left while a[j]>o { j=j-1 } // skip larger elements from right if (i<=j) then { exchange(a[i],a[j]); i=i+1; j=j11 } } while i<=j // i is now right of j -> stop loop if l<j then sort(l,j); // sort left part (only if exists) if i<r then sort(i,r); // sort right part (only if exists) Zeitbedarf: Tn = 2Tn/2+ n (Tn = Zeitbedarf für n, n2, T1=0) Annahme (o.B.d.A.): n = 2k, (d.h. k = ld n) T2k = 2T2k-1 + 2k  1/2k T2k = T2k-1/2k-1 + 1 = T2k-2/2k-2 + 1 + 1 = ... = k  1/2k T2k = k  T2k = 2k k  Tn = n log n  Laufzeit O(n log n)

6.3.3 Häufige O-Ausdrücke: O(n2) - rekursiv Rekursive Algorithmen, die die Eingabedaten jeweils um eins verringern, dabei aber alle Daten betrachten müssen, haben eine Laufzeit von O(n2) Beispiel: Sortieren einer Liste a : array[1..max] of integer StraightSelection (IN:l,r:integer) { // l left, r right index i: integer; // index i = l; // start with left element while (i<r) { // walk through complete list // if an element is smaller, bring it to the left if (a[i]<a[l]) then exchange(a[i],a[l]); i = i+1; } if (l<r) then StraightSelection (l+1,r); } Zeitbedarf: Tn = Tn-1+ n (Tn = Zeitbedarf für n, n2, T1=1) Tn = Tn-1 + n = Tn-2 + n-1 + 1 = Tn-3 + n-1 + n-2 + 1 = ... = 1+2+3+..+n  Tn = (n(n+1))/2 = 1/2n2 + 1/2n  Laufzeit O(n)

6.3.3 Häufige O-Ausdrücke: O(n2), O(n3) - iterativ Iterative Algorithmen die eine Liste - deren Länge abhängig von der Menge der Eingabeelemente ist - (fast) sooft durchlaufen, wie die Liste lang ist (doppelt verschachtelte Schleife), haben die Laufzeit O(n2) Beispiel: Sortieren einer Liste a : array[1..max] of integer StraightSelection (IN:l,r:integer) { // l left, r right index i: integer; // index i = l; // start with left element for i=1 to r-1 // walk through complete list { for j=i+1 to r // walk through rest of list { if (a[j]<a[i]) then exchange(a[i],a[j]); } } } Dreifach verschachtelte Schleifen haben eine Laufzeit von O(n3) Beispiel: Multiplikation zweier Matrizen

6.3.4 Einige Regeln Hat ein Algorithmus eine Laufzeit, die mit einem Polynom k-ten Grades darstellbar ist (aknk + ak-1nk-1 + ... + a0) , so ist die Laufzeit O(nk) Beispiel: Laufzeit: 9n3 + 7n - 1000  Laufzeit O(n3) Wird ein Teil A mit Laufzeit O(x) vor einem Teil B mit Laufzeit O(y) ausgeführt, so ist die Gesamtlaufzeit das Maximum der Laufzeiten. Beispiel: Laufzeit A ist O(n2), Laufzeit B ist O(n)  Laufzeit A,B = O(n2) + O(n) = O(n2) Wird ein Teil A mit Laufzeit O(x) innerhalb eines Teiles B mit Laufzeit O(y) ausgeführt, so ist die Gesamtlaufzeit das Produkt der Laufzeiten. Beispiel: Laufzeit A ist O(n2), Laufzeit B ist O(n)  Laufzeit A(B) = Laufzeit B(A) = O(n2)  O(n) = O(n3) Beispiel: Eine Dreifach verschachtelte Schleife (O(n3)) ist eine Schleife O(n) in einer zweifach verschachtelten Schleife (O(n2)) : O(n3) = O(n2)  O(n)

6.3.5 Quantitatives n ld n (ld n)2 n n ld n n2 10 3 9 3 30 100 10 3 9 3 30 100 100 6 36 10 600 1000 1000 9 81 31 9000 1000000 10000 13 169 100 130000 108 100000 16 256 316 1,6 106 1010 1000000 19 361 1000 19 106 1012

6.3.6 Platzbedarf Unter „Aufwand“ wird i.A. der zeitliche Aufwand, also die Zeitkomplexität verstanden Manchmal ist auch die Platzkomplexität bzw. Speicherbedarf relevant. Darunter versteht man dann, ganz entsprechend zur Zeitkomplexität, eine obere Schranke für den Speicherbedarf eines Algorithmus für ein Problem mit einer Eingabemenge der Größe n. Auch beim Speicherbedarf von Algorithmen existieren die „Komplexitätsklassen“ (n, n2, n log n, ...) Auch beim Speicherbedarf unterscheiden sich „geschickte“ und „ungeschickte“ Algorithmen für die Lösung eines gegebenen Problems. Da Computerspeicher endlich, die Zeit aber potentiell unendlich ist hat der Speicherbedarf oft die höhere Priorität. Meist wird daher der Algorithmus gewählt, der sehr Nahe am minimal möglichen Speicherbedarf bei möglichst optimalem Aufwand liegt.

6.3.6 Platzbedarf Oft kann man eine bessere Zeitkomplexität zu Lasten des Speicherbedarfs erreichen (und umgekehrt) Beispiel: Trivialer Hashsort (Unsortierte Liste a: array [1..n] of type) b: array [1..max(type)] // max(type) is largest element in type, // e.g. max(unsigned integer) = 65535 i,j : integer; for i=1 to n { b[a[i]] = a[i]; } j = 1; for i=1 to max(type) { // shift to beginning of list if ((not_empty(b[i])) and (i<>j)) then { b[j]=b[i]; j=j+1;} } 1.Schleife + 2.Schleife: O(n) + O(1) = O(n) Man wägt daher Speicherbedarf und Zeitkomplexität gegeneinander ab.

6.4 Zusammenfassung des Kapitels Berechenbarkeit: Einige Fragen und das Entscheidungsproblem Die Turing-Maschine und der Begriff der Berechenbarkeit Rekursive Funktionen und die Church‘sche These Korrektheit Ansatz und Definition Logik zur Verifikation: Die Hoare‘schen Regeln Beispiele und Beweis des Euklid‘schen Algorithmus Kritische Anmerkungen Komplexität Wie „gut“ ist ein Algorithmus und die O-Notation Häufige O-Ausdrücke und einige Regeln bei deren Anwendung Quantitatives Platzbedarf

Kapitel 7 Sprachen Wir haben Information als grundlegenden Begriff der Informatik eingeführt und über Codes und Datenstruktur abstrahiert. Andererseits haben wir den Umgang mit Information, zunächst am einfachen Beispiel (Rechnen mit Zahlen in beliebigen Zahlensystemen), dann abstrakter und mächtiger mit Hilfe von Algorithmen kennengelernt. Dieses Kapitel führt nun in die wesentliche Anwendung dieser grundlegenden Überlegungen ein. Es beschreibt die fundamentalen theoretischen Grundlagen von Sprachen im Allgemeinen und Programmiersprachen im Besonderen. Inhalt Programmiersprachen Syntax und Semantik Reguläre Ausdrücke Endliche Automaten Grammatiken

7.1 Programmiersprache Programmiersprachen sind das Mittel der Informatik, Algorithmen problemorientiert zu formulieren. Die wichtigen Begriffe „Programmiersprache“ und „Programm“ sind dabei - zumindest was den zweiteren betrifft - nicht ganz klar und sollen zunächst kurz eingeführt werden. Danach soll ein sehr kurzer Überblick über die Entwicklung von Programmiersprachen gegeben werden, der mit einem Resumée abschließt. Inhalt Was ist eine Programmiersprache Was ist ein Programm Generationen von Programmiersprachen Programmiersprachen heute

7.1.1 Was ist eine Programmiersprache Eine Programmiersprache ist eine künstliche Sprache zur präzisen Formulierung von Algorithmen. Sie ist: vollständig (zumindest in einigen Aspekten) eindeutig maschinell verarbeitbar Die Programmiersprache spielt eine Mittlerrolle zwischen Mensch und Maschine Beschreibung soll für den Menschen generierbar und verständlich sein Beschreibung soll für die Maschine verständlich und exakt, wiederholbar ausführbar sein. Programmiersprachen sind abhängig von Anwendungsgebiet Art der Rechnersysteme Mentalität der Programmierer

7.1.2 Was ist ein Programm Ein Programm durchläuft einige Repräsentationsformen Quelltext Der Quelltext ist die dem Menschen geläufigste Repräsentationsform eines Programmes. Der Quelltext wird meist vom Menschen mit einem Editor erstellt und formalisiert einen Algorithmus Teilweise wird Quelltext auch von anderen Programmen generiert Der Quelltext eines Programmes befindet sich oft in genau einer Datei, in größeren Programmen meist in mehreren Dateien Objektmodul Wird ein Programm z.B. mit Hilfe eines Compilers übersetzt, so ist es bereits in binärer Repräsentation, allerdings so noch nicht lauffähig auf einem Prozessor Ausführbares Programm Das Programm ist binär repräsentiert und mit allen Teilen „zusammen-gebunden“, die notwendig für die Ausführung auf einem Prozessor sind. Prozess Ein Prozess ist ein Programm, welches gerade auf dem Prozessor (auf den Prozessoren) ausgeführt wird.

7.1.3 Generationen von Programmiersprachen Wie ? Speicher- stelle Generation: Maschinensprachen Generation: Assemblersprachen Generation: Prozedurale Sprachen Generation: Datenbankabfragesprachen Generation: Deklarative Sprachen Relation Objekt Was ?

7.1.3 Generation: 1. Maschinensprachen Prozessorspezifische Sprache, meist in Binärform : 0100 0111 0110 0110 0011 0111 0111 0000 1100 1000 0010 1000 0111 0100 0000 0000 ... Direkte Ausführung durch Prozessor möglich Extrem aufwendige Programmierung Einsatz heute nur noch in (manchen) Mikroprozessorsteuerungen im ROM-BIOS, Bootblock zur Wartung alter Steuergeräte, wenn deren Einsatz bzgl. des Programmieraufwandes noch lohnend ist

7.1.3 Generation: 2. Assemblersprachen Verwendung mnemonischer Bezeichner, strukturäquivalent zu Binärcode (seit ca. 1950) 00401571 mov ecx,dword ptr [esp+4] 00401579 test ecx,ecx 00401584 jne 0040158E 00401586 push 0FDh 00401588 call dword ptr ds:[4010B8h] 0040158E pop ecx 00401592 ret 8 0040159B mov esi,ecx 0040159D push 0 0040159F call 0040156C 004015A7 ret ... Übersetzung des Codes durch Assembler Einsatz heute noch bei systemnaher Programmierung

7.1.3 Generation: 3. Prozedurale Sprachen Prozedurale Sprachen setzen Algorithmen und Datenstrukturen, wie sie in den vorangegangenen Kapiteln beschrieben wurden sehr natürlich um. Rechnerunabhängige Sprachen in einer meist anwendungsabhängigen Schreibweise (Syntax) und Bedeutung (Semantik). Fortran 1954 wissenschaftlich/technisch Cobol 1957 kommerziell Algol 1957 wissenschaftlich/technisch PL/1 1960 universell Basic 1963 einfach wissenschaftlich/technisch Pascal 1968 universell, Lehre Chill 1968 Systemprogrammierung (T-Kom) Pearl 1970 Regelung C 1970 universell, Systemprogrammierung Ada 1975 universell, Militär Modula 1975 Lehre C++ 1980 universell, Systemimplementierung

7.1.3 Generation: 4. Datenbankabfragesprachen Einfacher Umgang mit Datenbanken (4GL, seit 1965): Definition des Datenbank-Layouts Operationen auf Datenbanken Generierung von graphischen Benutzeroberflächen Beispiele: SQL (Standard Query Language) NATURAL Heute oft in Kombination mit prozeduralen Sprachen unterstützt durcvh graphische Sprachelemente Extreme Beschränkungen durch Fokus auf Datenbanken, daher nicht (mehr) weit verbreitet.

7.1.3 Generation: 5. Deklarative Sprachen Beschreibung des Problems in einem (meist) mathematischen Formalismus. Lösung, basierend auf der Beschreibung, durch das System. Logische Sprachen, z.B. Prolog funktionale Sprachen, z.B. ML logisch-funktionale Sprachen (Zur Zeit) Keine wesentlichen Einsatzgebiete

7.1.4 Programmiersprachen heute Seit den Zeiten der Maschinensprachen hat eine Entwicklung zu mehr Abstraktion stattgefunden Abstraktion des Algorithmus von einfachsten Maschinenbefehlen (bestehend aus Zuweisungen, Vergleichen und Sprüngen) über prozedurale Sprachen (mit ihren Mitteln der strukturierten Programmierung) bis hin zu deklarativen Sprachen (die Probleme vollständig beschreiben, deren Lösung dann generisch stattfinden kann) Abstraktion der Datenstrukturen von der „blanken“ Speicherstelle und Register bis hin zu relationalen Strukturen (4GL-Sprachen) und objektorientierten Strukturen (mit Vererbungsbeziehungen und Datenkapselung) Stand heute: Tatsächlich sind die Sprachen der 3. Generation, insbesondere die mit objektoerientierter Erweiterung, die zur Zeit wesentlichen. Grund für das „Scheitern“ der 4GL-Sprachen ist der eingeschränkte Fokus auf relationale Strukturen - Grund des „Scheiterns“ deklarativer Sprachen ist die unangepasste Abstraktionsfähigkeit der Datenstrukturen und insbesondere der Aufwand generischer Algorithmen.

7.2 Syntax und Semantik Im vorangegangenen Unterkapitel haben wir Programmiersprachen als präzise, vollständig und eindeutig beschrieben. Diese Beschreibung trifft tatsächlich aber nicht auf alle Aspekte der Sprache zu. In diesem Unterkapitel sollen nun die Aspekte einer Programmier-sprache beschrieben werden, sowie die Möglichkeiten, diese Aspekte zu beschreiben. Inhalt Syntax vs. Semantik Syntax Semantik

7.2.1 Syntax vs. Semantik Bei der Beschreibung einer Programmiersprache unterscheidet man zwischen Syntax und Semantik der Sprache: Unter der Syntax einer Programmiersprache bezeichnet man den formalen Aufbau, also die Struktur, einer Sprache Unter der Semantik einer Programmiersprache bezeichnet man, die Bedeutung der Konstrukte einer Programmiersprache Beispiel: Syntax für die Zuweisung: linke_seite = rechte_seite; Semantik der Zuweisung: Der Wert der rechten Seite wird bestimmt und wird an die Speicherstelle abgelegt, die durch die linke Seite bezeichnet ist. Beachte Die Syntax kann (meist) vollständig formal angegeben werden Die Semantik wird meist nur informell beschrieben Fehler, die auf fehlerhaftes Verständnis der Semantik beruhen sind oft schwer zu finden.

7.2.2 Syntax Wie wir gesehen haben, beschreibt die Syntax einer Programmier-sprache deren Struktur. Dabei ist lässt sich die Struktur von Programmiersprachen noch in zwei Abstraktionsebenen einteilen: Lexikalische Struktur: Hierunter versteht man die Struktur der „atomaren“ Elemente oder Grundsymbole der Programmiersprache Syntaktische Struktur: Hierunter versteht man die Zusammensetzung von Grundsymbolen der Sprache zu komplexeren Strukturen Notation: Die Syntax einer Sprache lässt sich (meist) formal beschreiben. Dazu gibt es verschiedene Beschreibungsmittel bzw. Notationen. lexikalische Struktur syntaktische Struktur

7.2.2 Syntax: Lexikalische Struktur Die lexikalische Struktur: beschreibt also den Aufbau der Grundsymbole aus einzelnen Zeichen Diese Zeichen sind Buchstaben, Ziffern und Sonderzeichen Die resultierenden Grundsymbole nennt man auch Token Beispiel: Zahlen bestehen aus beliebig vielen, aber mindestens einer Ziffer IEEE 754 Zahlen bestehen aus Ziffern und Kommas in Mantisse und Exponent mit einem (kleinen oder großen) E dazwischen. Dabei sind einige Teile optional Bezeichener beginnen mit einem Buchstaben, gefolgt von Ziffern, Buchstaben und dem Sonderzeichen „_“ Die lexikalische Struktur lässt sich mit regulären Ausdrücken beschreiben endlichen Automaten untersuchen Ein Programm zur Umsetzung lexikalischer Strukturen in Token nennt man Scanner.

7.2.2 Syntax: Syntaktische Struktur Die syntaktische Struktur beschreibt also die Zusammensetzung von Grundsymbolen der Sprache zu Ausdrücken, Anweisungen und letztlich zu einem vollständigen Programm. Beispiel: Ein Ausdruck besteht aus: einem Ausdruck gefolgt von einem Operator, gefolgt von einem Ausdruck z.B.: 5 * 7 oder aber einer einzelnen Zahl z.B. 5 Eine abweisende Schleife besteht aus: dem Schlüsselwort „while“, einem boll‘schen Ausdruck (in Klammern) und einer Anweisung. z.B. while (a>5) i=i+1; Die syntaktische Struktur lässt sich durch Grammatiken beschreiben Ein Programm zur Analyse der syntaktischen Struktur (und zu dessen weiteren Verarbeitung) nennt man Parser.

7.2.3 Semantik Die Semantik beschreibt also die Bedeutung der Konstrukte einer Programmiersprache. Beispiel: if (a>5) then a=5 else a=0 Die Bedeutung dieser Alternative lässt sich wie folgt beschreiben: Die bool‘sche Bedingung der Alternative wird ausgewertet: Ist das Ergebnis „wahr“ so werden die Anweisungen des then-Zweiges ausgeführt, Ansonsten werden die Anweisungen des else-Zweiges ausgeführt. Die Beschreibungsformen - also die Notation der Beschreibung - sind typischerweise nicht vorgeschrieben bzw. formalisiert. Da es für die meisten Programmiersprachen keine formalen Notationen der Semantik gibt, gibt es auch meist kein Programm, welches für eine Programmiersprache automatisch einen Übersetzer für Programme dieser Sprache generiert. Scanner und Parser können automatisch generiert werden Compiler meist nicht

7.3 Reguläre Ausdrücke Im vorangegangenen Unterkapitel haben wir gesehen, dass die lexikalische Analyse auf einer formalen Beschreibung der lexikalischen Strukturen einer Programmiersprache aufbaut. Diese formale Beschreibung ist die der „regulären Ausdrücke“. Dieses Unterkapitel führt nun in die regulären Ausdrücke ein. Inhalt Beispiel Definition: reguläre Ausdrücke Definition: reguläre Sprachen UNIX-Notation Beispiele

7.3.1 Beispiel Beispiel Ziffer = [‘0‘-‘9‘] Zahl = {Ziffer}+ Buchstabe = [‘A‘-‘Z‘‘a‘-‘z‘] Bezeichner = {Buchstabe}({Ziffer}|{Buchstaben})* Notation (Auszug aus der UNIX-Notation) Einfache Notationsregeln: Hintereinander schreiben bedeutet: Konkatenation | bedeutet: Alternative Die Klammerung ist möglich (und äquivalent der math. Bedeutung) [‘0‘-‘9‘] ist die Kurzform von ‘0‘ | ‘1‘ | ... | ‘9‘ {x} wird ersetzt durch die Definition von x + bedeutet: beliebig oft, aber mindestens einmal * bedeutet: beliebig oft, auch kein mal

7.3.2 Definition: reguläre Ausdrücke Reguläre Ausdrücke sind Formeln, mit denen (bestimmte) Sprachen definiert werden könnn Sei  ein endlichen Alphabet bestehend aus Zeichen. Reguläre Ausdrücke sind wie folgt induktiv definiert e ist ein regulärer Ausdruck Für jedes a  ist a ein regulärer Ausdruck wenn a und b reguläre Ausdrücke sind, dann auch: a) ab a konkateniert mit b b) (a|b) a oder b c) (a)* a beliebig oft, einschließlich 0-mal wobei die Wiederholung Vorrang vor der Konkatenation und diese wiederum Vorrang vor der Alternative hat. Um Präzedenzen explizit darzustellen ist es möglich, beliebig zu lammern. Beispiel: Sei ={a,b,c,d,e}: (ab|cd*)* ist ein regulärer Ausdruck denn, a und b ist regulärer Audruck wg. 2., ab ist regulärer Ausdruck wg. 3.a c und d ist regulärer Audruck wg. 2., d* ist regulärer Ausdruck wg. 3. c), cd* ist regulärer Ausdruck wg .3.a) (ab|cd*) ist regulärer Ausdruck wg. 3.b) (ab|cd*)* ist regulärer Ausdruck wg. 3.c)

7.3.3 Definition: reguläre Sprachen Alle durch einen regulären Ausdruck r definierten Folgen von Zeichen nennt man Wörter der Sprache L(r) Die Menge der durch reguläre Ausdrücke beschreibbaren Sprachen ist genau der Menge der regulären Sprachen Beispiele:  ={a,b}  = {a,b,c} r =  r = a | bc | ccc L(r) = { } L(r) = {a,bc,ccc}  = {a,b,c} r = (abc|bc)a*(bc|ab)* L(r) = {abcabc, bcabc, abcaab, bcaab, abcaabc, ....} Es gibt Sprachen, die sich nicht durch reguläre Ausdrücke definieren lassen: L(r) = {ab,aabb,aaa,bbb, ....., anbn} Alle Programmiersprachen

7.3.3 UNIX-Notation - die klassischen Elemente Für Token einer real existierenden Programmiersprache ist die einfache Notation regulärer Ausdrücke teilweise sehr umständlich. Beispiel: Bezeichner: (a|b|c|....|z|A|B|...|Z|_)(a|b|c|....|z|A|B|...|Z|_|0|1|....|9)* Daher hat sich in der Informatik eine zwar komplexere aber dafür flexiblere Notation eingebürgert: Die UNIX-Notation Die UNIX Notation übernimmt die folgenden Konstruktionsregeln (mit den zugehörigen Präzedenzregeln) aus der „klassischen“ Notation für reguläre Ausdrücke Konkatenation zweier reg. Ausdrücke erfolgt ohne expliziten Operator Alternativen werden mittels j gebildet ein normales\ Zeichen steht fur sich selbst ein nachgestellter * steht für beliebige Wiederholung Klammerung erfolgt durch ( und )

7.3.3 UNIX-Notation - Die Sonderzeichen Zusätzlich unterscheidet man in der UNIX Notation zwischen weiteren Sonderzeichen und normale Zeichen. Weitere Sonderzeichen sind z.B. : * + [ ] ? ^ ( ) . $ Falls ein Sonderzeichen nicht als solches interpretiert werden soll, ist ein "\“ voranzustellen Die Bedeutung der Sonderzeichen ist wie folgt . steht für ein beliebiges Zeichen außer '\n‚ (Zeilenumbruch) Auch in Apostrophe eingeschlossene Strings werden verbatim interpretiert. ein nachgestelltes + steht für nichtleere Wiederholung ein nachgestelltes ? bezeichnet einen optionalen Anteil ^ am Anfang eines regulären Ausdrucks steht für Zeilenanfang $ am Ende eines regulären Ausdrucks steht für Zeilenende

7.3.3 UNIX-Notation - Die Zeichenklasse eine Zeichenklasse steht für genau ein Zeichen. Sie kann durch Zeichen-Aufzählung x1, x2,... xn und Bereichsangaben x1-xn gebildet werden: [x1-xn] steht für ein Zeichen aus dem Bereich und entsprich der klassischen Notation x1|x2|... |xn Beispiel: [0-9] [x1x2...xn] steht für genau ein Element aus der Menge der angegebenen Zeichen Beispiel: [abc_] Beide Schreibweisen (Bereich und Aufzählung) können beliebig kombiniert werden. Beispiel: [a-zA-Z0-9_] Ein ^-Zeichen am Anfang der Zeichnklasse ( [^....] ) spezifiziert die komplementäre Zeichenmenge. Beispiel: [^0-9] steht für ein beliebiges Zeichen außer einer Ziffer

7.3.4 Beispiele Alle mit kleinem „a“ beginnenden Zeichenketten: a.* Alle nichtleeren Dezimalziffernfolgen: [0-9]+ Alle Wörter, die aus genau 3 Zeichen bestehen und nicht mit einer Ziffer enden: ..[^0-9] Pascal-Bezeichner = [A-Za-z][A-Za-z0-9]* C-Float-Literale = -?[0-9]+((\.[0-9]+)|((\.[0-9]+)?[eE]-?[0-9]+) C-Float-Literale bestehen aus einem Vorkomma-Anteil\ (ggf. mit Minuszeichen) (Syntax: -?[0-9]+) einem optionalen Nachkomma-Anteil (Syntax: \.[0-9]+) und einem ebenfalls optionalen Exponenten-Anteil (Syntax: [eE]-?[0-9]+). Dabei ist zu beachten, dass entweder der Nachkomma-Anteil oder der Exponent vorhanden sein muss. Wenn beides fehlt, liegt eine Integer-Konstante vor. Daher ist die folgende Spezifkation nicht korrekt: -?[0-9]+(\.[0-9]+)?([eE]-?[0-9]+)? Viel komplizierter wird es in der Praxis nur selten !

7.4 Endliche Automaten Wie wir gesehen haben, lassen sich die Grundelemente einer Programmiersprache, die Token, durch reguläre Ausdrücke formal beschreiben. Es gibt nun eine zweite äquivalente Beschreibungsart, die zudem der Ausgangspunkt für eine maschinelle Überprüfung von Wörtern bezüglich gegebener regulärer Ausdrücke ist: Endliche Automaten. Diese sind Gegenstand dieses Unterkapitels Inhalt Definition Graphische Darstellung Funktionsweise Beispiel: NEA, DEA Automaten und reguläre Ausdrücke

7.4.1 Definition Definitionen Ein endlicher Automat M ist ein 5-Tupel M = (Z, S, d, z0, E) mit: Z ist eine endliche Menge der Zustände S ist das Eingabealphabet mit Z  S = d : Z x S  Z ist die Überführungsfunktion z0 ist der Startzustand E  Z ist die Menge der Endzustände Ist in d die Wertemenge Z eindeutig für alle Zustände und Zeichen und ist   Z ( ist das “leere” Zeichen), so nennt man den Automaten deterministisch ansonsten Indeterministisch. Die von M akzeptierte Sprache L(M) ist definiert als: L(M) = {x  S* | z0 geht mit x in einen Zustand aus E über}

7.4.2 Graphische Darstellung Ein endlicher Automat kann als gerichteter Graph dargestellt werden: Die Zustände werden als Knoten repräsentiert Die Überführungsfunktion wird als Kanten dargestellt Der Anfangszustand wird mit einem eingehenden Pfeil markiert Die Endzustände werden mit einem zweiten Kreis umringt z1 z2 z3 z0 a b M = { Z = z0, z1, z2, z3, S = a,b, d = (z0,b,z3), (z0,a,z1), (z1,b,z0), (z1,a,z2), (z2,b,z1), (z2,a,z3), z0, E = z3, }

7.4.3 Funktionsweise Der endliche Automat versucht, ein Eingabewort, also eine Sequenz von Eingabezeichen, zu „akzeptieren“. Der Automat befindet sich anfänglich im Eingangszustand zo Jetzt werden das Wort, Buchstabe für Buchstabe im Automat verarbeitet. Dabei ergibt ein aktueller Zustand und der gerade gelsenen Buchstabe über die Überführungsfunktion einen Folgezustand, der dann der aktuelle Zustand für den Folgebuchstaben wird. Das Wort ist akzeptiert, wenn sich der Automat nach der Verarbeitung des letzten Buchstabens in einem Endzustand befindet Das Wort ist nicht akzeptiert, wenn sich der Automat nach der Verarbeitung des letzten Buchstabens nicht in einem Endzustand befindet, oder die Übergangsfunktion bei der Abarbeitung keinen Wert für einen aktuellen Zustand und das zugehörige aktuell gelesene Zeichen findet. Beispiel: Der Automat des vorangegangen Beispiels akzeptiert z.B. b,aaa,abaa, ... Er akzeptiert nicht: aa (kein Endzustand), aab ( b in Z2 nicht definiert)

7.4.3 Beispiel: NEA, DEA Beispiel eines nichtdeterministischen endlichen Automaten (NEA) Beispiel eines (äquivalenten) deterministischen endlichen Automaten (DEA) Jeder indeterministische endliche Automat lässt sich in einen deterministischen endlichen Automaten (automatisch) umformen, der die gleiche Sprache akzeptiert (also L(NEA) = L(DEA) ) z1 z2 z3 z0 a b  a z0 a z1 b z2 z3

7.4.3 Automaten und reguläre Ausdrücke Satz: Die Menge der regulären Sprachen ist identisch mit der Menge, der von endlichen Automaten akzeptierten Sprachen. Beweisidee: Für jeden endlichen Automaten gibt es einen regulären Ausdruck, der die vom Automaten akzeptierte Sprache beschreibt. Umgekehrt gibt es für jeden regulären Ausdruck einen endlichen Automaten, der die durch den regulären Ausdruck beschriebenen Sprache akzeptiert. Beweis durch Konstruktion eines Automaten aus einem regulären Ausdruck und umgekehrt ( Compilerbau, 4. Semester) Beispiel: (a|bc)* z0 a b z2 c 

7.5 Grammatiken Die Grundsymbole einer Programmiersprache, die deren lexikalische Struktur definieren, lassen sich mit Hilfe regulärer Ausdrücke beschreiben und mit endlichen Automaten überprüfen. Reguläre Sprachen bzw. endl. Automaten sind aber nicht mächtig genug, komplexere Strukturen wie z.B. syntaktische Strukturen einer Programmiersprache zu beschreiben. Dieses Unterkapitel stellt nun eine Beschreibungsform vor, die auch (bestimmte) komplexere Strukturen, wie sie typisch für Programmiersprachen sind, zu beschreiben vermag: Grammatiken. Inhalt Beispiel aus der deutschen Sprache Definitionen Notationen Chomsky Hierarchie

7.5.1 Beispiel: Deutsche Sprache Ein Satz ist eine Folge von Subjekt Prädikat und möglicherweise Objekt, abgeschlossen mit einem Punkt (".") Ein Subjekt ist ein Eigenname oder ein Artikel, gefolgt von einem Substantiv Ein Prädikat ist ein Verb Ein Objekt ist ein Artikel, gefolgt von einem Substantiv Eigenname: Adam, Eva Verb: ißt, beißt Artikel: der, die Substantiv: Apfel, Schlange Grammatik: Nichtterminalsymbole und Terminalsymbole bilden die Elemente Regeln zu deren Verwendung Ein Startsymbol (Satz)

7.5.1 Beispiel: Notation Beispiel Ein Satz ist eine Folge von Subjekt Prädikat und möglicherweise Objekt, abgeschlossen mit einem Punkt (".") <Satz> := <Subjekt> <Prädikat> [<Objekt>] . Ein Subjekt ist ein Eigenname oder ein Artikel, gefolgt von einem Substantiv <Subjekt> :=(<Eigenname> | <Artikel>) <Substantiv> Ein Prädikat ist ein Verb <Prädikat> := <Verb> Ein Objekt ist ein Artikel, gefolgt von einem Substantiv <Objekt> := <Artikel><Substantiv> Eigenname: Adam, Eva <Eigenname> := "Adam" | "Eva" ....

7.5.1 Beispiel: Ein „Wort“ der Sprache <Satz> := <Subjekt> <Prädikat> <Objekt> <Subjekt> := <Artikel> <Attribut> <Substantiv> <Artikel> := e | der | die | das <Attribut> := e | <Adjektiv> | <Adjektiv> <Attribut> <Adjektiv> := kleine | bissige | große <Substantiv> := Hund | Katze <Prädikat> := jagt | sieht <Objekt> := <Artikel> <Attribut> <Substantiv> Ableitungsbaum: <Satz> <Subjekt> <Prädikat> <Objekt> <Artikel> <Attribut> <Substantiv> <Adjektiv> der kleine bissige Hund jagt die große Katze

7.5.2 Definitionen Eine Grammatik G ist ein 4-Tupel G = (N, T, P, S) mit: N ist eine endliche Menge, die Menge der Nichtterminalen T ist eine endliche Menge, das Terminalalphabet mit NT= P ist eine endliche Menge von Regeln oder Projektionen mit P ist eine Teilmenge von (NT)+  (N T)* die Grammatik heißt kontextfrei, wenn gilt: P ist eine Teilmenge von N  (N T)* S  N ist das Startsymbol ein Wort v ist direkt ableitbar aus u (notiert: u  v) , wenn gilt: u = xyz, v = xy’z (x,y Worte); y := y’ ist Regel in P ein Wort w ist ableitbar aus u (notiert: u  w), wenn gilt: u  u1  u2  …  w (u1,u2,… Worte) Die von G dargestellte Sprache L(G) ist definiert als: L(G) = {w  T* | S  w } (S : Startsymbol) 1 1 1 1 1

7.5.2 Definition: Beispiel Eine Grammatik G ist ein 4-Tupel G = (<N>, T, P, S) mit: N ist eine endliche Menge, die Menge der Nichtterminalen T ist eine endliche Menge, das Terminalalphabet mit NT= P ist eine endliche Menge von Regeln oder Projektionen mit P ist eine Teilmenge von (NT)+  (N T)* die Grammatik heißt kontextfrei, wenn gilt: P ist eine Teilmenge von N  (N T)* S  N ist das Startsymbol Aus unserem Beispiel <Satz> := <Subjekt> <Prädikat> <Objekt> <Subjekt> := <Artikel> <Attribut> <Substantiv> <Artikel> := e | der | die | das <Attribut> := e | <Adjektiv> | <Adjektiv> <Attribut> <Adjektiv> := kleine | bissige | große <Substantiv> := Hund | Katze <Prädikat> := jagt | sieht <Objekt> := <Artikel> <Attribut> <Substantiv>

7.5.2 Definition: Beispiel G = ( ) N= { <Satz>, <Subjekt>, <Prädikat>, <Objekt>, <Artikel>, <Attribut>, <Substantiv>, <Adjektiv>} T= { kleine, bissige, große, Hund, Katze, jagt, sieht} P = { <Satz> := <Subjekt> <Prädikat> <Objekt> <Subjekt> := <Artikel> <Attribut> <Substantiv> <Artikel> := e | der | die | das <Attribut> := e | <Adjektiv> | <Adjektiv> <Attribut> <Adjektiv> := kleine | bissige | große <Substantiv> := Hund | Katze <Prädikat> := jagt | sieht <Objekt> := <Artikel> <Attribut> <Substantiv> } S = <Satz> )

7.5.2 Definition: Beispiele G = { N,T,P,A }, N = { A,B,C }, T = { a,b,c }, P = { A:=aAa, A:=BC, B:=bbB, B:=BC, B:=e, C:=Cc, C:=c } a2b2c3 a2  L(G) a4 b2 c b2 c a4  L(G) G = { N,T,P,S }, N = { A,B,C,S }, T = { a,b,c }, P = { S:=ABC, A:=ABA, C:=CBC, A:=a, B:=b, C:=c } {wT* | w= (ab)nac(bc)n, n>=1} = L(G) b2a2c3  L(G) G = { N,T,P,S }, N = { A,B,C,S }, T = { a,b,c }, P = { S:=ABC, A:=Aa, A:=a, B:=bBc, B:=b, C:=c } {wT* | w= anbncn, n>1}  L(G) a3b2c2  L(G) a2b2c3  L(G) …

7.5.3 Notationen: BNF / EBNF Die BNF (John Backus, Peter Naur, 1960) ist die Grundform und entspricht der Definition eventuell erweitert um den alternativ-Operator (“|”)  siehe Beispiele Die EBNF erweitert die BNF um 3 (2) Operatoren den Alternativ Operator: | den Wiederholungs-Operator: { … } Notiert auf der rechten Seite einer Regel, drückt er aus, dass der geklammerter Ausdruck beliebig oft wiederholt werden kann - einschließlich kein mal. Teilweise wird die minimal und maximal mögliche Anzahl von Wiederholungen zusätzlich notiert: { … } der Optional-Operator: [ … ] Notiert auf der rechten Seite einer Regel, drückt er aus, dass der geklammerter Ausdruck ein oder keinmal wiederholt werden kann, also optional ist. Es lässt sich zeigen, dass beide Notationen gleich mächtig sind, dass sich also BNF notierte Grammatiken auch in EBNF notieren lassen (trivial) und umgekehrt (wie ?) max min

7.5.3 Notationen: Syntaxdiagramme Syntaxdiagramme sind eine einfache graphische Repräsentation der syntaktischen Struktur: Konkatenationen werden durch Sequenzen, Alternativen durch Verzweigungen, Wiederholungen durch Rückkopplung dargestellt. Elemente sind Terminale und Nichtterminale Unser Beispiel (vereinfacht) im Syntaxdiagramm <Satz> = <Subjekt> <Prädikat> [<Objekt>] . <Subjekt> = <Eigenname> | <Artikel> <Substantiv> <Prädikat> = <Verb> <Objekt> = <Artikel><Substantiv> <Eigenname> = "Adam" | "Eva" Satz: Eigename Artikel Substantiv Verb . Eigenname: Adam Eva

7.5.4 Chomsky Hierarchie Grammatiken - und damit die von ihnen definierten Sprachen - bilden eine Hierachie von “Mächtigkeiten” Typ 0 rekursiv aufzählbar Keine Einschränkung Typ 1 kontextsensitiv Linke Seite aller Regeln kürzer/gleich als rechte Typ 2 kontextfrei zusätzlich: linke Seite aller Regeln ein Nichtterminal Typ 3 regulär zusätzlich: rechte Seite beginnt mit Terminal Eine Sprache L heißt vom Typ x (x=0,1,2,3), falls es eine Typ x Grammatik G gibt mit L(G) = L Reguläre Ausdrücke beschreiben Typ 3-Sprachen, kontextfreie Grammatiken beschreiben Typ 1-Sprachen Typ 0-Sprachen Typ 1-Sprachen Typ 2-Sprachen Typ 3-Sprachen nicht entscheidbar entscheidbar, aber zu komplex entscheidbar mit endl. Automat mit Stack entscheidbar mit endl. Automat

7.5.4 Chomsky Hierarchie: Beispiel Aus den Teilmengenbeziehungen der Chomsky-Hierarchie lässt sich also insbesondere ableiten dass alle Sprachen, die sich mit regulären Ausdrücken beschreiben lassen auch durch kontextfreie Grammatiken darstellen lassen dass sich nicht notwendigerweise alle durch Grammatiken darstellbaren Sprachen auch durch reguläre Ausdrücke beschreiben lassen Endlicher Automat Grammatik z1 z2 z3 z0 a b <start> := <ab>b|a<ba>a<ba>a <ab> := e | ab | ab<ab> <ba> := e | ba | ba<ba>

7.6 Zusammenfassung des Kapitels Programmiersprache Was ist eine Programmiersprache / ein Programm Generationen von Programmiersprachen / Programmiersprachen heute Syntax und Semantik Syntax vs. Semantik Syntax / Semantik Reguläre Ausdrücke Definitionen: reguläre Ausdrücke und reguläre Sprachen UNIX-Notation Endliche Automaten Definition, Graphische Darstellung und Funktionsweise Automaten und reguläre Ausdrücke Beispiel aus der deutschen Sprache Definition und Notationen Chomsky Hierarchie

Übungen

Übung 2.1 Information Wieviele Fragen benötigen Sie beim „Zahlenraten“ um eine aus 100 Zahlen zu erraten um eine aus n Zahlen zu erraten Eine Nachrichtenquelle sendet Zeichen aus dem Alphabet X = {a,b,c,d} mit den Wahrscheinlichkeiten p(a)=1/4, p(b)=p(c)=1/8 Berechnen Sie die Entropie der Quelle Wie groß ist der Informationsgehalt der Nachricht „abcd“ Wie groß ist der mittlere Informationsgehalt der Nachricht „abcd“ Wie groß ist der mittlere Informationsgehalt einer Nachricht mit 1000 Zeichen Wie groß ist der Informationsgehalt einer Nachricht mit 1000 Zeichen unter der Annahme, dass alle Zeichen gleich wahrscheinlich sind.

Übung 2.2 Huffmann Berechnen Sie Informationsgehalt jedes Symbols Mittlerer Informations-gehalt des Alphabets Huffmann Codierung Redundanz Ihres Huffmann-Codes relative Redundanz Ihres Huffman-Codes des Alphabets der deutschen Sprache (siehe Tabelle) Tip: Verwenden Sie eine Tabellenkalkulation Buchstabe Häufigkeit in % Buchstabe Häufigkeit in% Buchstabe Häufigkeit in % a 6,51 j 0,27 s 7,27 b 1,89 k 1,21 t 6,15 c 3,06 l 3,44 u 4,35 d 5,08 m 2,53 v 0,67 e 17,40 n 9,78 w 1,89 f 1,66 o 2,51 x 0,03 g 3,01 p 0,79 y 0,04 h 4,76 q 0,02 z 1,13 i 7,55 r 7,00    

Übung 2.3 Hamming Bestimmen Sie Die Hamming-Distanz des ASCII-Codes Welche Bitfehler sind erkennbar ? Welche Bitfehler sind korrigierbar ? Bestimmen Sie die Hamming-Distanz der nach der Hamming-Methode kodierten Codewörter. Betrachten Sie dabei zunächst nur die Codewörter für 0000 bis 1111 Betrachten Sie den mit der Hamming-Methode codierten Code für „1000“ Kippen sie jedes Bit je einmal und bestimmen sie das gekippte Bit mit der Hamming-Methode. Was passiert, wenn zwei Bits gekippt sind - verdeutlichen Sie dies anhand eines Beispiels.

Übung 3.1 Zahlensysteme Die Duodezimalindianer haben zwölf Finger Berechnen Sie nach dem Zahlensystem der Duodezimalindianer die wichtigsten Werte des täglichen Lebens: 300g Pizza Eine Flasche Bier (0,5 bzw. 0,33 Liter) ALDI 2.95 € Konvertieren Sie die obigen Werte auch in Bin, Hex und Okt Grundrechenarten (verwenden Sie keinen Rechner) Berechnen Sie 568110 / 1910 Konvertieren Sie 568110 und 1910 ins Binärsystem Dividieren Sie die Binärdarstellungen der beiden Zahlen Machen Sie die Gegenprobe im Binärsystem Konvertieren Sie 0,110 ins Binärsystem mit der Restwertmethode Addieren Sie paarweise alle Zahlen von -3 bis +4 (26 Additionen), verwenden Sie dabei die Darstellung negativer Zahlen im Zweierkomplement.

Übung 3.2 Gebrochene Zahlen (optional) Programmieren Sie in PHP4/HTML-Forms einen Konverter zur Konvertierung ganzer und gebrochener Zahlen zwischen beliebigen Zahlensystem und zur Darstellung im IEEE 754 float und double Format. Stellen Sie  als IEEE 754 float-Zahl dar (optional) als IEEE 754 double-Zahl dar Geben Sie im Binärsystem und Dezimalsystem den größt- bzw. kleinst-möglichen positiven bzw. negativen Wert einer float-Zahl an (für IEEE 754 float)

Übung 3.3 IEEE 754 (optional) Betrachten sie das Programm konvd auf der GDI-Website (www.prof-kneisel.de -> Lehre -> GDI (Tabelle: Sonstiges)) Bestimmen Sie (durch Ausprobieren) Vorzeichenbit, Exponentenbits, Mantissenbits Bias Für die Datentypen Extended Double Currency Single Bemerkung: Die im Programm konvd dargestellten Werte entsprechen den Binärrepräsentationen von Borlands Delphi-Datentypen.

Übung 4.1 Strukturierte Datentypen Formen Sie die „Kneisel“-Notation und die Beispiele aus Kapitel 4.3 in C++ - Notation um. Beschreiben Sie Gemeinsamkeiten und Unterschiede von „Datenstruktur“, „Datentyp“ und „Variable“. Was sind die Vor- und Nachteile von Arrays gegenüber verketteten Listen Definieren Sie einen Datentyp für das Objekt „Schachspiel“. Berücksichtigen Sie dabei z.B. die Namen der Spieler, alle Züge, den Gewinner, ... Betrachten Sie den Stundenplan auf meiner Homepage Skizzieren Sie einen Datentyp für das Objekt „Stundenpläne“ Welchen Speicherplatz benötigt eine Variable dieses Typs ? An welchen Stellen sehen Sie Alternativen zu Ihrer Typdefinition ?

Übung 4.2 Abstrakte Datentypem Definieren Sie den Datentyp für eine einfach verkettete Liste (die Datenwerte seien vom Typ: integer) doppelt verkette Liste (die Datenwerte seien vom Typ: integer) <int> <int> <int> <int> <int> <int> ... ... Definieren Sie den Datentyp für ein beliebiges Netz - siehe Bild der Datenwert jedes Knotens sei vom Typ integer die maximale Anzahl von Nachfolgeknoten sei begrenzt) <int> <int> <int> <int> <int> <int> <int> <int> <int>

Übung 5.1 Schleifen Konstruieren Sie (beliebig) und wandeln Sie um ... eine „While“-Schleife in eine „Do-While“-Schliefe eine „Do-While“-Schleife in eine „While“-Schleife Formulieren Sie Ihr Vorgehen für allgemeine „While“- und „Do-While“-Schleifen, mit Bedingungen B und Aktionen.A. Betrachten Sie Ihre konstruierte „While“-Schleife Wandeln Sie diese in einen Algorithmus mit Sprung-Befehlen um. Formulieren Sie Ihr Vorgehen für allgemeine „While“-Schleifen, mit Bedingungen B und Aktionen.A. Betrachten Sie Ihre konstruierte „Do-While“-Schleife. Formulieren Sie Ihr Vorgehen für allgemeine „Do-While“-Schleifen, mit Bedingungen B und Aktionen.A.

Übung 5.2 Spiel des Lebens Das Spiel des Lebens findet in einer Welt statt, die einfachen Regeln gehorcht. Die Welt besteht aus einem unendlich großen Schachbrett in dessen Feldern primitive Tierchen, die “Nöpel” wohnen. Diese sitzen ein Jahr unbeweglich auf ihren Feldern, unterhalten sich mit ihren Nachbarn - es gibt erhitzte Diskussionen, Gedichtvorträge, Tratsch und Klatsch über andere Nöpel, politische Reden, Deklamationen, Verleumdungen und Schmeicheleien. Jedes Jahr genau um 12 Uhr in der Silvesternacht lösen sich Nöbel entweder in Luft auf, bleiben sitzen oder werden aus dem Nichts erschaffen. Dabei schlägt das Schicksal nicht blind zu: Hat ein Nöpel (von acht möglichen) keinen oder nur einen Nachbarn, so stirbt er an Vereinsamung. Hat ein Nöpel vier oder mehr Nachbarn, so stirbt er an Erschöpfung ob der vielen Plaudereien. Überleben tun Nöbel mit zwei und drei Nachbarn. Nöpel werden auf leeren Feldern geboren, wenn dort im Jahr zuvor genau drei Nöpel gelebt haben

Übung 5.2 Die Generationen 0,1,4,5,6,7,8 2,3 3

Übung 5.2 Interessante Völker Der Gleiter Der Blinker

Übung 5.2 Spiel des Lebens Überlegen Sie sich Rahmenbedingungen für das Spiel des Lebens (Anhang B) Formalisieren Sie dieses Problem Stellen sie einen umgangssprachlichen Lösungsansatz auf Formalisieren Sie den Lösungsansatz als Algorithmus Spielen Sie den Algorithmus anhand eines Beispieles durch Bewerten Sie den Algorithmus bezüglich seine Laufzeit und seines Platzbedarfes optional: Programmieren Sie dieses Spiel

Übung 5.3 Rekursion Programmieren Sie die Fakultätsfunktion Optional: Rekursiv Iterativ Ermitteln Sie die Laufzeiten beider Varianten in Abhängigkeit von n und stellen Sie diese tabellarisch dar. Optional: Programmieren Sie für das „Weg des Springers“-Problem ein Programm mit Backtracking. Entwickeln Sie unterschiedliche Heuristiken zur Realisierung des „waehleKandidat“-Blockes. Zeigen Sie, durch Berechnung der ersten n Lösungen, welche Heuristik die erfolgreichste ist.

Übung 5.4 Acht Damen Problem Das acht Damen Problem: Acht Damen sind so auf einem Schachbrett aufzustellen, dass keine Dame eine andere bedroht: Eine mögliche Lösung: Formulieren Sie einen rekursiven Algorithmus zur Lösung des Acht- Damen Problems. Programmieren Sie den Algorithmus

Übung 6.1 Turing-Maschine Machen Sie sich mit der Funktionsweise des „Busy Beaver“-Programms vertraut Vollziehen sie die 11 Schritte der ersten Turing-Tabelle. Versuchen Sie sich selbst am Turing Simulator der IGS (Link auf meiner Homepage) Entwerfen Sie eine Turing-Maschine zur Multiplikation zweier natürlicher Zahlen.

Übung 6.2 Einfache Verifikation Gegeben ist folgender Algorithmus {a<0, b>0, c>0} // Vorbedingung P(a,b,c) a=b; d=b-a; if (c == 0) then d=5; else d=d+1; Geben Sie eine Nachbedingung Q(d) für die Variable d an Beweisen Sie dass sich durch den Algorithmus aus P(a,b,c) diese Nachbedingung Q(d) ableiten lässt Schreiben Sie einen zweiten Algorithmus, der ebenfalls die Nachbedingung Q(d) aus P(a,b,c) ableiten kann Verifizieren Sie Ihren Algorithmus

Übung 6.3 Denksportaufgabe Gegeben sei folgendes Verfahren In einem Topf seien s schwarze und w weiße Kugeln - insgesamt mindestens eine. Solange mindestens zwei Kugeln im Topf sind, nimm zwei beliebige Kugeln heraus. Falls Sie gleiche Farbe haben, wirf beide weg und lege eine neue schwarze Kugel in den Topf. Falls sie verschiedene Farben haben, wirf die schwarze weg und lege die weiße zurück in den Topf. Welche Farbe hat die letzte Kugel Welche Aussage - die einen Hinweis auf die Antwort gibt - gilt vor, in und nach der Schleife (Invariante) Terminiert die Schleife ? Begründen Sie ihre Antwort. 

Übung 6.4 Invariante Betrachten Sie nochmals das Verfahren aus der vorgegangenen Übung: In einem Topf seien s schwarze und w weiße Kugeln - insgesamt mindestens eine. Solange mindestens zwei Kugeln im Topf sind, nimm zwei beliebige Kugeln heraus. Falls Sie gleiche Farbe haben, wirf beide weg und lege eine neue schwarze Kugel in den Topf. Falls sie verschiedene Farben haben, wirf die schwarze weg und lege die weiße zurück in den Topf. Beschreiben Sie das Verfahren als Algorithmus Das „Nehmen“ dürfen Sie als Block voraussetzen. Entwerfen Sie den Kopf dieses Blocks, Beschreiben Sie seine Parameter beschreiben Sie sein Verhalten in Form einer Vor- und Nachbedingung Bestimmen Sie die Invariante Beweisen Sie die Korrektheit Ihrer Nachbedingung

Übung 6.5 Vollständige Verifikation gegeben ist der folgende Algorithmus zum schnellen Potenzieren (Legendre Algorithmus) // Vorbedingung P(V): a>0  b0 x = a; y = b; z = 1; while y > 0 { if odd(y) then z = z*x; y = y div 2; // Ganzzahldivision x = x*x; } Was ist die Nachbedingung dieses Algorithmus Bestimmen die die Schleifeninvariante Beweisen Sie die Korrektheit de Legendre Algorithmus

Übung 6.6 Schranken Angenommen, Ihr Algorithmus habe einen Aufwand von g(n) = 5n3 + n + 1000 für alle n Geben sie eine obere Schranke O(g(n)) an. Beweisen Sie, dass ihre Schranke tatsächlich eine obere Schranke ist. Konstruieren Sie einen Graphen fü die beiden Funktionen g(n) O(g(n) so, dass der Schnittpunkt deutlich wird. Geben Sie eine untere Schranke an Sie haben zusätzlich einen Algorithmus mit O(2n) Aufwand. Vergleichen Sie diesen Algorithmus mit dem Algorithmus aus 1. Welches ist der „schnellere“ Algorithmus ? Begünden Sie Ihre Antwort quantitativ

Übung 6.7 O-Notation gegeben seien folgende Werte: 1,3,4,8,9,15,17,25,28,29,31,36,41,45 Zeichnen Sie einen sortierten Baum minimaler Tiefe, der mit den gegeben Werten belegt ist. Schreiben Sie einen Algorithmus, der den Baum aufspannt (als Wiederholungs-Übung von Zeigern) Gegeben ist der Suchalgorithmus aus „Häufige O-Ausdrücke: O(log n)“. Geben Sie für jeden Wert an, wie oft der Block durchlaufen wird Formulieren Sie einen iterativen Algorithmus mit O(n4) Geben Sie eine kurze rechnerische Begründung für Ihre Antwort

Übung 6.8 Aufwand Gegeben ist folgender Algorithmus: do (list:*liste) { i:integer; for i=1 to no_of_elements(list) { remove_last_element(list); do (list) // call list with one element less } Geben Sie den Aufwand an. Belegen Sie Ihre Antwort rechnerisch Gegeben ist folgender Algorithmus for i=1 to n { j=1; while (j<i) { j = j+2; } }

Übung 7.1 Syntax und Semantik Geben Sie Beispiele für lexikalische Strukturelemente syntaktische Strukturelemente der Programmiersprache C++ an Formulieren Sie die Semantik einer while-Schleife eines Unterprogrammaufrufes in C++ recherchieren Sie nach weiteren Programmiersprachen

Übung 7.2 Reguläre Ausdrücke Geben Sie reguläre Ausdrücke für Integerliterale Die Schlüsselwort: while, function, if in C++, jeweils in „klassischer“ und in UNIX-Notation an Geben Sie einen regulären Ausdruck zu folgenden Sprachen an: Alle Folgen von Großbuchstaben, die jeden Vokal genau einmal in alphabetischer Reihenfolge enthält: Bsp.: SDFKJHZZTADGFPMNBEHGQIQWGFMNOLKHYXUQSKJH Alle Dualziffernfolgen, die „001“ nicht als Teilfolge enthalten Gegenbsp.: 10011100101010000 Welche Sprachen sind durch die folgenden regulären Ausdrücke definiert ? (0?|1*)* (0|1)*0(0|1)(0|1) /\*((\*[^/])|[\*])*\*/

Übung 7.3 Grammatiken gegeben ist folgende Grammatik G: G = { N,T,P,S }, N = { A,B,C,S }, T = { a,b,c }, P = { S:=ABC, A:=ABA, C:=CBC, A:=a, B:=b, C:=c } Ist die Grammatik kontextfrei ? Begründen Sie Ihre Antwort Beweisen Sie: abababcbc  L(G) Begründen sie verbal, weshalb b2a2c3  L(G) Geben Sie einen regulären Ausdruck R an mit L(R) = L(G) Welchem Typ der Chomsky-Hierachie entspricht die Sprache, die durch G definiert ist ? Ist die Sprache L(G) vom Chomsky-Typ-0 ? Begründen Sie Ihre Antwort

Lösung 2.1 Information Wieviele Fragen benötigen Sie beim „Zahlenraten“ 7 nächste_ganze_Zahl_größer( ld n) Eine Nachrichtenquelle sendet Zeichen aus dem Alphabet X = {a,b,c,d} mit den Wahrscheinlichkeiten p(a)=1/4, p(b)=p(c)=1/8 H(x) = p(x) *h(x) = ((1/4*2)+(1/8*3)+(1/8*3)+(1/2*1)) bit = 1,75 bit (2+3+3+1) bit = 9 bit 4 * 1,75 bit = 7 bit 1000 * 1,75 bit = 1750 bit 1000 * H(x) = 1000 * (4 * (1/4 * 2 bit)) = 2000 bit

Lösung 2.2 Huffmann siehe Tabelle rechts: h(x) p(x)(in %) h(x) (in Bit) p(x) * h(x) a 6,51 3,94 0,2566 b 1,89 5,73 0,1082 c 3,06 5,03 0,1539 d 5,08 4,30 0,2184 e 17,40 2,52 0,4390 f 1,66 5,91 0,0982 g 3,01 5,05 0,1521 h 4,76 4,39 0,2091 j 7,55 3,73 0,2814 j 0,27 8,53 0,0230 k 1,21 6,37 0,0771 l 3,44 4,86 0,1672 m 2,53 5,30 0,1342 n 9,78 3,35 0,3280 o 2,51 5,32 0,1334 p 0,79 6,98 0,0552 q 0,02 12,29 0,0025 r 7,00 3,84 0,2686 s 7,27 3,78 0,2749 t 6,15 4,02 0,2474 u 4,35 4,52 0,1967 v 0,67 7,22 0,0484 w 1,89 5,73 0,1082 x 0,03 11,70 0,0035 y 0,04 11,29 0,0045 z 1,13 6,47 0,0731 Lösung 2.2 Huffmann siehe Tabelle rechts: h(x) mittlerer Informationsgehalt: H(x) = 4,06 bit Redundanz bei 8bit-Kodierung (z.B. ASCII mit Parity-Bit): R = L-H = 8 bit - 4,06 bit = 3,94 bit r = R/L = 0,49

Lösung 2.2 Huffmann c) Beispiele: a 0101 b 000010 c 01000 d 1111 e 001   p(x) (in %) a 6,51 b 1,89 c) Beispiele: a 0101 b 000010 c 01000 d 1111 e 001 f 000001 ... c 3,06 q x o w m g d 5,08 e 17,40 qx (0,05) y ow (4,40) u gm (5,54) t h d f 1,66 g 3,01 qxy (0,09) j ouw (8,75) n gmt (11,69) dh (9,84) h 4,76 ... ... ... ... i 7,55 jqxy (0,36) v nouw (18,53) dghmt (21,53) j 0,27 o 1 k 1,21 jqvxy (1,03) p z k dghmntouw (40,06) l 3,44 jqpvxy (1,82) f b kz (2,34) m 2,53 n 9,78 fjqpvxy (3,48) bkz (4,23) c l o 2,51 p 0,79 bfjkqpvxyz (7,71) i cl (6,50) a r s 1 q 0,02 ... o r 7,00 bfijkqpvxyz (15,26) e acl (13,01) rs (14,27) s 7,27 o ... ... ... t 6,15 befijkqpvxyz (32,66) aclrs (27,28) u 4,35 o 1 v 0,67 abcefijklqprsvxyz (59,94) o w 1,89 x 0,03 Die Bezeichnung der Kanten mit 0 oder 1 ist willkürlich y 0,04 z 1,13

Lösung 2.2 Huffmann H(x) = 4.,06 bit L = 4,1 bit R = L-H = 0,04 bit p(x) (in %) l(x) p(x)*l(x) a 6,51 4 0,2604 b 1,89 6 0,1134 c 3,06 5 0,1530 d 5,08 4 0,2032 e 17,40 3 0,5220 f 1,66 6 0,0996 g 3,01 5 0,1505 h 4,76 4 0,1904 j 7,55 4 0,3020 j 0,27 9 0,0243 k 1,21 7 0,0847 l 3,44 5 0,1720 m 2,53 5 0,1265 n 9,78 3 0,2934 o 2,51 5 0,1255 p 0,79 7 0,0553 q 0,02 11 0,0022 r 7,00 4 0,2800 s 7,27 4 0,2908 t 6,15 4 0,2460 u 4,35 4 0,1740 v 0,67 8 0,0536 w 1,89 5 0,0945 x 0,03 11 0,0033 y 0,04 10 0,0040 z 1,13 7 0,0791 Lösung 2.2 Huffmann H(x) = 4.,06 bit L = 4,1 bit R = L-H = 0,04 bit r = R/L = 0,01

Lösung 2.3 Hamming Hamming-Distanz bei ASCII-Code Hamming-Codierung für 0000 - 1111 D=3 (durch Vergleich der Distanz zwischen allen Codes) 2-bit Fehler können erkannt werden 1-bit Fehler können korrigiert werden 0000000 1001011 0000111 1001100 0011001 1010010 0011110 1010101 0101011 1100001 0101100 1100110 0110011 1111000 0110100 1111111

Lösung 2.3 Hamming Betrachten Sie den mit der Hamming-Methode codierten Code für „1000“ 1001011 P-Bits falsch => Fehler bei bit 1001010 1 1 1001001 2 2 1001111 1,2 3 1000011 4 4 1011011 1,4 5 1101011 2,4 6 0001011 1,2,4 7 Kippen von Bit 1 und Bit 6: 1101010 1,2,4 7 es wird ein Fehler erkannt (gut !). Allerdings wird der Fehler bei Bit 7 erkannt, wobei der Code bei der Korrektur also fälschlicherweise zu 0101010 korrigiert wird, statt zu 1001011

Lösung 3.1 Zahlensysteme Die Duodezimalindianer haben zwölf Finger Berechnen Sie nach dem Zahlensystem der Duodezimalindianer die wichtigsten Werte des täglichen Lebens: 21012g Pizza Eine Flasche Bier (0,612 bzw. ca. 0,3B62A68781B05912 Liter) ALDI ca. 2,B4972497249724 € Bin: 100101100 0,1 0,01010100011110101110000 10,111100 Okt: 454 0,4 0,25075341217270243 2,74631 Hex: 12C 0,8 0,547AE147AE145 2,F333333

Lösung 3.1 Zahlensysteme Grundrechenarten 568110 : 1910 = 299 1011000110001 : 10011 = 100101011 38 10011 188 00011001 171 10011 171 0011010 171 10011 000 11100 10011 10011 10011 00000 100101011 * 10011 100101011 100101011 100101011 1011000110001

Lösung 3.1 Zahlensysteme 0,110 2 · 0,1 = 0,2 --> Ziffer: 0 2 · 0,2 = 0,4 --> Ziffer: 0 2 · 0,4 = 0,8 --> Ziffer: 0 2 · 0,8 = 1,6 --> Ziffer: 1 2 · 0,6 = 1,2 --> Ziffer: 1 2 · 0,2 = 0,4 --> Ziffer: 0 2 · 0,4 = 0,8 --> Ziffer: 0 2 · 0,8 = 1,6 --> Ziffer: 1 ... Also: 0,000110011001100... 44 65 72 20 42 61 6C 6C 20 69 73 74 20 72 75 6E 64 2E ASCII: Der Ball ist rund. LongInt 1147499040 1113681004 543781748 544372078 1680736256 (mit 0en aufgefüllt) ......

Lösung 3.1 Zahlensysteme Subtraktion durch Addition des Zweierkomplementes 0 -1 -2 -3 0000 1111 1110 1101 4 0100 0100 (1)0011 (1)0010 (1)0001 3 0011 0011 (1)0010 (1)0001 (1)0000 2 0010 0010 (1)0001 (1)0000 1111 1 0001 0001 (1)0000 1111 1110 0 0000 0000 1111 1110 1101 -1 1111 1111 (1)1110 (1)1101 (1)1100 -2 1110 1110 (1)1101 (1)1100 (1)1011 -3 1101 1101 (1)1100 (1)1011 (1)1010 -4 1100 -5 1011 -6 1010

Lösung 3.2 Gebrochene Zahlen  = 3,14159265358979311...10 = 11,00100100001111110110101010001000100001011010001100...2 Mantisse Exponent 0,1100100100001111110110102 * 22 VEEEEEEEEMMMMMMMMMMMMMMMMMMMMMMM 01000000010010010000111111011010 Maximalwerte (bei bias = 126): größte negative 1 11.10 111...11  - 1 * 2127 kleinste negative 1 00..0 000...01 = - 2-23 * 2-126 = - 2-149 kleinste positive 0 00..0 000...01 = 2-23 * 2-126 = 2-149 größte positive 0 11.10 111...11  1 * 2127 Number sign exponent mantissa normalized number 0/1 01 to FE any value denormalized number 0/1 00 any value

Lösung 3.3 IEEE 754

Lösung 4.1 Strukturierte Datentypen 1. Umformen der „Kneisel“-Notation - Einfache Datentypen bool switch1; switch1 = false; // = 0 switch1 = switch1 && (!switch1); // = 1 and 0 = 0 int i; i = 1; // = 1 i = i + 32;´ // = 1 + 32 = 33 char symbol; symbol = ´A´; // = „A“ symbol = symbol + 32;´ // = „A“ + 32 = „a“ enum ampelfarbe {gruen,gelb,rot}; ampelfarbe = gruen; // = gruen ampelfarbe = ampelfarbe +1 ; ´ // = gruen + 1 = gelb float pi, flaeche, radius; // all real ! pi = 3.141; // needs not to be more accurate radius = 5; // might be changed by user flaeche = 2 * pi * pow(radius,2); // common formula

Lösung 4.1 Strukturierte Datentypen 1. Umformen der „Kneisel“-Notation - Strukturierte Datentypen float m[3][2]; float v[4]; v[2] = 5.03; v[3] = 4.12; m[0][1] = v[2] * 12 - v[3]; struct { int tag; int monat; } d ; d.monat = 10; d.tag = 20; struct { char[20] name; enum {m,f} sex; union { int IQ; real muscle; } } adam, eva; typedef struct Datum {int year; enum month {jan,feb,...}; int day; } Akt_Datum; // Akt_Datum hier struct { char[20] surname; char[20] forename; Datum birthday; } Person; // alternativ: Datum Akt_Datum;

Lösung 4.1 Strukturierte Datentypen siehe Kapitel 4.1 Arrays verkettete Listen maximale Anzahl der Elemente maximale Anzahl der Elemente ist bekannt ist nicht bekannt Elemente nur eines Typs Elemente unterschiedlichen erlaubt Typs (einfacher) möglich Belegung des Speicherbereichs für Belegung nur des tatsächlich maximale Anzahl von Elementen benötigten Speicherbereiches Einfacher Zugriff über Index Zugriff durch Durchlaufen der Liste Einfache Implementierung „Komplexere“ Implementierung Sortierung „nur“ durch Umkopieren Sortierung durch neue Verkettung möglich möglich ... ...

Lösung 4.1 Strukturierte Datentypen 4,5 Es gibt (unendlich) viele Lösungen für die Konstruktion einer Datenstruktur, daher sei hier nur eine mögliche Vorgehensweise beschrieben: Suche alle beteiligten Objekte (z.B. durch Brainstorming) Stelle die Objekte zueinander in Beziehung Ist-Teil-von-Beziehung (Aggregation) ... (bei OO-Sprachen insb.: Erbt von) Stelle die Wertebereiche fest Gibt es „generische“ Objekte ( = grundlegende Objekte, die z.B. in mehrerern Aggregationen vorkommen, auch in anderen Objekten) Bilde „generische Objekte entsprechend Ihrer Aggregationen als Record (oder bei Listenstruktur als Array) ab Bilde das zu modellierende Objekt - auch unter Verwendung der generischen Objekte -als Record (bzw. Liste) ab. Beachte die Vor- und Nachteile dynamischer Strukturen. Eventuell benötigt man aus Effizienzgründen (-> Algorithmik) weitere Hilfsobjekte.

Lösung 4.2 Abstrakte Datentypen in C++ Notation struct list {int value; struct list{ int value; next *list; }; naxt *list; prev *list; } <int> <int> <int> <int> <int> <int> ... ... in C++ Notatioon struct net (int value; next* net[max_succesors]; }; <int> <int> <int> <int> <int> <int> <int> <int> <int>

Lösung 5.1 Schleifen while (x < 5) if (x < 5) then while B if B then { do { { do { x = x + 1;  x = x + 1; A  A } } } } while (x < 5) while B do { x = x + 1; do { A x = x + 1;  while (x < 5) { A  while B { } x = x + 1; } A while (x < 5) } while B } 1: if x >= 5 goto 2 1: if !B goto 2 x = x + 1; A goto 1 goto 1 2: ... 2: ... 1: x = x + 1; 1: A if x < 5 goto 1 if B goto 1 2: ... 2: ...

Lösung 5.2 Spiel des Lebens: Aufgabe Überlegen Sie sich Rahmenbedingungen für das Spiel des Lebens (Anhang B) Formalisieren Sie dieses Problem Gegeben ist: Eine zweidimensionales „Spielfeld“ Annahme: die Grenzen werden verbunden. Auch möglich: „Unendliche“ Grenzen, „abschneidende“ Grenzen Anfangszustand: beliebige Nöpelpositionen im Spielfeld Regeln: entsprechend der Spielregeln für „Spiel des Lebens“ Gesucht: „Zwischenzustand“ nach beliebigen Generation (entsprechend der Regeln) Optional: Erkennung von „Endzuständen“

Lösung 5.2 Spiel des Lebens: Ansätze Stellen sie einen umgangssprachlichen Lösungsansatz auf Entwurf der Datenstrukturen - zwei Ansätze: Der Spielfeldzustand wird als zweidimensionales Feld repräsentiert Der Spielfeldzustand wird über die Positionen der Nöpel präsentiert Entwurf des Algorithmus act_state = Startzustand solange kein Endzustand { get_next_state (act_state, next_state); } zwei entsprechende Ansätze: get_next_state (In: act_state, Out: next_state) Der Spielfeldzustand wird als zweidimensionales Feld repräsentiert: { durchlaufe Felder und setze Nöpel „entsprechend“ } Der Spielfeldzustand wird über die Positionen der Nöpel präsentiert: { durchlaufe Nöpelliste und setze Nöpel „entsprechend“ } Vor- / Nachteile ?

Lösung 5.2 Spiel des Lebens: Feld 0,1,4,5,6,7,8 2,3 3 Lösung 5.2 Spiel des Lebens: Feld a) Der Spielfeldzustand wird als zweidimensionales Feld repräsentiert get_next_state (In: act_state, Out: next_state) { // determine survivors durchlaufe act_state // zweifach-verschachtelte Schleife { falls act_state[act_field] hat 2,3 Nachbarn in act_state setze next_state[act_field] } // determine babies durchlaufe next_state // zweifach-verschachtelte Schleife { falls next_state[act_field] hat 3 Nachbarn in act_state setze next_state[act_field] } }

Lösung 5.2 Spiel des Lebens: Liste 0,1,4,5,6,7,8 2,3 3 Lösung 5.2 Spiel des Lebens: Liste b) Der Spielfeldzustand wird über die Positionen der Nöpel präsentiert get_next_state (In: act_state, Out: next_state) { durchlaufe act_state // einfache Schleife durch Nöpelliste { // determine survivors find_neighbors(act_nöpel, no_of_neighbors) falls no_of_neighbors = 2 oder 3 kopiere act_nöpel nach next_state // determine babies durchlaufe nachbar_nöpel von act_nöpel // max. 8 { find_neighbors(nachbar_nöpel, no_of_neighbors) falls no_of_neighbors = 3 kopiere nachbar_nöpel nach next_state } } }

Lösung 5.2 Spiel des Lebens: Strukturen Stellen sie einen umgangssprachlichen Lösungsansatz auf Entwurf der Datenstrukturen - zwei Ansätze: Der Spielfeldzustand wird als zweidimensionales Feld repräsentiert act_state: array [1..max_reihen][1..max_spalten] of boolean; Der Spielfeldzustand wird über die Positionen der Nöpel präsentiert typedef struct nöpel {reihe: int; spalte: int ; // next_nöpel: *nöpel } ; act_state: array [1..max_nöpel] of nöpel; 1 1 1 1 ... 1 ... 1 2 2 2 3 3 2 3 4 3 ...

Lösung 5.2 Spiel des Lebens: Komplexität Bewerten Sie den Algorithmus bezüglich seine Laufzeit und seines Platzbedarfes get_next_state (In: act_state, Out: next_state) { durchlaufe act_state // einfache Schleife durch Nöpelliste { // determine survivors find_neighbors(act_nöpel, no_of_neighbors) // Durchsuche // alle Nöpel falls no_of_neighbors = 2 oder 3 kopiere act_nöpel nach next_state // determine babies durchlaufe nachbar_nöpel von act_nöpel // max. 8 { find_neighbors(nachbar_nöpel, no_of_neighbors) falls no_of_neighbors = 3 kopiere nachbar_nöpel nach next_state } } // Zeit: Nöpel * ( Nöpel + ( 8 * Nöpel ) ) = 9 * Nöpel2 } // Platz: 2 * Nöpel

Lösung 5.3 Rekursion Programmieren Sie die Fakultätsfunktion fakultaet (IN: n:integer, OUT: result:integer) { if (n == 0) then result = 1; else { fakultaet (n-1, result); result = result * n; } } fakultaet (IN: n:integer, OUT: result:integer) { result; old_result : int; // declaration result = 1; old_result = 1 // initialization for i=1 to n { result = i * old_result; old_result = result } } // Anzahl Multiplikationen in beiden Fällen proportional n

Lösung 5.4 Acht Damen Problem siehe Homepage

Lösung 6.1.1 Turing-Maschine Vollziehen sie die 11 Schritte der ersten Turing-Tebelle. 1,_ 2,1,> 1,1 3,1,< 2,_ 3,1,> 2,1 H,1,> 3,_ 1,1,< 3,1 2,_,< 4,_ H,_,> 4,1 H,_,> Ausgangszustand,Zeichen  Folgezustand,schreibeZeichen,Aktion 1 2 3 4 5 6 7 8 9 10 11 H State

Lösung 6.1.2 Turing-Maschine Eingabe der initialen Bandinschrift Eingabe der Turing-Tabelle Zustand x Zeichen  Folgezustand x Zeichen x Aktion Beispiel: 1,_  1,_,>

Lösung 6.1.3 Turing-Maschine Aufgabenstellung Entwerfen Sie eine Turing-Maschine zur Multiplikation zweier natürlicher Zahlen. Spezifikation Eingabespezifikation Die Zahlen werden durch die entsprechende Anzahl von ‚1‘ am Band dargestellt Zwischen den Zahlen befindet sich ein ‚x‘ am Band Hinter der letzten Zahl ist ein =- Zeichen am Band Das restliche Band ist mit ‚0‘ beschrieben. Der Schreib/Lesekopf befindet sich links von der 1. Zahl. Ausgabespezifikation Das Ergebnis ist hinter dem =, durch eine entsprechende Anzahl von ‚1‘ darzustellen. Beispiel: Die zwei Zahlen 3 und 4 sind mittels eines Turing-Programmes zu multiplizieren

Lösung 6.1.3 Turing-Maschine Idee: Kopiere alles vor dem = (den 2.Multiplikator) ans Ende Mache dies für jede 1 vor dem X (den 1.Multiplikator) Siehe Anhang C SucheStart R 1 SucheZahl2 X EndZustand L Zahl2Start GeheEnde = Mach1Aus0 SucheNull HolNaechsten1 Zahl1Start

Lösung 6.2 Einfache Verifikation Gegeben ist folgender Algorithmus {a<0, b>0, c>0} a=b; {a=b, b>0, c>0} d=b-a; {d=b-a, a=b, b>0, c>0}  {d=0, b>0, c>0} if (c == 0) then {d=0, b>0, c>0, c=0} d=5; {d=5, b>0, falsch}  {d=1} // aus falsch lässt sich alles folgern else {d=0, b>0, c>0, c<>0}  {d+1=1, b>0, c>0} d=d+1; {d=1, b>0, c>0} {d=1, b>0, c>0}  {d=1}

Lösung 6.3 Denksportaufgabe  Denksportaufgabe Welche Farbe hat die letzte Kugel ? Die Farbe der letzten Kugel ist abhängig von der Anzahl der weißen Kugeln: Ist die Anzahl gerade, so ist die letzte Kugel schwarz Ist die Anzahl ungerade, so ist die letzte Kugel weiß Welche Aussage gilt vor, in und nach der Schleife (Invariante) Ist die Anzahl der weißen Kugeln gerade, so bleibt sie gerade Ist die Anzahl der weißen Kugel ungerade, so bleibt sie ungerade Es werden entweder 2 weiße Kugeln entfernt oder keine. Terminiert die Schleife ? Begründen Sie ihre Antwort. JA. Die Anzahl der Kugeln vermindert sich bei jedem Zug um genau eine (nach Algorithmus: 2 nehmen, eine geben). Beim Erreichen von 2 Kugeln wird die Schleife noch einmal durchlaufen und terminiert mit einer Kugel.

Lösung 6.4 Invariante {s+w >= 1}  x=s; y=w; {x=s, y=w, x+y  1} {INV: ( (odd(w)odd(y))  (even(w)even(y)) )  x+y1 } while (x+y>1) { {INV  x+y>1} // Vorbedingung für „take“: x+y>1 take(a,b) // OUT: a no. black, b no white (drawn) {a+b=2, a,b0} // = Nachbedingung für „take“ switch a: { // a = no of black bullets drawn case 0: {x=x+1; y=y-2}; {INV} // add black, remove two w. case 1; (x=x-1); {INV} // remove black case 2; (x=x-1); {INV} // remove black } {INV} {INV   x+y>1  ( ((odd(w)odd(y))  (even(w)even(y)) )  x+y1  x+y1  ( ((odd(w)odd(y))  (even(w)even(y)) )  x+y=1) }

Lösung 6.5 Vollständige Verifikation // Vorbedingung P(V): a>0  b0 x = a; y = b; z = 1; // x=a  y=b  z=1  x>0  b0 { INV: zxy=ab  y0 } while y > 0 { {INV  y>0  (z*x/x)*xy=ab  y>0 } if odd(y) then z = z*x; { odd(y)  z/x*xy=ab  y>0  z*xy-1=ab  y>0 } // else { even(y)  z*xy =ab  y>0 }  { ( odd(y)  z*x(2(y div 2)+1)-1=ab  2(y div 2)+1>0 )  ( even(y)  z*x2(y div 2) =ab  2(y div 2) >0 ) } y = y div 2; // Ganzzahldivision { ( odd(y)  z*x(2y+1)-1=ab  2y+1>0  z*x2y=ab  2y0 )  ( even(y)  z*x2y =ab  2y >0  z*x2y=ab  2y>0 ) } x = x*x; { (odd(y)  z*xy=ab  2y0)  (even(y)  z*xy=ab  2y>0)  z*xy=ab  ((odd(y)2y0)  (even(y)2y0))  z*xy=ab  y0 } } { INV  (y0)  (z*xy=a*b)  (y=0)  z*x0=ab = Q(V) }

Lösung 6.6.1 Schranken n3 g(n) = 5n3 + n + 1000 für alle n Behauptung: Die Laufzeit von g(n) ist O(n3), also f(n)=n3, Beweis: Es muss Konstanten c und n0 geben, so dass gilt 5n3 + n + 1000  c n2, für alle n > n0 setze z.B. n0=10 und c=6, dann gilt: n3 > n + 1000 gilt für n11, n   5n3 + n + 1000  5n3 + 100n  5n3+n3 = 6n3  z.B.: 5n3 n3

Lösung 6.6.2 Schranken Sie haben zusätzlich einen Algorithmus mit O(2n) Aufwand. Vergleichen Sie diesen Algorithmus mit dem Algorithmus aus 1. Welches ist der „schnellere“ Algorithmus ? Für kleine n (n<14) ist der Algorithmus mit O(2n) der schnellere, ansonsten der mit g(n) = 5n3 + n + 1000 Begründen Sie Ihre Antwort quantitativ 2n

Lösung 6.7.1 O-Notation gegeben seien folgende Werte: 1,3,4,8,9,15,17,25,28,29,31,36,41,45 17 31 28 41 45 8 9 3 4 29 25 15 1 36 Anzahl Aufrufe 1 2 3 4 node: array[1..14] of knoten; // Normalerweise wird der Speicher dynamisch allokiert node[1].value = 17; node[12].value = 41; node[1].left = &node[2]; node[12].left = &node[13]; node[1].right = &node[3]; node[12].right = &node[14]; node[2].value = 8; node[13].value = 36; node[2].left = &node[4]; node[13].left = nil; node[2].right = &node[5]; node[13].right = nil; node[3].value = 31; node[14].value = 45; node[3].left = &node[6]; node[14].left = nil; node[3].right = &node[7]; node[14].right = nil; ...

Lösung 6.7.2 O-Notation Formulieren Sie einen iterativen Algorithmus mit O(n4) for (i=1 to n) { for (j=1 to n) { for (k=1 to n) { for (l=1 to k) { // Statements } } } } Aufwand: nn(n(n+1))/2 = n2(n2/2+n/2)=n4/2 + n3/2  Laufzeit O(n4)

Lösung 6.8 Aufwand do (list:*liste) { i:integer; for i=1 to no_of_elements(list) { remove_last_element(list); do (list) // call list with one element less } Zeitbedarf: Tn = n Tn-1 (Tn = Zeitbedarf für n, n2, T1=1) Tn =nTn-1 = n  (n-1)  Tn-2 = n  (n-1)  (n-2) Tn-3 = ... = 1 2 3 ... n  Tn = n!  Laufzeit O(n!) (wirklich viel! Algorithmus inpraktikabel) for i=1 to n { j=1; while (j<i) { j = j+2; } } Zeitbedarf: Betrachte Anzahl der Zuweisungen für alle i<n: 1 + 2 + 2 + 3 + 3 + 4 + 4 + .... + n/2 + n/2 = 2  (n/2  (n/2+1))/2 - 1 = n/2  (n/2 +1) -1 = n2/4 + n/2 - 1  Laufzeit O(n2)

Lösung 7.1 Syntax und Semantik Geben Sie Beispiele für lexikalische Strukturelemente: Bezeichner, Literale, Schlüsselworte, ... syntaktische Strukturelemente: Alle Elemente aus „Algorithmenentwurf“ der Programmiersprache C++ an Formulieren Sie die Semantik einer while-Schleife: siehe Schleife mit vorausgehender Prüfung eines Unterprogrammaufrufes siehe „Block“ recherchieren Sie nach weiteren Programmiersprachen Algol 60, Algol 68, Forth, PL/1, Fortran, Smalltalk, Simula 67, SETL, Snobol, Cobol, Pascal, Turbo-Pascal, DELPHI, Concurrent Pascal, SPSS, CLU, Alphard, SDL, Oberon, Oberon-2, Object Cobol, Ada, APL, CDL 2, Ada 95, Mesa, Modula-2, Chill, BCPL, C, Objective-C, Modula-3, C++, ,Assemblersprachen, Prolog, Prolog II, Eiffel, Beta, Opal, CS,P Hope, Miranda, Lisp, Common Lisp, PHP, Perl, Scheme, Haskell, Standard ML, Clipper, Basic, Visual Basic, Java, JavaScript, SQL, Late,x Postscript, HTML, UML, Z, Act-One, VDM, awk, LEX, YACC, Maschinensprachen, RPG, Occam, Linda, T Lotus, OPS-5, ...  werden Sie zu Meta-Programmierern und -Programiererinnen

Lösung 7.2 Reguläre Ausdrücke Geben Sie reguläre Ausdrücke für Integerliterale: [1-9][0-9]* bzw. (1|2|3|4|5|6|7|8|9)(o|1|2|3|4|5|6|7|8|9)* while, function, if while usw. bzw. ‘w‘‘h‘‘i‘‘l‘‘e‘ usw. Geben Sie einen regulären Ausdruck zu folgenden Sprachen an: Alle Folgen von Großbuchstaben, die jeden Vokal genau einmal in alphabetischer Reihenfolge enthält: KONS = [B-DF-HJ-NP-TV-Z] {KONS}A{KONS}E{KONS}I{KONS}O{KONS}U{KONS} Alle Dualziffernfolgen, die „001“ nicht als Teilfolge enthalten (0?1+)*0* Welche Sprachen sind durch die folgenden regulären Ausdrücke definiert ? (0?|1*)* alle Binärzahlen, denn (0|1) ist Teilmenge von (0?|1*) (0|1)*0(0|1)(0|1) alle Binärzahlfolgen, bei denen die drittletzte Ziffer existiert und 0 ist /\*((\*[^/])|[\*])*\*/ „wohlgeformte“ C-Kommentare

Lösung 7.3 Grammatiken gegeben ist folgende Grammatik G: G = { N,T,P,S }, N = { A,B,C,S }, T = { a,b,c }, P = { S:=ABC, A:=ABA, C:=CBC, A:=a, B:=b, C:=c } Die Grammatik ist kontextfrei, da auf der linken Seite aller Regeln genau ein Nichtterminalsymbol steht Beweis durch Ableitung : S  ABC  ABABC  ABABABC  ABABABCBC  ... : abababcbc Es gibt keine Regel, die ein b vor ein a produziert, daher ist b2a2c3  L(G), denn in b2a2c3 ist ein b vor einem a. (ab)+c(bc)* Da die Grammatik G kontextfrei ist die Sprache vom Chomsky-Typ-2. Da sich die Sprache auch als regulären Ausdruck darstellen lässt, ist die Sprache sogar Chomsky-Typ 3. Ja, denn jede Chomsky-Typ2 bzw. 3 Sprache ist auch vom Chomsky-Typ0

Beispielklausur In diesem Kapitel wird ein Beispiel für eine Klausur vorgestellt. Dabei sind jeweils die Aufgaben und die Lösungen gegeben. Beachten Sie Diese Beispielklausur erhebt weder in Form, Inhalt noch Umfang einen Anspruch auf Vollständigkeit.- dies betrifft insbesondere reine Wissensfragen, die hier etwas vernachlässigt sind. Grundsätzlich ist der gesamte in der Vorlesung und den Übungen behandelte Stoff möglicher Gegenstand der Prüfung Vorbereitung Arbeiten Sie die gesamten Folien nochmals durch Bearbeiten Sie alle Übungsaufgaben nochmals Arbeiten Sie das Skript von Herrn Geise durch Bearbeiten Sie dessen Übungsaufgaben Bedenken Sie: In der Klausur sind keine Hilfsmittel zugelassen.

Informatik Fehlt in dieser Beispielklausur ...

Information Eine Nachrichtenquelle sendet Zeichen aus dem Alphabet X = {a,b,c,d,e} mit den Wahrscheinlichkeiten p(a)=1/2, p(b)=p(c)=p(d)=p(e)=1/8 Wie groß ist der Informationsgehalt der einzelnen Zeichen Wie groß ist der Informationsgehalt der Nachricht „abc“ Wie groß ist der mittlere Informationsgehalt einer Nachricht mit 1000 Zeichen Finden Sie einen möglichst optimalen Code für dieses Alphabet Angenommen die Wahrscheinlichkeiten wären p(b)=1/2, p(a)=p(c)=p(d)=p(e)=1/8 . Wie groß wäre dann die Redundanz Ihres Codes aus Aufgabe d) Hamming Codieren Sie die Binärzahl 1000 mit der Hamming-Methode Wieviele Bits können als fehlerhaft erkannt werden ? Wieviele Bits können korrigiert werden ?

Zahlensysteme Stellen Sie die Dezimalzahl 7,25 dar Binär Hexadezimal Oktal dar Berechnen Sie im Binärsystem (mit Vollständiger Rechnung) 1100100 : 101 Machen Sie schriftlich die Gegenprobe (auch im Binärsystem) 10111 – 1010 (durch Addition des Zweierkomplements)

Zahlensysteme Fehlt in dieser Beispielklausur: Gleitpunktzahlen IEEE 754 ...

Datenstrukturen ... Gegeben ist folgende Struktur Vorname Nachname Definieren Sie Datenstrukturen, mit denen diese Struktur einer zweifach verketteten Liste repräsentiert werden kann. Begründen Sie, weshalb diese Datenstruktur als „dynamisch“ bezeichnet wird (im Gegensatz zu statisch) Geben Sie jeweils zwei Gründe für die Verwendung dynamischer bzw. statischer Datentypen an. Definieren Sie statische Datenstrukturen, mit denen man die oben aufgezeichnete Struktur möglichst vollständig abbilden kann. Vorname Nachname ...

Algorithmenentwurf Gegeben ist folgender Algorithmus: x=a, y=5; while (x>0) { y = y+1; x = x-1; } Formen sie die while Schleife in eine repeat-Schleife um Bilden Sie die Funktion dieses Algorithmus‘ ohne Schleifen, mit Hilfe von Sprüngen und Marken nach

Algorithmenentwurf Fehlt in dieser Beispielklausur: Weitere Umformungen Blockung Umwandlung Rekursion/Iteration ...

Berechenbarkeit Beweisen Sie mit Hilfe einer Turing-Maschine, dass f: N  N mit: f(x) ist Binärkomplement von x berechenbar ist. Geben Sie dabei an: Alphabet Bandinschrift (mit Codierverfahren) Kopfposition Zustände (mit dem Startzustand und den Endzustände) Zustandsübergänge Zeichen Sie für eine Zahl das Turingband vor- und nach Ausführung des Turingprogrammes

Korrektheit Tausch zweier Variablen Entwerfen Sie einen Algorithmus zum Vertauschen der Werte zweier Variablen (vom Typ integer) Vorbedingung: x=a, y=b Nachbedingung: x=b, y=a Beweisen Sie die Korrektheit Ihres Algorithmus Gegeben sei folgender Algorithmus: x=3, y=5; while (x>0) { y = y+1; x = x-1; } Was macht dieser Algorithmus ? Beweisen Sie Ihre Antwort für Frage a) mit Hilfe der Hoare'schen Logik

Komplexität Fehlt in dieser Beispielklausur: Fragen zu den Konstanten c und n0 Beispiele für O(...) Bestimmung des Aufwandes für iterativen/rekursiven Algorithmus ...

Reguläre Ausdrücke gegeben ist folgender regulärer Ausdruck R (in UNIX-Notation): [abc]*d[abc]+ (mit Alphabet  = {a,b,c,d} ) formulieren Sie den Ausdruck in die „klassische“ Notation für reguläre Ausdrücke um. Geben Sie 2 Worte aus L(R) deren Länge jeweils genau 10 Zeichen betragen Geben Sie zwei Worte aus * an, die nicht in L(R) sind Konstruieren Sie einen indeterministischen endlichen Automaten A mit L(A)=L(R) Konstruieren sie reguläre Ausdrücke (in UNIX-Notation) für Hexadezimalzahlen Eigennamen bestehend aus optionalen Titeln, Vor- und Nachnamen (eventl. Doppelnamen, keine Beachtung von Umlauten) Beispiele.: Prof. Dr. Peter Kneisel, Sabine Mustermann, Dr. Kloebner, Karl-Heinz Müller-Lüdenscheid) Lall-Sprache: Bestehend aus l‘s, die durch Vokale miteinander-Verbunden sind Beispiele: lal, lala, lelalilu, lelelalal

Endliche Automaten Gegeben ist folgender endlicher Automat A b b z0 z1 Von welchem Typ ist dieser Automat: Ist dies ein NEA oder ein DEA, begründen Sie Ihre Antwort Formen Sie den Automaten in den anderen Typ so um, dass immer noch die gleiche Sprache akzeptiert wird. Welches sind die Symbole, die der Automat verarbeitet ? Geben Sie die Übergangsfunktion  an Formulieren Sie einen regulären Ausdruck R mit L(R) = L(A) b b z0 z1 z2 z3 a  a

Grammatiken Fehlt in dieser Beispielklausur

Lösung: Information Hamming Eine Nachrichtenquelle sendet Zeichen aus dem Alphabet X = {a,b,c,d,e} mit den Wahrscheinlichkeiten p(a)=1/2, p(b)=p(c)=p(d)=p(e)=1/8 h(a) = -ld(1/2) = 1bit. h(b)=h(c)=h(d)=h(e)=-ld(1/8)=3bit 1bit + 3bit + 3bit = 7 bit 1000 x Mittlerer Informationsgehalt: H(x)=p(xi)h(xi) = 1000 x ( 1/2x1 + 1/8x3 + 1/8x3 + 1/8x3 + 1/8x3 )bit = 1000 x 2bit = 2000 bit Nach Huffmann: p(de)=1/4, p(bc)=1/4, p(debc)=1/2, p(a)=1/2). p(abcde)=1 also z.B.: a=1, b=000, c=001, d=010, e=011 Redundanz = L(x)-H l(x)=1bit , l(b)=l(c)=l(d)=l(e)=3bit (entsprechend der Codierung in d.) L(x) = p(xi)l(xi) = (0,125x1 + 0,5x3 + 0,125x3 + 0,125x3 + 0,125x3)bit = 2,75 bit h(b) = 1bit, h(a)=h(c)=h(d)=h(e)=-ld(1/8)=3bit H(x) = p(xi)h(xi) = (0,5x1 + 0,125x3 + 0,125x3 + 0,125x3 + 0,125x3 )bit = 2 bit Redundanz = L(x)-H = 2,75bit – 2bit = 0.75 bit Hamming 100P0PP (Relevant: Bit 3,5,7)  100P0P1 (even Parity: also 1 ergänzen) 100P0P1 (Relevant: Bit 3,6,7)  100P011 (even Parity: also 1 ergänzen) 100P011 (Relevant: Bit 5,6,7)  1001011 (even Parity: also 1 ergänzen) Der Hamming-Abstand D ist 3bit, es können D-1 = 2bit Fehler erkannt werden Es können (D-1)/2 = 1bit Fehler korrigiert werden.

Lösung: Zahlensysteme Dezimalzahl 7,25 Vorkommateil: Nachkommateil 7 : 2 = 3 Rest: 1 2 · 0,25 = 0,5 --> Ziffer: 0 3 : 2 = 1 Rest: 1 2 · 0,5 = 1 --> Ziffer: 1 1 : 2 = 0 Rest: 1 -> 111 ->0,01 Binärzahl: 111.01 0111,01002 = 7,416 (7 * 160 + 4 * 16-1) 111,0102 = 7,28 (7 * 80 + 2 * 8-1) Berechnung 1100100 : 101 = 10100 10100 x 101 101 10100 --- 00000 101 10100 101 ------- --- 1100100 000 10111 – 1010 10111 - 01010 auf gleiche Längenbringen 1 10111 + 10110 Binärkomplement 10101+ 1 = 101100 Lösung: 1101 Überlauf weggelassen

Lösung: Datenstrukturen Doppelt verkettete Liste Person : record { vorname : array[1..64] of char; nachname: array[1..64] of char; prev : *Person; next : *Person; } Man kann aus diesen Strukturen beliebig lange Ketten von Personen bilden Pro: Dynamisch: Verwaltung von Objekten, deren Anzahl zur Entwicklungszeit nicht bekannt ist. Speicherverbrauch nur für die Objekte, die tatsächlich zur Laufzeit existieren. Pro Statisch: Einfach in der Realisierung, schnell in der Bearbeitung (Fehlerunanfälliger) Person : record { vorname : array[1..64] of char; nachname: array[1..64] of char; } Personeliste: array[1...65534] od Person;

Lösung: Algorithmenentwurf Umformung der while-Schleife: Als repeat-Schleife: x=a; y=5; if (x>0) { repeat do { { y = y+1; y = y+1; x = x–1; x = x-1; } until (x<=0) } while (x<=0} } Sprünge und Marken x=a; y=5; x=a; y=5; 1: if (x<=0) goto 2 1: if (x>0) y = y+1; { x = x–1; y = y+1; goto 1; x = x–1; 2: ... goto 1 } 2: ...

Lösung: Berechenbarkeit Definiere eine Turing-Maschine, die beliebige binäre Ziffernfolgen bitweise invertiert. Die Turing-Maschine: Alphabet : {_,0,1}, Bandinschrift: Zahl, codiert als Binärzahl, alles andere „_“ Kopfposition: links neben der Binärzahl Zustände: {q0, q1,q2}, Startzustand. q0, Endzustände:{q2} Zustandsübergänge: A  Q  A  Q  {r, l} _,q0  _,q0,r 0,q0  1,q1,r 1,q0  0,q1,r 0,q1  1,q1,r 1,q1  0,q1,r _,q1  _,q2,r Das Turing-Band vor und nach Abarbeitung des Turing-Programmes für die Zahl: 44 1 1 1 1 1 1

Lösung: Korrektheit a) und b) z : integer { x=a,y=b } z=y; {x=a,y=b,z=b} y=x; {x=a,y=a,z=b} x=z; {x=b,y=a,z=b  x=b,y=a} q.e.d Beweis durch Anwendung der Hoare‘schen Logik: Der Algorithmus liefert für y den Wert 8  Nachbedingung Q: (y=8) x=3, y=5; {x=3, y=5} { INV: y=8-x  x0 } while (x>0) { { INV  x>0  (y+1)-1=8-x  x0  x>0 } y = y+1; { y-1=8-x  x0  x>0  y=9-((x-1)+1)  (x-1)+1>0 } x = x-1; { y=9-(x+1)  x+1>0  y=8-x  x0  INV} } { INV  x0  y=8-x  x=0  y=8 = Q } q.e.d.

Lösung: Reguläre Ausdrücke gegeben ist folgender regulärer Ausdruck R (in UNIX-Notation): [abc]*d[abc]+ (mit Alphabet  = {a,b,c,d} ) (a|b|c)*d(a|b|c)(a|b|c)* abcabcdabc abddab. abcabcaabbccd NEA: z.b.   z0 z1 z3 z4 d a,b,c a,b,c, Konstruieren sie reguläre Ausdrücke (in UNIX-Notation) für [1-9A-F][0-9A-F]* (Prof\.)?(Dr\.)?([A-Z][a-z]*(\-[A-Z][a-z])?)? ([A-Z][a-z]*(\-[A-Z][a-z])?) VOKAL = [AEIOU] l(<VOKAL>l)*<vokal>?

Lösung: Endliche Automaten Gegeben ist folgender endlicher Automat A Dies ist ein indeterministischer endlicher Automat, da es einen -Übergang gibt. NEA  DEA, z.b.: a,b  = { (z0, a, z1), (z1, b, z0), (z1, , z1), (z2, a, z3), (z3, b, z2) } a(ba)*a(ba)* b b z0 z1 z2 z3 a  a b a z0 z2 z3 z2 a a b