Was bisher geschah I Algorithmen I Spezifikation I asymptotische Laufzeit I rekursive Algorithmen I Divide-and-Conquer-Algorithmen I Dynamische Programmierung 93 Entwurfsebenen Mathematik: Algorithmik: Programmierung: Funktion ↓ Algorithmus ↓ (Unter-)Programm Methode Abstrakter Datentyp ↓ Algebra (Konkreter Datentyp) ↓ Datenstruktur ↓ Datentyp Klasse 94 Motivation ADT Aufgabe: Verwaltung einer Menge ganzer Zahlen, so das festgestellt werden kann, ob eine Zahl darin enthalten ist und Zahlen hinzugefügt und entfernt werden können. Spezifikation des Datentyps NSet muss enthalten: I I N N Wertebereiche (Sorten): , Mengen ⊆ , Wahrheitswerte (Bool) Operationen: finden, hinzufügen, entfernen Operationen mit Typdeklaration (Signatur) N N contains : Menge × → add, remove : Menge × → isempty : Menge → emptyset : I Bool Menge Bool Menge Bedeutung der Operationen t falls x ∈ M contains(M, x) = f sonst add(M, x) = M ∪ {x} remove(M, x) = M \ {x} = ∅ t falls M = ∅ isempty(M) = f sonst emptyset 95 Spezifikation durch abstrakte Datentypen (ADT) Abstrakter Datentyp NSet: Sorten: N, Mengen ⊆ N, Wahrheitswerte (Bool) Signatur: Operationen mit Typdeklaration N N contains : Menge × → add, remove : Menge × → isempty : Menge → emptyset : Bool Menge Bool Menge Axiome: formale Beschreibung der Bedeutung der Operationen (Zusammenhänge dazwischen) N ∀s ∈ Menge∀n ∈ N ∀s ∈ Menge∀n ∈ N ∀s ∈ Menge∀m, n ∈ N ∀s ∈ Menge∀n ∈ N ∀n ∈ isempty((emptyset) = t : contains(emptyset, n) = f : contains(add(s, n), n) = t : contains(remove(s, n), n) = f : add(add(s, n), m) = add(add(s, m), n) : add(add(s, n), n) = add(s, n) ... 96 Abstrakte und konkrete Datentypen Abstrakter Datentyp (ADT): (formale Spezifikation) I Menge von Sorten I mehrsortige Signatur ΣF I Menge von Axiomen Φ ADT = (funktionale) Signatur ΣF + Axiome Φ Konkreter Datentyp: ΣF -Algebra A mit A ∈ Mod(Φ) (Struktur mit geeigneten Funktionen, so dass alle Axiome erfüllt sind) 97 Beispiel: Boolesche Algebra Abstrakter Datentyp Boolesche Algebra: Sorten: Bool (zwei Wahrheitswerte) Signatur: t: f: ¬: Bool → ∨ : Bool × Bool → ∧ : Bool × Bool → Bool Bool Bool Bool Bool Axiome: ∀a∀b : a ∧ b = b ∧ a, ∀a∀b : a ∨ b = b ∨ a, ∀a∀b∀c : a ∨ (b ∧ c) = (a ∨ b) ∧ (a ∨ c), Φ= ∀a∀b∀c : a ∧ (b ∨ c) = (a ∧ b) ∨ (a ∧ c), ¬(t = f), ∀a∀b : ¬(¬a ∨ b) ∨ ¬(¬a ∨ ¬b) = a passende konkrete Datentypen, z.B. I ({0, 1}, max, min, x 7→ 1 − x, 0, 1) I (2{d} , ∪, ∩, , ∅, {d}) 98 Einfache und zusammengesetzte Datentypen Datentyp: Menge von Werten mit Operationen auf diesen Werten I einfache Datentypen, z.B. int, bool, float, ... I zusammengesetzte Datentypen Konstruktion durch die Operationen I I I I kartesisches Produkt von Datentypen: mehrfaches Produkt desselben Typs, z.B. Tupel Produkt verschiedener Typen, z.B. Klassen, record Vereinigung von Datentypen (in Java: Interface mit mehreren Implementierungen) rekursive Datentypen, z.B. Liste, Term Abbildung zwischen Datentypen (Funktionen) 99 Prominente zusammengesetzte Datentypen Mengen typische Operationen: I Test auf Leerheit I Einfügen, Entfernen von Elementen I Suche nach Element I Vereinigung, Durchschnitt, Differenz Folgen (z.B. Listen, Texte), typische Operationen: I Einfügen, Entfernen von Elementen I Suche nach Element I spezielle Elemente suchen (Min, Max, Median) I Sortieren I Verketten, Spiegeln Abbildungen (z.B. Wörterbücher), typische Operationen: I Einfügen, Entfernen von Argument-Wert-Paaren I Suche nach dem Wert zu einem Argument Graphen typische Operationen: I Einfügen, Entfernen von Knoten und Kanten I Suche nach Knoten I Suche nach Pfaden (z.B. kürzeste) I Suche nach Teilgraphen (z.B. Gerüst) 100 Wiederholung: mehrsortige Strukturen Modellierung von Strukturen mit S = {Si | i ∈ I} von Elementen I verschiedenen Sorten (Mengen) I Operationen I Eigenschaften und Zusammenhänge zwischen Operationen Beispiele: I Mengen (Elemente, Mengen von Elementen, polymorph) Operationen: add, contains, empty Zusammenhänge: ∀e∀l : empty(add(e, l)) = false I Folgen (Elemente, Folgen von Elementen, polymorph) Operationen: add, remove, append, add, reverse Zusammenhänge: ∀l : reverse(reverse(l)) = l I Vektorraum (Skalare, Vektoren) Operationen: smult,sprod,+,0,0v Zusammenhänge: ∀v : smult(0,v) = 0 101 Mehrsortige Strukturen hier nur funktionale Strukturen (Algebren) I Sorten I Signatur Σ = (ΣF , ∅) (keine Relationssymbole) ΣF -Algebra A = ({AS | S ∈ S}, J·KA ) mit I I für jede Sorte S ∈ S eine nichtleere Menge AS (Träger, Universum der Sorte) für jedes Funktionssymbol f : Si1 . . . Sin → Si eine Funktion Jf KA : Ai1 × · · · × Ain → Ai Modell für Menge Φ von Sätzen: ΣF -Algebra A, welche alle Sätze aus Φ erfüllt 102 Beispiel ADT Folge Ziel: Datentyp zur Verwaltung einer endlichen Folge von Elementen einen Typs a (Zuordnung f : {1, . . . , n} → a) mit Operationen zum Bestimmen der Länge der Folge, Hinzufügen und Lesen eines Elementes an einer bestimmten Position. Sorten: Element, Folge von Elementen (polymorph), Bool, Nat Signatur: nil : Folge isempty : Folge → Bool add : Folge × Element → Folge get : Folge × Nat → Element size : Folge → Nat weitere sinnvolle Operationen für Folgen: head : Folge → tail : Folge → reverse : Folge → remove : Folge × Element → append : Folge × Folge → Element Folge Folge Folge Folge Axiome: ? (Tafel) 103 (Ein möglicher) konkreter Datentyp für Folgen N N Sorten: Bool: {0, 1}, Nat: , Element: {a, b, c}, Folge: {(x1 , . . . , xn ) | n ∈ ∧ ∀i ∈ {1, . . . , n} : xi ∈ {a, b, c}} Realisierung der Operationen: nil = () t falls x = () f sonst isempty(x) = add((x1 , . . . , xn ), y ) = (y , x1 , . . . , xn ) get((x1 , . . . , xn ), i) = xi size(x1 , . . . , xn ) = n Nachweis der Gültigkeit der Axiome: (Tafel) 104 Realisierung zusammengesetzter Typen (Verwaltung mehrerer Daten derselben Art) I lineare Datenstrukturen, z.B. Folge, Liste, Queue, Stack I hierarchische Strukturen, z.B. Bäume I Relationen, z.B. Graphen 105 Realisierungen des ADT Menge einige Möglichkeiten: I ungeordnete Folge (Aufzählung aller Elemente) I I I I I geordnete Folge (sortierte Aufzählung aller Elemente) I I I I I add O(1) remove O(n) contains O(n) isempty O(1) add O(n) remove O(n) contains O(log n) isempty O(1) Bitvektor (charakteristische Funktion) I I I I add O(1) remove O(1) contains O(1) isempty O(n) 106 ADT Folge mit Positionszugriff ADT PFolge (Spezifikation): Sorten: Element, Folge von Elementen (polymorph), Bool, Nat, Pos Signatur: nil : isempty : Folge → get : Folge × Pos → set : Folge × Element × Pos → remove : Folge × Pos → size : Folge → Folge Bool Element Folge Folge Nat Axiome z.B. isempty(nil) = t, ∀l ∈ Folge∀y ∈ Element∀i ∈ Pos : get(set(l, y , i), i) = y 107 Modell für Folgen mit Positionszugriff Trägermengen: Element E, Folgen: E ∗ nil = ε t falls n = 0 isempty(x1 · · · xn ) = f sonst xi falls i ≤ n get(x1 · · · xn , i) = undef sonst set(x1 · · · xn , y , i) = remove(x1 · · · xn , i) = size(x1 · · · xn ) = x1 · · · xi−1 , y , xi+1 , . . . , xn x1 · · · xi−1 ◦ xi+1 · · · xn undef falls i ≤ n sonst n Implementierung z.B. als Array (hinreichender Größe) 108 ADT Folge ohne Positionszugriff ADT Folge (Spezifikation, Auszug): Sorten: Bool, Element, Folge, Nat Signatur: nil : isempty : Folge → head : Folge → tail : Folge → add, remove : Folge × Element → append : Folge × Folge → reverse : Folge → size : Folge → Folge Bool Element Folge Folge Folge Folge Nat Axiome z.B isempty(nil) = t ∀x ∈ Folge∀e ∈ Element : isempty(add(e, x)) = f ∀x ∈ Folge∀e ∈ Element : head(add(e, x)) = e ∀x ∈ Folge∀e ∈ Element : tail(add(e, x)) = x 109 Modell für Folgen ohne Positionszugriff Trägermengen: Element E, Folgen: E ∗ nil = ε isempty(x1 · · · xn ) = head(x1 · · · xn ) = tail(x1 · · · xn ) = t falls n = 0 f sonst x1 falls n > 0 undef sonst x2 · · · xn falls n > 0 undef sonst add(e, x1 · · · xn ) = ex1 · · · xn append(x1 · · · xn , y1 · · · ym ) = x1 · · · xn ◦ y1 · · · ym reverse(x1 · · · xn ) = xn · · · x1 size(x1 · · · xn ) = n 110 Rekursive Datentypen Wiederholung: Funktion f heißt rekursiv gdw. in der Definition von f kommt f selbst vor. analog: ADT heißt genau dann rekursiv, wenn er in seiner Definition selbst vorkommt. Jeder induktiv definierte Datentyp (z.B. Listen, Terme, Formeln) ist rekursiv. Operationen in rekursiven Datentypen lassen sich rekursiv realisieren. 111 Einfach verkettete Liste Knotentyp: I I nil (Konstante) oder Knoten aus I I Element (head) und (Verweis auf) Liste (tail) in Haskell: data List a = Nil {} | Cons { head :: a, tail :: List a } oft kürzer (Nil 7→ [], Cons 7→ :, ohne Komponentennamen): data [a] = [] | a : [a] Spezialfall: zyklisch verkettete Liste 112 Realisierung des ADT Folge (mit Positionszugriff) durch verkettete Liste: I isempty O(1) I add O(1) (am Anfang anfügen) I contains O(n) (ein Vorkommen finden) I remove O(n) (alle Vorkommen finden) I get, set O(n) (Position finden) durch Array (variabler Länge): I isempty O(1) I add O(1) (am Ende anfügen) I contains O(n) (ein Vorkommen finden) I remove O(n) (alle Vorkommen finden und Nachrücken) I get, set O(1) (Direktzugriff über Index) 113 Doppelt verkettete Liste Knotentyp: I I nil (Konstante) oder Knoten aus I I I Element (head) und (Verweis auf) Liste (next) und (Verweis auf) Liste (prev) und 114 Spezielle lineare Datenstrukturen add, remove und get nur an festgelegten Positionen (remove’ ohne Element, get’ ohne Index) ADT Lin (Spezifikation): Sorten: Bool, Element, Folge Signatur: isempty : Folge → nil : add : Folge × Element → remove0 : Folge → get0 : Folge → Bool Folge Folge Folge Element Spezialfälle: Stack: andere Namen für Operationen: add 7→ push, remove’ 7→ pop, get’ 7→ top Queue: andere Namen für Operationen: add 7→ enqueue, remove’ 7→ dequeue, get’ 7→ front 115 Stack (Stapel, Keller, LIFO) ADT Stack Sorten: Bool, Element, Stack (polymorph) Signatur: isempty : Stack → nil : push : Stack × Element → pop : Stack → top : Stack → Axiome: Bool Stack Stack Stack Element isempty(nil) = t, ∀s∀e : isempty(push(s, e)) = f, ∀s∀e : pop(push(s, e)) = s, ∀s∀e : top(push(s, e)) = e, . . . Realisierungen meist durch verkettete Liste oder Array 116 Queue (Warteschlange, FIFO) ADT Queue Sorten: Bool, Element, Queue (polymorph) Signatur: isempty : Queue → nil : enqueue : Queue × Element → dequeue : Queue → front : Queue → Bool Queue Queue Queue Element Axiome: isempty(nil) = t, ∀q∀e : isempty(enqueue(q, e)) = f, ∀a∀b : front(enqueue(enqueue(nil, a), b)) = a ∀a∀b : dequeue(enqueue(enqueue(nil, a), b)) = enqueue(nil, b), . . . Realisierung meist durch zyklisch verkettete Liste oder Array 117