Vorlesung Inf-Prog 20.11.2009 Contents 1 Abstrakte Datentypen (Mengen) 1.1 2 Rekapitulation (letzte Vorlesung) . . . . . . . . . . . . . . . . . . 2 1.1.1 . . . . . . . . . . . 2 1.2 Liste der Elemente ist geordnet in aufsteigender Reihenfolge . . . 2 1.3 Menge als geordnete binäre Bäume . . . . . . . . . . . . . . . . . 3 1.3.1 Datenstruktur 3 1.3.2 Implementierung: element? . . . . . . . . . . . . . . . . . 4 1.3.3 Implementierung: hinzufügen . . . . . . . . . . . . . . . . 4 1.3.4 Komplexität: 4 1.3.5 Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.4 1.5 Implementierung: ungeordnete Listen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anwendung von Mengen: Human-Bäume . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 5 5 1.5.1 Beispiel ASCII-Code: . . . . . . . . . . . . . . . . . . . . 5 1.5.2 Konstruktion: Human-Codierung . . . . . . . . . . . . . 6 1.5.3 Konstruktion von Human-Bäumen 7 1 . . . . . . . . . . . . 1 Abstrakte Datentypen (Mengen) 1.1 Rekapitulation (letzte Vorlesung) Schnittstelle: leer, hinzufügen, element?, schnitt,.... 1.1.1 Implementierung: ungeordnete Listen Schnitt: O(n2 ) ⇒schlecht 1.2 Liste der Elemente ist geordnet in aufsteigender Reihenfolge Voraussetzung: Totale Ordnung auf Elementen existiert (hier: Zahlen: <, <=...) ⇒Zukünftig existiert nur eine Darstellung der Menge {1, 2, 4, 3, 5} : (list 1 2 3 4 5) Implementierung Hinzufügen nicht nur am Anfang: (define (hinzufuegen x m) (cond ((empty? m) (cons x m)) ((= x (first m)) m) ((< x (first m)) (cons x m)) (else (cons (fist m) (hinzufügen x (rest m)))))) Komplexität: Im Durchschnitt haben wir n 2 Vergleich + hinzufügen: O( n2 ) = O(n) Verbesserung bei Schnitt vergleiche Anfangselemente: beide Mengen gleichzeitig durchlaufen: ” = ” →schnitt, sonst werfe kleineres Element weg (define (schnitt m1 m2) (if (or (empty? m1) (empty? m2)) leer (cond ((= (first m1) (first m2)) (cons (fist m1) (schnitt (rest m1) (rest k2)) (define (durchschnitt m1 m2) (cond ((< first m1) (first m2)) (schnitt (rest m1) m2) (else (schnitt m1 (rest m2))))) Komplexität |m2| bei jedem Schnittaufruf: Wegnahme eines Elementes Schritte (maximal) ⇒ O (n) (statt O n2 ), Mächtigkeit der beiden Mengen ⇒Noch relativ aufwendig: Elementtest, Hinzufügen 2 ⇒ |m1| + dabei ist n die Anzahl der 1.3 Menge als geordnete binäre Bäume (binärer Baum: jeweils maximal 2 Kindknoten) Idee Linker Teilbaum enthält kleinere Elemente Rechter Teilbaum enthält gröÿere Elemente Bäume für {1, 2, 3, 4, 5, 6} Vorteil: (element? x m) 1. x = Wurzel(m) → 2. x < Wurzel(m) →linker 3. x > Wurzel(m) →rechter fertig Teilbaum Teilbaum Im Durchschnitt sind in jedem Teilbaum Ein Schritt: n→ n 2 Elemente n 2 Elemente ⇒Komplexität: O (log) n 1.3.1 Datenstruktur Knoten ≈(eintrag linker-baum ≈leere Liste rechter-baum) Leerer Baum ⇒Strukturdenition: (define-struct baum (eintrag links recht)) ⇒Konstruktoren: make-baum, leer: (define leer empty) ⇒Selektoren: baum-eintrag, baum-links, baum-rechts 3 1.3.2 Implementierung: element? (define (element? x m) (cond ((empty? m) false) ((= x (baum-eintrag m)) true) ((< x (baum-eintrag m)) (element? x (baum-links m))) (else (element? x (baum-rechts m))))) 1.3.3 Implementierung: hinzufügen Ahnlich wie geordnete Listen, hier: Aufbau von geordneten Bäumen Vergleiche x mit baum-eintrag und füge x im linken oder rechten Baum hinzu (define (hinzufuen x m) (cond ((empty? m) (make-baum x empty empty)) ((= x (baum-eintrag m)) m) ((< x (baum-eintrag m)) (make-baum (baumeintrag m) (hinzufuegen x (baum-links m)) (baum-rechts m))) (else (make-baum (baum-eintrag m) (baum-links m) (hinzufuegen x (baum-rechts m)))) 1.3.4 Komplexität: Analog zu element?: O (log n) schnitt/vereingigung: keine eziente Möglichkeit wie geordnete Listen sondern: für jedes Element prüfe in anderer Menge O(n − log n) 1.3.5 Problem O(log n) Laufzeit nur für ausgewogene Bäume, aber: Hinzufügen von 1,2,3,4,5,6 4 Annahme: Lösung: → Hinzufügen erfolgt zufällig (nicht garantiert!) bessere Datenstrukturen, ausgeworgen gehalten (z.B. AVL-Bäume Algortihmen + Datenstrukturen) 1.4 Anwendung von Mengen: Datenbanksysteme Elemente: Paare (Schlüssel / Inhalt) Schlüssel z.B. Versicherungsnummer, Inhalt ist der sonstige Inhalt (Name...) ⇒totale Ordnung:(s1 i1 )<(s2 i2 ) genau dann wenn s1 < s2 1.5 Human-Bäume 1.5.1 Beispiel ASCII-Code: ein Zeichen ≈ ⇒Nachricht Folge von 7 Bits (128 verschiedene Zeichen - codierbar) mit 10 Zeichen: 70 Bits Allgemein: Codierung von N verschiedenen Zeichen: Nachrichten mit 8 Zeichen: A,B,C,D,E,F,G,H ⇒3 Bits reichen aus: • A: 000 • B: 001 • C: 010 5 log2 N Bit/Zeichen • D: 011 • E: 100 • F: 101 • G: 110 • H: 111 ABAFBA: 000001000101001000: 18 Bits! Code fester Länge Häug ist jedoch der Fall: Buchstabenhäugkeit unterschiedlich (Vokale: oft, x,y: selten) Häuge Zeichen: kurzer Code Seltene Zeichen: langer Code →Code variabler Länge • A: 0 • B: 100 • C: 1010 • D: 1011 • E: 1100 • F: 1101 • G: 1110 • H: 1111 ABAFBA: 0100011011000: 13 Bits Problem: Wo fängt das nächste Zeichen an? Lösung: Präxcode: keine Codierung eines Zeichens ist Präx eines anderen Zeichens. oben: A ≈ 0, kein anderer Coe fängt mit 0 an. 1.5.2 Konstruktion: Human-Codierung Idee: Repräsentiere Code als Binärbaum • Blätter: einzelne Zeichen mit Gewichtung (Häugkeit) • Innere Knoten: Zeichenmengen (Vereinigung der Kindknoten) + Gewichtung (Summer der Kindknoten) 6 Beispiel: Codierung: • Beschrifte beide Kinder mit 0,1 • Code für Zeichen: Folge der Beschriftungen von der Wurzel zu den Zeichen Decodierung: • Folge Code von der Wurzel hinunter • Falls Blatt erreicht: Zeichen gefunden 1.5.3 Konstruktion von Human-Bäumen • Anfang: nur Blätter mit den Zeichen + Häugkeiten • Schritt: Suche Teilbäume mit geringster Gewichtung, vereinige diese zu einem neuen Baum • Ende: nur ein Baum vorhanden Beispiel:{(E, 1), (F, 1), (G, 1), (H, 1)} 7