31.12.2013 Aufrufe

Präsentation - Torsten Finke

Präsentation - Torsten Finke

Präsentation - Torsten Finke

MEHR ANZEIGEN
WENIGER ANZEIGEN

Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.

YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.

Überblick<br />

Ankündigungen<br />

Algorithmen<br />

(Revision 183)<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong><br />

FOM<br />

2013-12-01<br />

Einführung<br />

Datenstrukturen<br />

Algorithmen – Konzepte und Analyse<br />

Sortieren<br />

Zeichenketten<br />

Kompression<br />

Kryptologie<br />

Geometrie<br />

Graphen<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 1 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 2 / 235<br />

Ankündigungen<br />

Inhalte<br />

Ankündigungen<br />

Klausur<br />

Algorithmen – Folien<br />

Klausur<br />

http://www.dr-torsten-finke.de/lehre/algorithmen/bachelor/algorithmen.pdf<br />

http://www.dr-torsten-finke.de/lehre/algorithmen/bachelor/algorithmen-print.pdf<br />

◮ Formalia<br />

◮ Dauer 120 Minuten<br />

◮ keine Hilfsmittel<br />

◮ Formvorschriften<br />

◮ Inhalt<br />

◮ Inhalt komplett relevant<br />

◮ kein Repetitorium<br />

◮ Auswahlklausur<br />

◮ Schwerpunkt auf Verständnis<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 3 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 4 / 235


Algorithmik – Literatur<br />

Ankündigungen<br />

Literatur<br />

Arndt, Jörg: Matters Computational – Ideas, Algorithms, Source Code.<br />

Autor, 2010.<br />

http://www.jjj.de/fxt/.<br />

Cormen, Thomas H., Charles E. Leiserson und Ronald L. Rivest:<br />

Introduction to Algorithms.<br />

The MIT Press, 3. Auflage, 2009.<br />

ISBN: 978-0262533058.<br />

Engeln-Müllges, Giesela und Frank Uhlig: Numerical Algorithms with C.<br />

Springer-Verlag, 1997.<br />

ISBN: 3540605304.<br />

Knuth, Donald E.: The Art of Computer Programming – Fascicles 0–4.<br />

Addison-Wesley, 2009.<br />

ISBN: 978-0321637130.<br />

Sedgewick, Robert: Algorithms in C.<br />

Addison-Wesley, 1990.<br />

ISBN: 978-0201514254.<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 5 / 235<br />

Algorithmik – Quelltexte<br />

Ankündigungen<br />

Literatur<br />

◮ Quelltexte sind weitgehend in Anlehnung an [Sed90] wiedergegeben.<br />

◮ Die dargestellten Programme dienen primär der Illustration der<br />

diskutierten Algorithmen. Korrekte Funktion und praktische<br />

Verwendbarkeit sind ausdrücklich nicht garantiert.<br />

◮ Die Beispiele sollen Anregungen zu eigenen Programmierübungen in<br />

beliebigen Programmiersprachen sein.<br />

◮ Programmbeispiele sind herzlich willkommen – bitte einsenden mit<br />

Angaben zur Urheberschaft und einer Lizenz (MIT, BSD, GPL etc.)<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 6 / 235<br />

Einführung<br />

Begriffe<br />

Einführung<br />

Programmcodes – C<br />

Begriffe<br />

Programmcodes – C<br />

◮ Al Chwarizmi – Algorithmus<br />

◮ Verarbeitungsvorschrift (finit, determiniert(?))<br />

◮ Darstellung:<br />

◮ Programmablaufplan (DIN 66001/ISO 5807)<br />

◮ Struktogramm (Nassi/Shneidermann, DIN 66261)<br />

◮ Pseudocode<br />

◮ maschinennah, Rechenaufwand gut bestimmbar<br />

◮ Typen: int, char, double<br />

◮ globale Variable (kompakter Code)<br />

◮ Felder: Zeiger auf erstes Element, Länge separat<br />

◮ Strukturen: struct entry { int x, y; }<br />

◮ Pointer: struct entry *p; ...; a = p->x;<br />

◮ Kontrollstrukturen<br />

◮ Operatoren<br />

◮ Ein-/Ausgabe: c = getchar(); printf("n = %d\n", n)<br />

◮ Zip-Archiv<br />

◮ andere Programmiersprachen<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 7 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 8 / 235


Einführung<br />

Größter gemeinsamer Teiler<br />

Beispiel – ggT<br />

Einführung<br />

ggT – Idee: Primfaktorzerlegung<br />

Beispiel – ggT<br />

◮ ggT(84, 231)<br />

Beispiel:<br />

◮ ggT(84, 231) =?<br />

◮ Idee?<br />

84 = 2 · 2 · 3 · 7<br />

231 = 3 · 7 · 11<br />

⇒ ggT(84, 231) = 3 · 7<br />

= 21.<br />

◮ Erforderlich:<br />

◮ Primzahlenverzeichnis<br />

◮ Listen für Faktoren<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 9 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 10 / 235<br />

Einführung<br />

Beispiel – ggT<br />

Primzahlen – Sieb des Eratosthenes<br />

Einführung<br />

Beispiel – ggT<br />

Sieb des Eratosthenes – Implementation<br />

2 3 4 5 6 7 8 9 10 11 12<br />

13 14 15 16 17 18 19 20 21 22 23 24<br />

25 26 27 28 29 30 31 32 33 34 35 36<br />

37 38 39 40 41 42 43 44 45 46 47 48<br />

49 50 51 52 53 54 55 56 57 58 59 60<br />

61 62 63 64 65 66 67 68 69 70 71 72<br />

73 74 75 76 77 78 79 80 81 82 83 84<br />

85 86 87 88 89 90 91 92 93 94 95 96<br />

97 98 99 100 101 102 103 104 105 106 107 108<br />

109 110 111 112 113 114 115 116 117 118 119 120<br />

121 122 123 124 125 126 127 128 129 130 131 132<br />

eratos(int s[], int n)<br />

{<br />

int i, k;<br />

/* prepare sieve: 1 - prime, 0 - no prime */<br />

for ( s[1] = 0, i = 2; i


Einführung<br />

Beispiel – ggT<br />

Einführung<br />

Beispiel – ggT<br />

Euklid – ggT: Idee<br />

Fläche: 30 × 21 – maximale Kachelgröße?<br />

Euklid – ggT: Pseudo-Code<br />

1: procedure gcd(u, v)<br />

2: while u > 0 do<br />

3: if u < v then<br />

4: (u, v) ← (v, u) ⊲ let u always be the greater value<br />

5: end if<br />

6: u ← u − v ⊲ try mod<br />

7: end while<br />

8: return v ⊲ gcd is v<br />

9: end procedure<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 13 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 14 / 235<br />

Einführung<br />

Beispiel – ggT<br />

Einführung<br />

Beispiel – ggT<br />

Euklid – ggT: Beispiel<br />

Euklid – ggT: Programmablaufplan<br />

◮ ggT(84, 231) =?, ggT(233, 144) =?<br />

◮ 231<br />

84<br />

147<br />

84<br />

63<br />

21<br />

42<br />

21<br />

21 ⇒ ggT(84, 231) = 21<br />

0<br />

233<br />

144<br />

89<br />

55<br />

34<br />

21<br />

13<br />

8<br />

5<br />

3<br />

2<br />

1<br />

1 ⇒ ggT(233, 144) = 1<br />

0<br />

n<br />

Start<br />

read(u,v)<br />

u,v > 0?<br />

j<br />

n<br />

u > 0?<br />

j<br />

n<br />

u < v?<br />

j<br />

(u,v) := (v, u)<br />

u := u − v<br />

print(v)<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 15 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 16 / 235


Einführung<br />

Beispiel – ggT<br />

Einführung<br />

Beispiel – ggT<br />

Euklid – ggT: Struktogramm<br />

Euklid – ggT: Implementation<br />

Loop:<br />

Input: u, v<br />

j<br />

u, v > 0<br />

while: u > 0<br />

j<br />

u < v<br />

n<br />

(u,v) := (v,u)<br />

u := u − v<br />

Output: v<br />

n<br />

int gcd(int u, int v)<br />

{<br />

int t;<br />

while (u > 0) {<br />

if (u < v) {<br />

t = u; u = v; v = t;<br />

}<br />

u = u - v;<br />

}<br />

return v;<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 17 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 18 / 235<br />

Einführung<br />

Beispiel – ggT<br />

Einführung<br />

Beispiel – ggT<br />

Euklid – Fazit<br />

Übungen<br />

◮ einfache Methode<br />

◮ einfache Operationen (Addition, Subtraktion, Vergleich)<br />

◮ einfache Datentypen<br />

◮ Beschreiben Sie die behandelten Algorithmen so, dass ein Mensch sie<br />

ausführen kann! Testen Sie Ihre Beschreibung mit einer<br />

Versuchsperson!<br />

◮ Implementieren Sie die dargestellten Algorithmen in einer<br />

Programmiersprache Ihrer Wahl!<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 19 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 20 / 235


Datenstrukturen<br />

Elementare Datenstrukturen<br />

Datenstrukturen<br />

Speicherzellen und Felder<br />

Elementare Datenstrukturen<br />

Speicherzellen und Felder<br />

◮ einfache Datenstrukturen<br />

◮ Ganzzahl – int (long int, unsigned int)<br />

◮ Fließpunkt – float, double<br />

◮ Zeichen(-kette) – char<br />

◮ aggregierte Datenstrukturen<br />

◮<br />

◮<br />

Feld<br />

Struktur<br />

◮ Arrays<br />

◮ Matrizen<br />

◮ Indizes (effizientes Vertauschen)<br />

Index i[n] Array a[m][n]<br />

/* swap rows p, q by index */<br />

t = i[p];<br />

i[p] = i[q];<br />

i[q] = t;<br />

/* now access first element */<br />

x = a[i[p]][0];<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 21 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 22 / 235<br />

Datenstrukturen<br />

Speicherzellen und Felder<br />

Datenstrukturen<br />

Lineare Datenstrukturen<br />

Feld – Operationen<br />

Liste<br />

◮ n Elemente – Problemumfang<br />

◮ Aufwand A = A(n)<br />

◮ Einfügen an gegebener Position<br />

◮ Aufbau<br />

Head<br />

Value<br />

ptr<br />

Node<br />

Value<br />

ptr<br />

Value<br />

ptr<br />

Tail<br />

A insert = O(n).<br />

◮ Löschen an gegebener Position: A remove = O(n).<br />

◮ Suchen<br />

◮<br />

◮<br />

günstigster Fall: A = O(1)<br />

ungünstigster Fall: A = O(n)<br />

◮<br />

◮<br />

◮<br />

◮<br />

Kopf<br />

Knoten<br />

Ende<br />

doppelte Verkettung<br />

◮ Funktionen<br />

◮ Initialisierung<br />

◮ Einfügen<br />

◮ Löschen<br />

◮ Traversieren(Suchen/Modifizieren)<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 23 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 24 / 235


Datenstrukturen<br />

Lineare Datenstrukturen<br />

Liste – Implementation/Initialisierung<br />

Liste – Element einfügen<br />

Datenstrukturen<br />

Lineare Datenstrukturen<br />

struct node {<br />

int key;<br />

struct node *next;<br />

};<br />

struct node *head, *z, *t;<br />

void listinitialize()<br />

{<br />

head = malloc(sizeof *head); /* get memory from OS */<br />

z = malloc(sizeof *z);<br />

head->next = z;<br />

z->next = z;<br />

}<br />

struct node *insertafter(int v, struct node *n)<br />

{<br />

struct node *x;<br />

x = (struct node *) malloc(sizeof *x);<br />

x->key = v; /* 1. insert value */<br />

x->next = n->next; /* 2. connect successor */<br />

n->next = x; /* 3. connect predecessor - why last? */<br />

return x;<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 25 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 26 / 235<br />

Liste – Element löschen<br />

Datenstrukturen<br />

Lineare Datenstrukturen<br />

void deletenext(struct node *n)<br />

{<br />

t = n->next;<br />

n->next = n->next->next; /* memory leak */<br />

free(t); /* release memory */if ( t != z ) free(t);<br />

}<br />

Datenstrukturen<br />

Liste traversieren – Element suchen<br />

◮ Suche bis Listenende<br />

Lineare Datenstrukturen<br />

struct node *search(int v, struct node *n) {<br />

while ( n != n->next ) { /* until end of list */<br />

if ( n->key == v ) break; /* found */<br />

n = n->next; /* otherwise continue */<br />

}<br />

return n;<br />

}<br />

◮ Suche bis Sentinel<br />

struct node *search(int v, struct node *n) {<br />

z->key = v; /* sentinel */<br />

while ( n->key != v ) n = n->next; /* will find */<br />

return n;<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 27 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 28 / 235


Datenstrukturen<br />

Lineare Datenstrukturen<br />

Datenstrukturen<br />

Lineare Datenstrukturen<br />

Listen – Übungen<br />

Stack/Stapel<br />

◮ LiFo<br />

push<br />

pop<br />

◮ Implementation Modifizieren<br />

◮ Aufwand der Suche nach einem Element?<br />

◮ Optimierungsstrategie für die Suche?<br />

Stackpointer<br />

◮ Stackpointer<br />

◮ Operationen<br />

◮ Initialisierung<br />

◮ Push<br />

◮ Pop<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 29 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 30 / 235<br />

Datenstrukturen<br />

Stack – Implementation/Aufbau<br />

struct node {<br />

int key;<br />

struct node *next;<br />

};<br />

Lineare Datenstrukturen<br />

static struct node *head, *z, *t;<br />

stackinit() {<br />

head = (struct node *) malloc(sizeof *head);<br />

z = (struct node *) malloc(sizeof *z);<br />

head->next = z;<br />

z->next = z; head->key = z->key = 0;<br />

}<br />

Datenstrukturen<br />

Stack – Implementation/Operation<br />

Lineare Datenstrukturen<br />

push(int v) {<br />

t = (struct node *) malloc(sizeof *t);<br />

t->key = v; t->next = head->next;<br />

head->next = t;<br />

}<br />

int pop() {<br />

int x;<br />

t = head->next; head->next = t->next;<br />

x = t->key;<br />

if ( ! stackempty() ) free(t);<br />

return x;<br />

}<br />

int stackempty() {<br />

return head->next == z;<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 31 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 32 / 235


Datenstrukturen<br />

Lineare Datenstrukturen<br />

Stack – Anwendung: UPN (̷Lukasiewicz)<br />

int b = 10, c, n, t, x;<br />

stackinit();<br />

do {<br />

x = n = 0; /* prepare to read number */<br />

for (c=getchar(); c>=’0’ && c 0) { push(x); /* got number */ }<br />

if (c == ’+’) { push(pop() + pop()); }<br />

else if (c == ’-’) { t = pop(); push(pop() - t); }<br />

else if (c == ’~’) { push(-pop()); }<br />

else if (c == ’*’) { push(pop() * pop()); }<br />

else if (c == ’/’) { if (t = pop()) push(pop()/t); }<br />

} while ( c != EOF )<br />

printf("%d\n", pop());<br />

Queue(Schlange)<br />

◮ FiFo<br />

get<br />

◮ Operationen an beiden Enden:<br />

◮<br />

◮<br />

Put<br />

Get<br />

Datenstrukturen Lineare Datenstrukturen<br />

◮ Anwendung: Schieberegister, Warteschlange<br />

put<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 33 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 34 / 235<br />

Datenstrukturen<br />

Lineare Datenstrukturen<br />

Datenstrukturen<br />

Lineare Datenstrukturen<br />

Ringspeicher<br />

Lineare Datenstrukturen – Übung<br />

Head<br />

◮ Implementieren Sie einen Stack mit einem Array!<br />

◮ Implementieren Sie die Funktionen get und put für eine Queue!<br />

◮ Implementieren Sie sinnvolle Funktionen zum Aufbau und zur<br />

Anwendung von Ringspeichern!<br />

◮ Implementieren Sie einen Infix-Parser (Hinweis: Shunting Yard<br />

Algorithmus)<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 35 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 36 / 235


Datenstrukturen<br />

Lineare Datenstrukturen<br />

Datenstrukturen<br />

Lineare Datenstrukturen<br />

Hash<br />

Hash – Beispiel<br />

◮ Hash-Funktion: z.B. modulo<br />

h(k) = k mod M<br />

◮ k komplex (große Zahl): Stellensystem (Basis b)<br />

k =<br />

◮ Modulo-Rechnung:<br />

n∑<br />

k i b i<br />

(a + b) mod M = (a mod M + b mod M) mod M<br />

(a · b) mod M = (a mod M · b mod M) mod M<br />

◮ Horner-Schema (mit impliziter Modulorechnung)<br />

i=0<br />

Hashkodes zum schnellen Finden von Schlüssel/Wert-Paaren<br />

◮ gegeben: Schlüssel k (kompliziert)<br />

◮ berechne h(k) (eventuell nicht eindeutig)<br />

◮ Aufwand der Suche A = O(1)<br />

◮ verwende h(k) als Index in einem Feld<br />

◮ jeder Feldeintrag ist ein Listenkopf<br />

◮ jede Liste enthält alle Schlüssel gleicher Hashcodes<br />

◮ Knoten tragen komplette Schlüssel und Verweise auf Werte<br />

◮ Vorteil: kurze Listen, effiziente Suche<br />

a 3 x 3 + a 2 x 2 + a 1 x + a 0 = ((a 3 x + a 2 ) · x + a 1 ) · x + a 0<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 37 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 38 / 235<br />

Datenstrukturen<br />

Lineare Datenstrukturen<br />

Hashing – Schlüssel/Wert-Verwaltung<br />

k<br />

h(k)<br />

h(k 1 )<br />

k 1<br />

v 2 v’ 2<br />

h(k 2 )<br />

k2<br />

k’ 2<br />

v 3<br />

h(k 3 )<br />

k 3<br />

M Einträge<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 39 / 235<br />

v 1<br />

Datenstrukturen<br />

Lineare Datenstrukturen<br />

Hash – Wörter zählen: Initialisierung<br />

int M = 101; /* chose prime */<br />

struct node {<br />

char *key; int val;<br />

struct node *next;<br />

} **heads, *z;<br />

unsigned hash(char *k) {<br />

for (int h=0; *k!=’\0’; k++) h=((hnext = z;<br />

}<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 40 / 235


Datenstrukturen<br />

Lineare Datenstrukturen<br />

Datenstrukturen<br />

Lineare Datenstrukturen<br />

Hash – Wörter zählen: eintragen und finden<br />

Hash – Anwendung<br />

void hashinsert(char *k, int h, int v) {<br />

struct node *new = malloc(sizeof *z);<br />

new->key = k; new->val = v;<br />

new->next = heads[h]->next;<br />

heads[h]->next = new;<br />

}<br />

struct node *hashfind(char *k, int h, int *v)<br />

{<br />

struct node *t = heads[h];<br />

z->key = k;<br />

do {<br />

t = t->next;<br />

} while ( strcmp(t->key, k) );<br />

*v = t->val;<br />

return t;<br />

}<br />

◮ sinnvolle Wahl der Hashgröße<br />

◮ Modul M prim<br />

◮ Objekte mit gleichem Hashcode: Listen<br />

◮ Identität:<br />

◮ Hashcodes verschieden: Objekte verschieden<br />

◮ Hashcodes gleich: Objekte möglicherweise gleich<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 41 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 42 / 235<br />

Datenstrukturen<br />

Lineare Datenstrukturen<br />

Datenstrukturen<br />

Bäume<br />

Hash – Übung<br />

Bäume – Aufbau<br />

Wurzel<br />

◮ Zeigen Sie, dass die Modulorechnung distributiv hinsichtlich Addition<br />

und Multiplikation ist!<br />

◮ Gegeben: Kodierungstabelle: A – 1, B – 2, C – 3, ... Z – 26<br />

b = 30, M = 97<br />

Gesucht: Hashcode der Zeichenkette ALGORITHMUS<br />

◮ Implementieren Sie ein Programm, das die vorstehende Aufgabe löst.<br />

Kante<br />

Knoten<br />

Blatt<br />

Pfad<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 43 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 44 / 235


Datenstrukturen<br />

Bäume<br />

Datenstrukturen<br />

Bäume<br />

Binär-Bäume<br />

Verzeichnis-Bäume<br />

n Knoten<br />

Tiefe t<br />

n = 2 t − 1<br />

t = log 2 (n + 1)<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 45 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 46 / 235<br />

Datenstrukturen<br />

Bäume<br />

Datenstrukturen<br />

Bäume<br />

Bäume – Traversierung<br />

Suche im Baum<br />

*<br />

M<br />

+ -<br />

H<br />

T<br />

3 4 7 2<br />

D K P W<br />

◮ Pre-Order: (* (+ 3 4) (- 7 2))<br />

◮ In-Order: ((3 + 4) * (7 - 2))<br />

◮ Post-Order: 3, 4 + 7, 2 - *<br />

◮ Level-Order: * + - 3 4 7 2<br />

B F I L<br />

A C E G<br />

N R U Y<br />

Q S X Z<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 47 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 48 / 235


Datenstrukturen<br />

Bäume<br />

Datenstrukturen<br />

Bäume<br />

Binäre Such-Bäume<br />

◮ Sortiertes Einfügen<br />

◮ Suche: A = O(log n)<br />

A<br />

100<br />

80<br />

60<br />

40<br />

20<br />

0<br />

O(n)<br />

O(log n)<br />

10 20 30 40 50 60 70 80 90 100<br />

n<br />

Baum-Implementation: Aufbau<br />

static struct node {<br />

int key, info;<br />

struct node *l, *r;<br />

};<br />

static struct node *t, *head, *z;<br />

treeinitialize()<br />

{<br />

z = (struct node *) malloc(sizeof *z);<br />

z->l = z;<br />

z->r = z;<br />

z->info = -1;<br />

head = (struct node *) malloc(sizeof *head);<br />

head->r = z;<br />

head->key = 0;<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 49 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 50 / 235<br />

Datenstrukturen<br />

Bäume<br />

Datenstrukturen<br />

Bäume<br />

Baum-Implementation: Suchen und Ausgeben<br />

int treesearch(int v)<br />

{<br />

struct node *x = head->r;<br />

z->key = v; /* sentinel */<br />

while (v != x->key)<br />

x = (v < x->key) ? x->l : x->r;<br />

return x->info;<br />

}<br />

treeprint(struct node *x)<br />

{<br />

if (x != z) {<br />

treeprint(x->l);<br />

printnode(x); /* visit In-Order */<br />

treeprint(x->r);<br />

}<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 51 / 235<br />

Baum-Implementation: Einfügen<br />

treeinsert(int v, int info)<br />

{<br />

struct node *p, *x;<br />

p = head;<br />

x = head->r;<br />

while (x != z) {<br />

p = x; x = (v < x->key) ? x->l : x->r;<br />

}<br />

x = (struct node *) malloc(sizeof *x);<br />

x->key = v;<br />

x->info = info;<br />

x->l = x->r = z;<br />

if (v < p->key) p->l = x;<br />

else p->r = x;<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 52 / 235


Datenstrukturen<br />

Knoten löschen – einfache Fälle<br />

Bäume<br />

Datenstrukturen<br />

Bäume<br />

Knoten löschen – komplizierter Fall<br />

A<br />

ein NF<br />

C<br />

E<br />

H<br />

NF ohne NF<br />

N<br />

R<br />

S<br />

kein NF<br />

C<br />

E<br />

H<br />

R<br />

P<br />

A<br />

C<br />

E<br />

H<br />

re. NF(E)<br />

N<br />

R<br />

A<br />

C<br />

H<br />

N<br />

R<br />

M<br />

P<br />

M<br />

M<br />

P<br />

M<br />

P<br />

L<br />

L<br />

L<br />

L<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 53 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 54 / 235<br />

Datenstrukturen<br />

Baum-Implementation: Löschen<br />

Bäume<br />

treedelete(int v) {<br />

struct node *c, *p, *x;<br />

z->key = v; p = head; x = head->r;<br />

while (v != x->key) { /* search node */<br />

p = x; x = (v < x->key) ? x->l : x->r;}<br />

t = x; /* t to be deleted */<br />

if (t->r == z) x = x->l; /* node is leaf, cut off */<br />

else if (t->r->l == z) { /* node’s child is leaf */<br />

x = x->r; x->l = t->l;}<br />

else { c = x->r;<br />

while (c->l->l != z) c = c->l; /* substitute */<br />

x = c->l; c->l = x->r;<br />

x->l = t->l; x->r = t->r;}<br />

if (v < p->key) p->l = x;<br />

else p->r = x;<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 55 / 235<br />

Datenstrukturen Bäume<br />

Baum-Implementation: Operationen<br />

◮ Suchen: effizient<br />

◮ Einfügen: nach erfolgloser Suche<br />

◮ Risiko: Degenaration<br />

◮ Abhilfe: Balancierte Bäume (Red-Black-Trees, AVL-Trees)<br />

◮ Löschen: schwierig – Alternative:<br />

◮<br />

◮<br />

Löschung markieren,<br />

Baum gelegentlich neu aufbauen<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 56 / 235


Algorithmen – Konzepte und Analyse<br />

Rekursion<br />

Algorithmen – Konzepte und Analyse<br />

Rekursion<br />

Einfache Rekursion – Fakultät<br />

Einfache Rekursion – Fibonacci-Folge<br />

Iteration:<br />

Rekursion:<br />

n! = n · (n − 1) · . . . · 1<br />

int fact(int n) {<br />

int f = n -- ;<br />

while (n) f *= n --;<br />

return f;<br />

}<br />

1. Abbruchbedingung für das triviale Problem;<br />

2. rekursive Verkleinerung des Problems<br />

n! = n · (n − 1)!<br />

int fact(int n) {<br />

if (n < 2) return 1;<br />

return n * fact(n-1);<br />

}<br />

◮<br />

f n = f n−2 + f n−1<br />

f 0 = f 1 = 1<br />

Übung: Implementation eines Programms zur Berechnung der<br />

Fibonacci-Folge;<br />

◮ Problem der Rekursion: überflüssige Berechnungen – schlechte<br />

Performanz<br />

◮ Verstecktes Problem: Speicherbedarf<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 57 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 58 / 235<br />

Algorithmen – Konzepte und Analyse<br />

Rekursion<br />

Algorithmen – Konzepte und Analyse<br />

Rekursion<br />

Rekursion – Teile und Herrsche<br />

Rekursion – Türme von Hanoi<br />

◮ Beispiel: Türme von Hanoi;<br />

◮ Aufgaben delegieren<br />

◮ mehrfache Anwendung der rekursiven Funktion<br />

◮ Bewege Turm von Säule A nach Säule B<br />

◮ Ziehe jeweils nur eine Scheibe<br />

◮ Immer muss die kleinere Scheibe über der größeren liegen<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 59 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 60 / 235


Algorithmen – Konzepte und Analyse<br />

Rekursion – Türme von Hanoi<br />

1: procedure Hanoi(n, a, b, c)<br />

2: if n = 1 then<br />

3: Write a → b<br />

4: else<br />

5: Hanoi(n − 1, a, c, b)<br />

6: Hanoi(1, a, b, c)<br />

7: Hanoi(n − 1, c, b, a)<br />

8: end if<br />

9: end procedure<br />

Rekursion<br />

Algorithmen – Konzepte und Analyse<br />

Rekursion<br />

Türme von Hanoi – Auflösung der Rekursion<br />

shiftn(int n, int a, int b, int c) {<br />

push(a); push(b); push(c); push(n);<br />

while ( 1 ) {<br />

while ( n > 1 ) { /* nested while instead of goto */<br />

push(a); push(b); push(c); push(n);<br />

n --; swap(c, b); /* shift(n-1, a, c, b) */<br />

}<br />

show(a, b);<br />

n = pop; c = pop; b = pop; a = pop;<br />

if ( stackempty ) break;<br />

show(a, b);<br />

n --; swap(a, c); /* shift(n-1, c, b, a) */<br />

}<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 61 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 62 / 235<br />

Algorithmen – Konzepte und Analyse<br />

Iteration statt Rekursion<br />

Rekursion<br />

Algorithmen – Konzepte und Analyse<br />

Rekursion<br />

Rekursion – Ackermann 1 -Funktion<br />

◮ Rekursion kann immer durch Iteration ersetzt werden;<br />

◮ durch formale Auflösung der Rekursion<br />

◮ durch Algorithmenanalyse<br />

◮ Iteration:<br />

◮ in der Regel performanter;<br />

◮ erfordert oft explizite Speicherverwaltung (meist per Stack)<br />

◮ Implementation meist komplizierter;<br />

◮ Rekursive Algorithmen rekursiv implementieren<br />

◮ meist leichter zu verstehen und zu warten,<br />

◮ iterative Realisierung durch optimierende Compiler.<br />

a(0, n) = n + 1<br />

a(m, 0) = a(m − 1, 1)<br />

a(m, n) = a(m − 1, a(m, n − 1))<br />

m/n 0 1 2 3 4 5 6<br />

0 1 2 3 4 5 6 7<br />

1 2 3 4 5 6 7 8<br />

2 3 5 7 9 11 13 15<br />

3 5 13 29 61 125 253 509<br />

4 13 65533<br />

5 65533<br />

1 Variante von Rózsa Péter<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 63 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 64 / 235


Algorithmen – Konzepte und Analyse<br />

Rekursion<br />

Ackermann-Funktion – Eigenschaften<br />

Algorithmen – Konzepte und Analyse<br />

Rekursion – Übungen<br />

Rekursion<br />

◮ theoretische Informatik<br />

◮ stark anwachsend – Aufwand?<br />

◮ wiederholte Berechnung – Memoization<br />

◮ Benchmarks<br />

◮ Iterative Programme für Fakultät und Fibonacci-Folge<br />

◮ Iteratives Programm für Türme von Hanoi – schwieriger<br />

◮ Iteratives Programm für die Ackermann-Funktion (mit/ohne<br />

Memoization)<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 65 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 66 / 235<br />

Algorithmen – Konzepte und Analyse<br />

Aufwandskalkulation<br />

Aufwandskalkulation<br />

Algorithmen – Konzepte und Analyse<br />

Aufwandskalkulation<br />

Aufwandskalkulation rekursiver Algorithmen<br />

◮ Aufwand A;<br />

◮ Problemgröße n;<br />

◮ Komplexität: A = A(n)<br />

◮ Ordnungsfunktion A = O(f (n)) (asymptotisch für große n)<br />

◮ Typische Ordungsfunktionen:<br />

◮ A = O(1)<br />

◮ A = O(log n)<br />

◮ A = O(n)<br />

◮ A = O(n log n)<br />

◮ A = O(n 2 )<br />

◮ A = O(2 n ) (schwierig)<br />

Pro Rekursionsschritt wird vom Eingabefeld:<br />

◮ jedes Element bearbeitet,<br />

◮ ein Element entfernt und der Rest verarbeitet<br />

A n = A n−1 + n<br />

= A n−2 + (n − 1) + n<br />

.<br />

= 1 + 2 + . . . + (n − 1) + n<br />

= n n + 1<br />

2<br />

= O(n 2 )<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 67 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 68 / 235


Algorithmen – Konzepte und Analyse<br />

Aufwandskalkulation<br />

Aufwandskalkulation rekursiver Algorithmen<br />

Pro Rekursionsschritt wird vom Eingabefeld:<br />

◮ jedes Element behandelt,<br />

◮ das Feld in Hälften zerlegt,<br />

◮ beide Hälften verarbeitet.<br />

Algorithmen – Konzepte und Analyse<br />

Aufwandskalkulation – Übung<br />

Aufwandskalkulation<br />

A n = 2 A n/2 + n, n = 2 k<br />

A 2 k = 2 A 2 k−1 + 2 k<br />

A 2 k<br />

2 k = A 2 k−1<br />

2 k−1 + 1<br />

= A 2 k−2<br />

2 k−2 + 1 + 1<br />

.<br />

= k<br />

A 2 k = k 2 k<br />

A n = O(n log n)<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 69 / 235<br />

◮ Bestimmen Sie die Ordnungen der Aufwandsfunktionen der bislang<br />

behandelten Algorithmen!<br />

◮ Stellen Sie die in Aufwandskalkulation<br />

grafisch dar!<br />

genannten Ordnungsfunktionen<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 70 / 235<br />

Sortieren<br />

Elementares Sortieren<br />

Sortieren<br />

Elementares Sortieren<br />

Sortieren – Grundkonzepte<br />

Sortieren – Vertauschen<br />

◮ vergleichen/vertauschen<br />

◮ intern/extern<br />

◮ Aufwand: N log N ... N 2<br />

◮ Speicherplatz<br />

◮ am Ort<br />

◮ Zusatzspeicher<br />

◮ stabil<br />

◮ Index<br />

◮ Einfluss Vorsortierung<br />

void swap (int a[], int i, int j)<br />

{<br />

int t;<br />

t = a[i];<br />

a[i] = a[j];<br />

a[j] = t;<br />

}<br />

/* exchange without buffer variable */<br />

#define swap(p, q) do { p ^= q; q ^= p; p ^= q; } while (0)<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 71 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 72 / 235


Sortieren<br />

Selection Sort<br />

Sortieren<br />

Selection Sort<br />

Selection Sort<br />

1: procedure SelectionSort(Feld)<br />

2: suche das kleinste Element im Feld<br />

3: vertausche es mit dem ersten Element des Feldes<br />

4: sortiere den Rest des Feldes<br />

5: end procedure<br />

◮ A excg (n) = O(n) =⇒ linear; vorteilhaft, wenn Vertauschen aufwendig<br />

◮ A comp (n) = O(n 2 /2)<br />

◮ relativ unempfindlich gegenüber Anordnung der Eingabedaten<br />

Selection Sort – Implementation<br />

selection(int a[], int n)<br />

{<br />

int i, j, imin;<br />

for (i = 1; i < n; i++) {<br />

imin = i;<br />

for (j = i + 1; j


Sortieren<br />

Insertion Sort<br />

Sortieren<br />

Insertion Sort<br />

Insertion Sort – Implementation<br />

insertion(int a[], int n)<br />

{<br />

int i, j, v;<br />

for (i = 2; i v) {<br />

a[j] = a[j - 1];<br />

j--;<br />

}<br />

a[j] = v;<br />

}<br />

}<br />

Insertion Sort – Verlauf<br />

500<br />

450<br />

400<br />

350<br />

300<br />

250<br />

200<br />

150<br />

100<br />

50<br />

’-’<br />

0<br />

0 50 100 150 200 250 300 350 400 450 500<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 77 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 78 / 235<br />

Sortieren<br />

Bubble Sort<br />

Sortieren<br />

Bubble Sort<br />

Bubble Sort<br />

Bubble Sort – Implementation<br />

1: procedure BubbleSort(Feld)<br />

2: vergleiche aufsteigend je zwei folgende Elemente des Feldes<br />

3: vertauschen wenn unsortiert ⊲ extremes Element nun auf Pos. N<br />

4: wiederhole die obigen Schritte für die Elemente bis N − 1<br />

5: end procedure<br />

◮ A excg (n) = O(n 2 /2)<br />

◮ A comp (n) = O(n 2 /2)<br />

◮ ineffizient<br />

◮ leicht zu verstehen<br />

◮ Optimierung: beenden, wenn Durchlauf ohne Vertauschung<br />

bubble(int a[], int n)<br />

{<br />

int i, j;<br />

for (i = n; i >= 1; i--) {<br />

for (j = 2; j a[j]) {<br />

swap(a, j, j-1);<br />

}<br />

}<br />

}<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 79 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 80 / 235


Sortieren<br />

Performantes Sortieren<br />

Sortieren<br />

Merge Sort<br />

Performantes Sortieren<br />

Mergesort<br />

◮ Komplexität elementarer Sortierverfahren etwa quadratisch<br />

◮ Existieren effizientere Verfahren mit A < O(n 2 ) ?<br />

◮ Idee: teile und herrsche!<br />

1: procedure MergeSort(Feld)<br />

2: teile Feld in Hälften<br />

3: sortiere Hälften per MergeSort<br />

4: verschmelze sortierte Hälften<br />

5: end procedure<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 81 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 82 / 235<br />

Sortieren<br />

Merge Sort<br />

Sortieren<br />

Merge Sort<br />

Mergesort – Eigenschaften<br />

Mergesort – Implementation<br />

◮ Teile und Herrsche<br />

◮ benötigt zusätzlichen Speicher<br />

◮ A = O(n log n)<br />

◮ stabil<br />

◮ unempfindlich gegenüber Vorsortierung<br />

mergesort(int a[], int b[], int l, int r)<br />

{<br />

int i, j, k, m;<br />

if (r > l) {<br />

m = (r+l)/2;<br />

mergesort(a, b, l, m);<br />

mergesort(a, b, m+1, r);<br />

for (i = m+1; i > l; i--) b[i-1] = a[i-1];<br />

for (j = m; j < r; j++) b[r+m-j] = a[j+1];<br />

for (k = l; k


Sortieren<br />

Merge Sort<br />

Sortieren<br />

Merge Sort<br />

Mergesort – Präparation<br />

Mergesort – Verlauf<br />

500<br />

’−’<br />

450<br />

/* wrapper */<br />

msort(int a[], int n)<br />

{<br />

int i, *b;<br />

/* additional memory */<br />

b = (int *) malloc((n+1) * sizeof(int));<br />

mergesort(a, b, 1, n);<br />

}<br />

400<br />

350<br />

300<br />

250<br />

200<br />

150<br />

100<br />

50<br />

0<br />

0 50 100 150 200 250 300 350 400 450 500<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 85 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 86 / 235<br />

Sortieren<br />

Quicksort<br />

Sortieren<br />

Quicksort<br />

Quicksort (C.A.R. Hoare)<br />

Quick Sort – Eigenschaften<br />

1: procedure QuickSort(Feld)<br />

2: wähle ein Element P des Feldes, das einsortiert werden soll<br />

3: partitioniere das Feld (unten alle kleineren, oben alle größeren)<br />

4: füge das Element zwischen den Partitionen ein<br />

5: sortiere beide Partitionen<br />

6: end procedure<br />

1: procedure Partition(Feld, P)<br />

2: Index i l startet von links<br />

3: i l stoppt, wenn sein Element größer als P<br />

4: Index i r läuft entsprechend von rechts<br />

5: Wenn beide Indizes gestoppt sind, vertausche ihre Werte<br />

6: fahre fort, bis die Indizes sich treffen<br />

7: end procedure<br />

◮ A(n) = O(n log n)<br />

◮ gutes Allzweckverfahren<br />

◮ nicht stabil<br />

◮ empfindlich, wenn Partitionierung dauerhaft asymmetrisch<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 87 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 88 / 235


Sortieren<br />

Quick Sort – Implementation<br />

Quicksort<br />

quicksort(int a[], int l, int r)<br />

{<br />

int i;<br />

if (r > l) {<br />

i = partition(a, l, r); /* lower, upper section */<br />

quicksort(a, l, i - 1); /* divide and conquer */<br />

quicksort(a, i + 1, r);<br />

}<br />

}<br />

/* wrapper -- call this */<br />

qsort(int a[], int n)<br />

{<br />

/* wrapper */<br />

quicksort(a, 1, n);<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 89 / 235<br />

Sortieren<br />

Quick Sort – Partitionierung<br />

Quicksort<br />

int partition(int a[], int l, int r)<br />

{<br />

int i, j, v, s;<br />

s = a[l - 1]; /* sentinel */<br />

i = l - 1; j = r; /* indexes */<br />

a[i] = v = a[r]; /* to be put to final position */<br />

while (1) {<br />

while (a[++i] < v);<br />

while (a[--j] > v);<br />

if (i >= j) break; /* pointers have met */<br />

swap(a, i, j); /* exchange among sections */<br />

}<br />

swap(a, i, r); /* final position */<br />

a[l - 1] = s;<br />

return (i);<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 90 / 235<br />

Sortieren<br />

Quicksort<br />

Sortieren<br />

Quicksort<br />

Quick Sort – Verlauf<br />

Quick Sort – Optimierung<br />

500<br />

’-’<br />

450<br />

400<br />

350<br />

300<br />

250<br />

200<br />

150<br />

100<br />

◮ Beseitigung der Rekursion<br />

◮ expliziter Stapel<br />

◮ Endrekursion<br />

◮ jeweils das größere Teilfeld auf Stapel<br />

◮ das kleinere Teilfeld direkt bearbeiten<br />

◮ Steigerung der Partitionssymmetrie (Median, Random)<br />

◮ Kombination mit Insertion Sort<br />

◮ kleine Teilfelder (n < 20) per Insertion Sort<br />

◮ kleine Teilfelder ignorieren – anschließend Insertion Sort<br />

50<br />

0<br />

0 50 100 150 200 250 300 350 400 450 500<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 91 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 92 / 235


Sortieren<br />

Heap Sort<br />

Sortieren<br />

Heap Sort<br />

Diskurs – Datenstruktur Heap<br />

Heap – Einfügen<br />

◮ Binärbaum mit n Knoten<br />

◮ Speicherung in Array<br />

◮ Heap-Bedingung: alle Pfade<br />

sortiert<br />

◮ schnelle Operationen –<br />

A = O(log n):<br />

◮ Einfügen eines Knotens<br />

◮ Entfernen der Wurzel<br />

◮ automatisch balanciert<br />

◮ Verwendung in<br />

Prioritätswarteschlangen<br />

A<br />

E<br />

G<br />

I M N O<br />

P R S T X<br />

upheap(int k) /* heap repair */<br />

{<br />

int c; /* assume >= 0 */<br />

c = a[k]; /* to be moved */<br />

a[0] = -1; /* sentinel */<br />

while (a[k/2] > c) {<br />

a[k] = a[k/2]; /* up */<br />

k = k/2; /* next level */<br />

}<br />

a[k] = c; /* insert */<br />

}<br />

insert(int c)<br />

{<br />

a[++N] = c; /* append */<br />

upheap(N);<br />

}<br />

A<br />

E<br />

G<br />

I M N O<br />

P R S T X L<br />

A<br />

E<br />

G<br />

I M L O<br />

P R S T X N<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 93 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 94 / 235<br />

Sortieren<br />

Heap Sort<br />

Heap – Entfernen der Wurzel (Remove)<br />

Sortieren<br />

Heap-Remove Implementation<br />

Heap Sort<br />

X<br />

A E<br />

I<br />

G<br />

P M L O<br />

R S T N<br />

/* entry k lower child */<br />

downheap(int k)<br />

{ /* ascending */<br />

int j, c;<br />

c = a[k];<br />

while (k


Sortieren<br />

Heap Sort<br />

Sortieren<br />

Heap Sort<br />

Heap-Sort<br />

Heap-Sort – Implementation<br />

1: procedure HeapSort(array)<br />

2: for all n in nodes do ⊲ build heap<br />

3: downheap(n)<br />

4: end for<br />

5: while nodes in heap do<br />

6: n ← remove() ⊲ reduce heap<br />

7: sorted ← (n, sorted)<br />

8: end while<br />

9: end procedure<br />

downheap(int a[], int n, int k)<br />

{ /* descending */<br />

int j, v = a[k];<br />

while ( k 1 ) {<br />

/* remove maximum */<br />

swap(a, 1, n);<br />

downheap(a, --n, 1);<br />

}<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 97 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 98 / 235<br />

Sortieren<br />

Heap Sort<br />

Sortieren<br />

Heap Sort<br />

Heap-Sort – Komplexität<br />

Heap-Sort – Eigenschaften<br />

◮ A build = O(N),<br />

◮ A comp = O(N log N)<br />

◮ nicht stabil<br />

◮ unempfindlich gegen Vorsortierung<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 99 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 100 / 235


Sortieren<br />

Heap Sort<br />

Zeichenketten<br />

Suchen in Zeichenketten<br />

Heap-Sort – Verlauf<br />

Suchen von Wörtern in Texten<br />

500<br />

’-’<br />

450<br />

400<br />

350<br />

300<br />

250<br />

200<br />

150<br />

100<br />

◮ gegeben:<br />

◮ Text gespeichert in Feld, Länge n<br />

◮ Zeichenfolge (Wort/Muster, Länge m), die im Text gesucht werden soll<br />

◮ m ≪ n<br />

◮ systematische Suche ab Textanfang<br />

◮ gesucht: Position der Zeichenfolge im Text<br />

◮ eventuelle Probleme bei externer Text-Speicherung:<br />

◮ langsamer Zugriff<br />

◮ Rücksetzen schwierig/unmöglich<br />

50<br />

0<br />

0 50 100 150 200 250 300 350 400 450 500<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 101 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 102 / 235<br />

Zeichenketten<br />

Wortsuche – Brute Force/Naiv<br />

Suchen in Zeichenketten – Naiv<br />

1: procedure NaiveSearch(Word, Text)<br />

2: Text ← Text + Word ⊲ sentinel<br />

3: i ← start(Text)<br />

4: Pos: for all j in Word do ⊲ compare all characters<br />

5: if Text(i + j) ≠ Word(j) then ⊲ mismatch<br />

6: i ← i + 1 ⊲ next position in Text<br />

7: next Pos<br />

8: end if<br />

9: end for<br />

10: return i − 1 ⊲ match found at position<br />

11: end procedure<br />

A = O(m · n)<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 103 / 235<br />

Zeichenketten<br />

Suchen in Zeichenketten – Naiv<br />

Brute Force Wortsuche – Implementation<br />

int brutesearch (char *p, char *a)<br />

/* a: text, p: word*/<br />

{<br />

int i, j, M = strlen (p);<br />

strcat(a, p); /* sentinel */<br />

for (i = 0, j = 0; j < M; i++, j++) {<br />

while ( a[i] != p[j] ) {<br />

i += 1 - j;<br />

j = 0;<br />

}<br />

}<br />

return i - M;<br />

}<br />

◮ Beispiel: suche aaaab in aaaaaaaaaaaaaaaaaaaab<br />

◮ wieviele Vergleiche?<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 104 / 235


Zeichenketten<br />

Knuth Morris Pratt – KMP<br />

Suchen in Zeichenketten – Knuth, Morris, Pratt<br />

Zeichenketten<br />

Knuth Morris Pratt – Wortanalyse<br />

Suchen in Zeichenketten – Knuth, Morris, Pratt<br />

◮ Idee: wiederholte Vergleiche an derselben Textstelle vermeidbar?<br />

◮ Vorteil: Wort ist bekannt<br />

◮ Beispiel: suche abend<br />

◮ Annahme: scheitern am d<br />

◮ Schlussfolgerung:<br />

◮ Wort kann an aktueller Stelle nicht stehen<br />

◮ erneute Wortsuche vor der Position von d sinnlos, da dort kein a<br />

◮ =⇒ nächste Wortsuche ab Textposition von d<br />

◮ Problem: Selbstähnlichkeit im Wort, Beispiel gegen<br />

◮ Beispiel: suche gegen<br />

◮ Annahme: scheitern am n<br />

◮ Schlussfolgerung:<br />

◮ Wort kann an aktueller Stelle nicht stehen;<br />

◮ aber: Wort könnte ab dem zweiten g stehen;<br />

◮ =⇒ nächste Wortsuche ab Textposition vom 2. g<br />

◮ Vorteil:<br />

◮ gegen – rot markierte Zeichen bereits gefunden<br />

◮ Wortvergleich ab Position 3 fortsetzen<br />

◮ kein Rücksetzen im Text<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 105 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 106 / 235<br />

Zeichenketten<br />

Suchen in Zeichenketten – Knuth, Morris, Pratt<br />

Knuth Morris Pratt – Wortanalyse Selbstähnlichkeit<br />

◮ Bestimme Position next im Wort, bei der nach Scheitern an Position<br />

j die Suche fortgesetzt wird<br />

◮ Beispiel: gegend<br />

j next[j]<br />

0 -1 sinnvoll zur Implementation<br />

1 gegend<br />

0 gegend<br />

2 gegend<br />

0 gegend<br />

3 gegend<br />

1 gegend<br />

4 gegend<br />

2 gegend<br />

5 gegend<br />

0 gegend<br />

Zeichenketten<br />

Suchen in Zeichenketten – Knuth, Morris, Pratt<br />

Knuth Morris Pratt – Implementation Suche<br />

int next[len];<br />

int kmpsearch (char *p, char *a)<br />

{<br />

int i, j, M = strlen (p);<br />

initnext (p);<br />

strcat(a, p); /* sentinel */<br />

for (i = 0, j = 0; j < M; i++, j++) {<br />

while ((j >= 0) && (a[i] != p[j])) {<br />

j = next[j];<br />

}<br />

}<br />

return i - M;<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 107 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 108 / 235


Zeichenketten<br />

Suchen in Zeichenketten – Knuth, Morris, Pratt<br />

Knuth Morris Pratt – Implementation Voranalyse<br />

int next[len];<br />

initnext (char *p)<br />

{<br />

int i = 0, j = -1, m = strlen (p);<br />

next[0] = -1;<br />

while ( i < m ) {<br />

while ((j >= 0) && (p[i] != p[j])) {<br />

j = next[j];<br />

}<br />

i++; j++;<br />

next[i] = j;<br />

}<br />

}<br />

Zeichenketten<br />

Knuth Morris Pratt – Zustandsautomat<br />

◮ Wortsuche per Automat<br />

◮ Automat spezifisch für das gesuchte Wort<br />

◮ Zustandsübergang aus Selbstähnlichkeitstabelle<br />

Suchen in Zeichenketten – Knuth, Morris, Pratt<br />

g(0) e(1) g(2) e(3) n(4) d(5)<br />

j next[j]<br />

0 -1<br />

1 0<br />

2 0<br />

3 1<br />

4 2<br />

5 0<br />

Beachte Ähnlichkeit zur eigentlichen Suche!<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 109 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 110 / 235<br />

Zeichenketten<br />

Suchen in Zeichenketten – Knuth, Morris, Pratt<br />

Knuth Morris Pratt – Simulation Automat<br />

◮ aus Selbstähnlichkeitstabelle C-Quellen erzeugen<br />

◮ nahezu identische Statements<br />

int kmpauto(char *a)<br />

{<br />

int i = -1;<br />

sm: i ++;<br />

s0: if(a[i] != ’g’) goto sm; i++;<br />

s1: if(a[i] != ’e’) goto s0; i++;<br />

s2: if(a[i] != ’g’) goto s0; i++;<br />

s3: if(a[i] != ’e’) goto s1; i++;<br />

s4: if(a[i] != ’n’) goto s2; i++;<br />

s5: if(a[i] != ’d’) goto s0; i++;<br />

return i-6;<br />

}<br />

j next[j]<br />

0 -1<br />

1 0<br />

2 0<br />

3 1<br />

4 2<br />

5 0<br />

Zeichenketten<br />

Suchen in Zeichenketten – Knuth, Morris, Pratt<br />

Knuth Morris Pratt – Simulation Automat<br />

◮ Beobachtung: Sprünge können zusammengefasst<br />

werden<br />

◮ Beispiel: s3 → s1 → s0<br />

g(0) e(1) g(2) e(3) n(4) d(5)<br />

j next[j]<br />

0 -1<br />

1 0<br />

2 -1<br />

3 0<br />

4 2<br />

5 0<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 111 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 112 / 235


Zeichenketten<br />

Suchen in Zeichenketten – Knuth, Morris, Pratt<br />

Zeichenketten<br />

Suchen in Zeichenketten – Knuth, Morris, Pratt<br />

Knuth Morris Pratt – Laufzeitautomat<br />

◮ Idee: Laufzeit-Maschinencode analog zu C-Programm<br />

◮ Hex-Dump Maschinencode (Beispiel Pentium):<br />

0: 55 push %ebp<br />

1: 89 e5 mov %esp,%ebp<br />

3: 8b 55 08 mov 0x8(%ebp),%edx<br />

6: b8 ff ff ff ff mov $0xffffffff,%eax<br />

...<br />

b: 40 inc %eax<br />

c: 80 3c 10 67 cmpb $0x67,(%eax,%edx,1) # ’g’<br />

10: 75 f9 jne b <br />

12: 40 inc %eax<br />

13: 80 3c 10 65 cmpb $0x65,(%eax,%edx,1) # ’e’<br />

17: 75 f3 jne c <br />

19: 40 inc %eax<br />

...<br />

43: 83 e8 07 sub $0x7,%eax # position found<br />

46: 5d pop %ebp<br />

47: c3 ret<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 113 / 235<br />

Knuth Morris Pratt – Laufzeitimplementation<br />

void *kmpauto(char *p) {<br />

char h[]={0x55,0x89,0xe5,0x8b,0x55,0x08,0xb8,0xff,0xff,0xff,0xff};<br />

char z[]={0x83,0xe8,0x00,0x5d,0xc3};<br />

char n[]={0x40,0x80,0x3c,0x10,0x00,0x75,0x00};<br />

int sh = sizeof(h), sn = sizeof(n), sz = sizeof(z);<br />

int i, j, l;<br />

char *c, *s, *t;<br />

l = initnext(p); /* word length */<br />

s = c = (char *) malloc(sh + sz + l * sn); /* code memory */<br />

memcpy(s, h, sh); s += sh; /* head code */<br />

for( t = p, i = 0; *t != ’\0’; t++, i++ ) {<br />

n[4] = *t; /* character to compare */<br />

n[6] = sn * (next[i] - i) - (sn-1) * (next[i]>=0); /* jump */<br />

memcpy(s, n, sn); s += sn; /* append next state */<br />

}<br />

z[2] = l-1; /* return address found */<br />

memcpy(s, z, sz); /* append rest of code */<br />

return((void *) c); } /* code’s address */<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 114 / 235<br />

Zeichenketten<br />

Suchen in Zeichenketten – Knuth, Morris, Pratt<br />

Zeichenketten<br />

Suchen in Zeichenketten – Knuth, Morris, Pratt<br />

Knuth Morris Pratt – Laufzeitaufruf<br />

Knuth Morris Pratt – Zusammenfassung<br />

...<br />

int n;<br />

int (*c)();<br />

strcat(a, p); /* sentinel */<br />

c = kmpauto(p); /* Zeiger auf Automaten */<br />

n = c(a); /* Suche */<br />

...<br />

◮ Voranalyse des Suchwortes<br />

◮ Kein Rücksetzen im Text<br />

◮ Implementation über Automaten<br />

◮ Aufwand A = O(n + m)<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 115 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 116 / 235


Zeichenketten<br />

Suchen in Zeichenketten – Boyer, Moore<br />

Zeichenketten<br />

Suchen in Zeichenketten – Boyer, Moore<br />

Boyer Moore – BM<br />

Boyer Moore – Konzept<br />

◮ Idee: Vergleich beim letzten Zeichen beginnen<br />

◮ Vorteil: meist keine Übereinstimmung<br />

◮ Folge: große Sprünge vorwärts<br />

◮ Voraussetzung: Rückwärtspositionierung erlaubt<br />

Prinzipien:<br />

◮ Vergleich am Wortende<br />

◮ bad/missing character<br />

◮ optimal: Textzeichen fehlt in Wort =⇒ Sprung um Wortlänge<br />

◮ sonst Wort verschieben bis Übereinstimmung mit Textzeichen<br />

◮ good suffix<br />

◮ ohne Selbstähnlichkeit große Sprünge<br />

◮ Selbstähnlichkeit am Ende (analog KMP)<br />

Beispiel zu bad character:<br />

◮ Suche gegen in gegeben<br />

◮ b fehlt im Wort<br />

◮ =⇒ Sprung um Wortlänge voraus<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 117 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 118 / 235<br />

Zeichenketten<br />

Boyer Moore – Analyse Bad Character<br />

Suchen in Zeichenketten – Boyer, Moore<br />

#define ASCII_LEN 256<br />

int skip[ASCII_LEN];<br />

void initskip(char *p)<br />

{<br />

int m, j;<br />

char c;<br />

m = strlen(p);<br />

for ( j = 0; j < ASCII_LEN; j++)<br />

skip[j] = m; /* normally skip word length */<br />

for ( j = 0; p[j] != ’\0’; j++ )<br />

skip[(int) p[j]] = m - j - 1;<br />

/* skip to rightmost character */<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 119 / 235<br />

Zeichenketten<br />

Boyer Moore – Implementation<br />

Suchen in Zeichenketten – Boyer, Moore<br />

/* Bad Character */<br />

bmsearch (char *p, char *a)<br />

{<br />

int i, j, t, M = strlen (p);<br />

initskip (p);<br />

strcat(a, p); /* sentinel */<br />

for (i = M - 1, j = M - 1; j >= 0; i--, j--) {<br />

while (a[i] != p[j]) {<br />

t = skip[a[i]];<br />

/* equivalent to naive method for t = 0 */<br />

i += (M - j > t) ? M - j : t;<br />

j = M - 1;<br />

}<br />

}<br />

return i;<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 120 / 235


Zeichenketten<br />

Suchen in Zeichenketten – Boyer, Moore<br />

Zeichenketten<br />

Suchen in Zeichenketten – Rabin, Karp<br />

Boyer Moore – Fazit<br />

Rabin Karp – RK<br />

◮ optimal: Kombination aus<br />

◮ good suffix<br />

◮ bad character<br />

◮ erfordert Rücksetzen im Text<br />

◮ Aufwand:<br />

worst case: A = O(n + m)<br />

durchschnittlich: A = O( n m )<br />

◮ extrem performant<br />

◮ Idee: Hashcode-Vergleich<br />

◮ Vorbereitung: Hash für Wort<br />

◮ Suche: Texthash an Wortposition vergleichen<br />

◮ Trick: Hash-Berechnung per Schiebeoperation<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 121 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 122 / 235<br />

Zeichenketten<br />

Rabin Karp – Algorithmus<br />

Suchen in Zeichenketten – Rabin, Karp<br />

Zeichenketten<br />

Rabin Karp – Hashberechnung<br />

Suchen in Zeichenketten – Rabin, Karp<br />

1: procedure RKSearch(Word, Text)<br />

2: h ← hash(Word)<br />

3: w ← length(Word)<br />

4: for i, TextLength do<br />

5: if hash(Text[i . . . i + w]) = h then<br />

6: break ⊲ match<br />

7: end if<br />

8: end for<br />

9: return i ⊲ text position of match<br />

10: end procedure<br />

◮ Nachprüfung<br />

◮ effiziente Hash-Berechnung?<br />

◮ Hashrechnung per Modulorechnung über Polynom (Horner-Schema)<br />

◮ implizite Modulorechnung (Modul q)<br />

◮ Basis b entsprechend Anzahl verschiedener Symbole<br />

◮ Position i in Text a, Hash h i über m Zeichen<br />

h i = a i b m−1 + a i+1 b m−2 + a i+2 b m−3 + . . . + a i+m−1<br />

h i+1 = a i+1 b m−1 + a i+2 b m−2 + . . . + a i+m−1 b + a i+m<br />

=⇒ h i+1 = (h i − a i b m−1 )b + a i+m<br />

h i+1 = h i b − a i B + a i+m<br />

B = b m<br />

◮ Prinzip der Teleskopsumme<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 123 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 124 / 235


Zeichenketten<br />

Rabin Karp – Implementation<br />

Suchen in Zeichenketten – Rabin, Karp<br />

#define b 256 /* Base, Alphabet’s size */<br />

#define q 8388593 /* Modulus, b q without overrun */<br />

int rksearch (char *p, char *a) /* assume strcat(a, p) */<br />

{<br />

unsigned int i, B = 1, hp = 0, ha = 0, M = strlen (p);<br />

for (i = 1; i < M; i++) B = (b * B) % q;<br />

for (i = 0; i < M; i++) {<br />

hp = (hp * b + p[i]) % q; /* prepare word hash */<br />

ha = (ha * b + a[i]) % q; /* prepare text hash */<br />

}<br />

for (i = 0; hp != ha; i++) { /* run through all text */<br />

ha = (ha + b * q - a[i] * B) % q; /* b q - ai B > 0 */<br />

ha = (ha * b + a[i + M]) % q;<br />

}<br />

return i;<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 125 / 235<br />

Rabin Karp – Fazit<br />

Zeichenketten Suchen in Zeichenketten – Rabin, Karp<br />

◮ keine komplizierte Voranalyse<br />

◮ Hash-Berechnung erfordert Nachvergleich<br />

◮ Aufwand: A = O(n + m) (ähnlich KMP)<br />

◮ kein Rücksetzen<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 126 / 235<br />

Zeichenketten Zeichenkettenklassifikation<br />

Phonetische Klassifikation – Soundex-Algorithmus<br />

Idee: Wörter von ähnlichem Klang klassifizieren<br />

◮ Phonetik – Code → Phonem<br />

◮ Vokale<br />

◮ Konsonanten – Anatomie/Lautbildungshorizonte:<br />

◮ Kehlkopf<br />

◮ Rachen<br />

◮ Gaumen (weich/hart)<br />

◮ Zähne/Zahndamm<br />

◮ Lippen<br />

◮ Nase<br />

◮ Artikulation:<br />

◮ Verschlusslaute, Dauerlaute<br />

◮ stimmhaft, stimmlos, behaucht<br />

Knuth: The Art of Computer Programming<br />

Soundex-Algorithmus<br />

Zeichenketten<br />

1: procedure Soundex(word)<br />

2: notiere Anlaut (Anfangsbuchstabe)<br />

3: ignoriere Vokale (und H, W)<br />

4: vereinzele Zeichen<br />

5: klassifiziere bis zu drei Zeichen<br />

6: fülle ggf. mit Nullen auf<br />

7: end procedure<br />

Zeichenkettenklassifikation<br />

Soundex-Klassifikation<br />

Code Phoneme Zeichen<br />

1 Labiale B, F, P, V<br />

2 Gutturale, Frikative C, G, J, K, Q, S, X, Z<br />

3 Dentale D, T<br />

4 laterale Approximanten L<br />

5 Nasale M, N<br />

6 Vibranten R<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 127 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 128 / 235


Zeichenketten<br />

Zeichenkettenklassifikation<br />

Soundex-Algorithmus – Implementierung<br />

#include /* isalpha() */<br />

char *soundex(char *str)<br />

{ /* ABCDEFGHIJKLMNOPQRSTUVWXYZ */<br />

char *tbl = "01230120022455012623010202";<br />

static char sndx[] = "A000";<br />

int cnt = 0;<br />

sndx[cnt++] = (char)toupper(*str++); /* first character */<br />

while(*str != ’\0’ && cnt < sizeof(sndx)-1) {<br />

if(isalpha(*str) && *str != *(str-1)) {<br />

sndx[cnt] = tbl[toupper(*str) - ’A’];<br />

if(sndx[cnt] != ’0’) ++cnt;<br />

}<br />

++str;<br />

}<br />

return(sndx);<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 129 / 235<br />

Soundex – Anwendung<br />

Zeichenketten Zeichenkettenklassifikation<br />

◮ Soundex-Werte:<br />

◮ Soundex(’Heidelberg’) = H341<br />

◮ Soundex(’Hotel’) = H340<br />

◮ Soundex(’Meier’) = M600<br />

◮ Soundex(’Mayr’) = M600<br />

◮ orientiert am Englischen<br />

◮ extrem einfach<br />

◮ A = O(1)<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 130 / 235<br />

Zeichenketten<br />

Zeichenkettenklassifikation<br />

Kompression<br />

Verlustlose Kompression<br />

Markov-Ketten<br />

Lauflängenkompression – Run Length Encoding (RLE)<br />

◮ Häufigkeit von Zeichen in Texten sprachabhängig<br />

◮ Häufigkeit von Digrammen, Trigrammen, N-Grammen<br />

◮ Beispiel – im Deutschen:<br />

◮ -s-c-h-, sehr wahrscheinlich<br />

◮ -s-c-e-, eher unwahrscheinlich<br />

◮ Wahrscheinlichkeit abhängig von vorangehenden Zeichen<br />

◮ Anwendung:<br />

◮ Spracherkennung<br />

◮ OCR (Optical Character Recognition)<br />

◮ Passwortgenerierung<br />

◮ Idee: manchmal tritt ein Zeichen mehrfach in Folge auf<br />

◮ Verdichten: Angabe von Zeichen und Anzahl<br />

◮ Anwendung:<br />

◮ kontraststarke Raster-Grafiken<br />

◮ Fax<br />

◮ Text mit Wiederholungszeichen (Leerzeichen)<br />

Jon Bentley: Programming Pearls, 2nd Ed., section 15.3<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 131 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 132 / 235


Kompression<br />

Lauflängenkompression – Varianten<br />

Verlustlose Kompression<br />

Kompression<br />

Lauflängenkompression – Bitmuster<br />

Verlustlose Kompression<br />

Text: AAAABBBAABBBBBCCCCCCCCABCQAAA<br />

◮ einfach: Paare (Anzahl/Zeichen)<br />

◮ 4A3B2A5B8C1A1B1C1Q3A<br />

◮ Aufblähen durch einfache Zeichen<br />

◮ Einzelzeichen ohne Zählung:<br />

◮ 4A3B2A5B8CABCQ3A<br />

◮ Ziffern können nicht kodiert werden<br />

◮ Abhilfe: Escape-Zeichen (Q – selten!)<br />

◮ QDABBBAAQEBQHCABCQ@AAA<br />

◮ Codes repräsentieren Zeichen oder Anzahlen<br />

◮ Kodierung Escape-Zeichen<br />

................<br />

.....XXXXXXX....<br />

....X.....XX....<br />

...XX......X....<br />

...X.......X....<br />

..XX............<br />

..XX............<br />

..XX............<br />

...X............<br />

...XX...........<br />

....XX.....X....<br />

.....XXXXX......<br />

................<br />

................<br />

◮ nur Anzahlen speichern<br />

◮ Zeile beginnt mit 0-Bit<br />

◮ 16<br />

5 7 4<br />

4 1 5 2 4<br />

3 2 6 1 4<br />

3 1 7 1 4<br />

2 2 12<br />

...<br />

◮ alternativ: Zeilenlänge angeben<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 133 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 134 / 235<br />

Kompression<br />

Verlustlose Kompression<br />

Lauflängenkompression – Implementierung<br />

#define out(z, k) do { fputc(k, ENC); fputc(z, ENC); \<br />

i = 1; n += 2; } while(0)<br />

int rlenc(FILE *F, FILE *ENC)<br />

{<br />

int i = 1, n = 0;<br />

char c0, c;<br />

if ( ( c0 = fgetc(F) ) == EOF ) return 0;<br />

while ( ( c = fgetc(F) ) != EOF ) {<br />

if ( c == c0 )<br />

if ( ++i > 255 ) out(c, 255);<br />

else out(c0, i);<br />

c0 = c;<br />

}<br />

out(c0, i);<br />

return n;<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 135 / 235<br />

Kompression Verlustlose Kompression<br />

Lauflängenkompression – Übung<br />

◮ Programme mit:<br />

◮ Bitmusterkompression<br />

◮ Escape-Zeichen<br />

◮ Zeichenfolgenwiederholungen<br />

◮ Programme zur Lauflängendekodierung<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 136 / 235


Kompression<br />

Verlustlose Kompression<br />

Kompression<br />

Entropiekodierung<br />

Huffman-Kompression – Entropiekodierung<br />

◮ Idee: häufige Zeichen durch kurze Codes speichern<br />

◮ Voraussetzung: Häufigkeitsauswertung<br />

◮ Günstig bei unterschiedlichen Zeichenhäufigkeiten<br />

◮ Informationsgehalt<br />

◮ Entropie<br />

Entropie (Shannon)<br />

Zeichen z<br />

Alphabet mit n Zeichen z i , i = 1 . . . n<br />

Häufigkeit/Wahrscheinlichkeit p:<br />

p = p(z)<br />

Informationsgehalt I eines Zeichens z (Anzahl erforderlicher Bits):<br />

I (z) = log 2<br />

1<br />

p(z) = − log 2 p(z)<br />

Entropie H für einen Datensatz mit m verschiedenen Zeichen:<br />

m∑<br />

H = − p i log 2 p i<br />

i=1<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 137 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 138 / 235<br />

Kompression<br />

Entropiekodierung<br />

Kompression<br />

Entropiekodierung<br />

Entropie – Information<br />

◮ Beispiel: Text mit drei verschiedenen Zeichen<br />

◮ Häufigkeiten:<br />

n 1 n 2 n 3 H<br />

1 4 100 0,31<br />

5 10 90 0,72<br />

10 30 65 1,27<br />

35 35 35 1,59<br />

◮ Entropie H steigt mit Gleichmäßigkeit der Verteilung<br />

◮ Thermodynamik: Entropie als Maß für Unordnung<br />

◮ Information vs. Chaos<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 139 / 235<br />

Entropie-Bestimmung – Implementation<br />

#include <br />

#include <br />

#define ALEN 256<br />

int main() {<br />

int k[ALEN] = {};<br />

int c, i, n = 0, z = 0;<br />

double h = 0.0, p, f;<br />

while ( ( c = getchar() ) != EOF ) {<br />

k[c] ++; n ++; /* count characters frequency and total */<br />

}<br />

f = 1.0 / n; /* use double precision arithmetic */<br />

for ( i = 0; i < ALEN; i ++ ) {<br />

if ( k[i] ) {<br />

p = f * k[i]; h -= p * log2(p);<br />

}<br />

}<br />

printf("%lg\n", h);<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 140 / 235


Kompression<br />

Huffman-Kompression<br />

Kompression<br />

Huffman-Kompression<br />

Huffman-Kompression – Baumkodierung<br />

Huffman-Kodierung<br />

Text: ABRACADABRA (11 Zeichen × 8 bit = 88 bit)<br />

(11)<br />

Beispiel-Code:<br />

A<br />

( 6)<br />

5 A: 0<br />

0<br />

1<br />

2 B: 10<br />

1 C: 1110<br />

1 D: 1111<br />

B<br />

( 4)<br />

0<br />

1<br />

2 R: 110 R<br />

( 2)<br />

0<br />

1<br />

1. zähle Häufigkeit aller Zeichen<br />

2. sortiere Zeichen nach Häufigkeit (Binärbaum – Heap)<br />

3. bilde Huffman-Codes durch Traversierung<br />

4. Speichere Coding<br />

5. Speichere Codes aller Zeichen<br />

0<br />

1<br />

Code: 0 10 110 0 1110 0 1111 0 10 110 0 (23 Bit)<br />

C<br />

D<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 141 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 142 / 235<br />

Huffman-Baum – Beispiel<br />

Kompression<br />

Huffman-Kompression<br />

Kompression<br />

Aufbau Huffman-Baum – Beispiel<br />

Huffman-Kompression<br />

Zeichenhäufigkeit (Beispiel)<br />

Zeichen Anzahl<br />

a 94<br />

b 51<br />

c 155<br />

d 100<br />

e 257<br />

f 124<br />

g 25<br />

h 78<br />

i 212<br />

j 14<br />

Frequency Heap<br />

(1110)<br />

Huffman Code Tree<br />

(1110)<br />

1 0<br />

(641) (469)<br />

1 0 1 0<br />

(362) (279) e(257) i(212)<br />

1 0 1 0<br />

(194) (168) c(155) f(124)<br />

0 1 0 1<br />

a(94) d(100) h(78) (90)<br />

1 0<br />

b(51) (39)<br />

1 0<br />

g(25) j(14)<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 143 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 144 / 235


Kompression<br />

Huffman-Kompression<br />

Kompression<br />

Huffman-Kompression<br />

Aufbau Huffman-Baum – Beispiel<br />

Coding-Tabelle des Beispiels<br />

Zeichen Anzahl Code<br />

a 94 1110<br />

b 51 11011<br />

c 155 101<br />

d 100 1111<br />

e 257 01<br />

f 124 100<br />

g 25 110101<br />

h 78 1100<br />

i 212 00<br />

j 14 110100<br />

11111110 11011010 01101010 11111000 11100010 00100111 10101 ?<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 145 / 235<br />

Huffman-Codierung – Implementation<br />

#define ALEN 256 /* symbols in alphabet */<br />

#define BLKSIZE 0x10000<br />

compress(FILE *F, FILE *C)<br />

{<br />

int M, N;<br />

char a[BLKSIZE]; /* buffer */<br />

int sym[2*ALEN], cnt[2*ALEN], pnt[2*ALEN];<br />

int code[ALEN], len[ALEN];<br />

M = input(F, a, BLKSIZE); /* read block */<br />

N = frequency(a, cnt); /* N different symbols */<br />

initheap(sym, cnt, ALEN); /* construct heap */<br />

hufftree(N, sym, cnt, pnt); /* coding tree */<br />

huffcode(pnt, code, len); /* codes and lengths */<br />

output(C, code, len, a, M);<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 146 / 235<br />

Kompression<br />

Huffman-Kompression<br />

Kompression<br />

Huffman-Kompression<br />

Huffman-Codierung – indirektes Einfügen Heap<br />

/* move symbol k in heap (size N) down to */<br />

/* appropriate position - given by it’s count */<br />

void idownheap(int sym[], int cnt[], int N, int k)<br />

{<br />

int j, c;<br />

c = sym[k];<br />

while (k


Kompression<br />

Huffman-Kompression<br />

Kompression<br />

Huffman-Kompression<br />

Huffman-Codierung – Baum<br />

void hufftree(int N, int sym[], int cnt[], int pnt[])<br />

{<br />

int t;<br />

while (N > 1) {<br />

t = sym[1]; sym[1] = sym[N--]; /* remove heap root */<br />

idownheap(sym, cnt, N, 1); /* and reorder heap */<br />

cnt[ALEN+N] = cnt[sym[1]] + cnt[t]; /* join lowest */<br />

pnt[t] = ALEN + N; /* old root: parents lower child */<br />

pnt[sym[1]] = -ALEN - N; /* new root: upper child */<br />

sym[1] = ALEN + N; /* replace root by lowest pair */<br />

idownheap(sym, cnt, N, 1); /* reorder heap */<br />

}<br />

pnt[ALEN + N] = 0; /* tree’s root */<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 149 / 235<br />

Huffman-Codierung – Code-Bestimmung<br />

void huffcode(int pnt[], int code[], int len[])<br />

{<br />

int i, j, k, t, x;<br />

for (k = 0; k set bit */<br />

x += j; t = -t;<br />

}<br />

t = pnt[t]; /* move up tree */<br />

j += j; i++; /* next bit, increase code length*/<br />

}<br />

code[k] = x; len[k] = i;<br />

}<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 150 / 235<br />

Kompression<br />

Huffman-Kompression<br />

Kompression<br />

Huffman-Kompression<br />

Kompletter Huffman-Baum (für Programm-Quelltext)<br />

Huffman-Codierung – Fazit<br />

N(45)<br />

(7846)<br />

1<br />

0<br />

(4477)<br />

(3369)<br />

0 1<br />

1<br />

0<br />

0x20(1934) (2543)<br />

(1852)<br />

(1517)<br />

1<br />

0<br />

1 0<br />

1 0<br />

(1360)<br />

(1183)<br />

(998)<br />

(854)<br />

(785)<br />

(732)<br />

1<br />

0<br />

1 0<br />

1<br />

0<br />

1<br />

0<br />

1 0 0 1<br />

(702)<br />

(658)<br />

(605) (578)<br />

(527)<br />

(471)<br />

(431)<br />

(423)<br />

(406) (379) 0xA(365) (367)<br />

1<br />

0 0 1<br />

1 0 1 0<br />

1 0<br />

1 0 0 1 1 0 0 1 0 1 0 1<br />

(361)<br />

(341) e(317) n(341)<br />

(315) (290) i(289) t(289) (272)<br />

(255)<br />

(240) (231) ((212) r(219) )(212) (211) ,(198) ;(208) c(189) (190) o(183) (184)<br />

1 0<br />

1 0<br />

1 0 1 0 0 1 0 1 0 1 1 0<br />

1 0 0 1 1 0<br />

f(183) (178)<br />

(173) (168)<br />

(162) (153) =(147) (143) d(135) s(137) a(123) (132) *(119) (121) l(117) (114)<br />

(108) (103)<br />

0x9(94) (96) p(93) (91)<br />

1 0 1 0 0 1 0 1<br />

1 0<br />

1<br />

0 1 0 0 1 1 0 0 1 0 1 0 1 1 0<br />

(90) (88) h(87) u(86) [(84) (84) E(78) ](84) (78) (75)<br />

(73)<br />

(70) 0x22(66) (66)<br />

b(60) (61) m(57) (57) {(54) }(54) +(50) (53)<br />

0(47) (49) L(46) (45)<br />

1 0<br />

0 1 0 1 1 0 0 1 1 0 0 1 1 0 0 1<br />

1 0 1 0 0 1 1 0<br />

T(45) (44) (44)<br />

1(42) (42)<br />

k(39) (39) /(37) x(38) z(37) (36) >(34) A(36) -(34)


Kompression<br />

Verlustbehaftete Kompression – DCT<br />

Diskrete Kosinus-Transformation – DCT (JPEG)<br />

Kompression<br />

Verlustbehaftete Kompression – DCT<br />

Diskrete Kosinus-Transformation – DCT<br />

Abbildung:<br />

◮ Idee: Signal-Approximation durch Überlagerung von Schwingungen<br />

◮ äquidistantes Signal x i über n Samples (z.B. Farbwerte in Pixelfolge)<br />

◮ Mittelwert + Oberschwingungen<br />

◮ Frequenz Grundschwingung: halbe Periode<br />

◮ Amplituden A k = ?<br />

X 0 =<br />

√<br />

1<br />

n<br />

i=0<br />

X = dct(x), R → R<br />

∑n−1<br />

√<br />

2 ∑n−1<br />

x i , X k = x i cos<br />

n<br />

i=0<br />

π(2i + 1)k<br />

, k = 1 . . . n − 1<br />

2n<br />

A 0 =<br />

√<br />

1<br />

n X 0, A k =<br />

√<br />

2<br />

n X k, k = 1 . . . n − 1<br />

http://www.faqs.org/faqs/compression-faq<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 153 / 235<br />

Vorteil:<br />

◮ rein reelle Rechnung<br />

◮ sehr performant berechenbar (ähnlich Fast Fourier Transformation,<br />

A = O(n log n))<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 154 / 235<br />

Kompression<br />

Verlustbehaftete Kompression – DCT<br />

Kompression<br />

Verlustbehaftete Kompression – DCT<br />

DCT – Signalapproximation<br />

DCT – Approximation<br />

DCT - Signalapproximation<br />

140<br />

120<br />

Signal<br />

11. Oberschwingung<br />

Approximation<br />

◮ Inverse DCT approximiert Ursprungssignal x<br />

◮ Amplituden fallen oft mit steigender Frequenz<br />

Grauwert 0-255<br />

100<br />

80<br />

60<br />

√ √<br />

1 2<br />

x i =<br />

n X 0 +<br />

n<br />

x = idct(X)<br />

∑n−1<br />

X k cos<br />

k=1<br />

π(2i + 1)k<br />

, i = 0 . . . n − 1<br />

2n<br />

0 2 4 6 8 10 12 14<br />

Pixel xi<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 155 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 156 / 235


DCT – Kompression<br />

Kompression Verlustbehaftete Kompression – DCT<br />

◮ Idee: Quantisierung<br />

◮ untere Bits der Amplituden ausblenden<br />

◮ z.B. 0xb9 & ~7 = 0xb8<br />

◮ Anzahl Ausblendungs-Bits variabel<br />

◮ Ausblendung ↑ Qualität ↓ Kompression ↑<br />

◮ Amplituden entropie-kodieren<br />

◮ optional: statt Amplituden ihre Differenzen kodieren<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 157 / 235<br />

Kompression<br />

DCT-Kompression – Beispiel<br />

Folge von 16 Pixeln (Grauwerte 0–255)<br />

x i X k X c x a<br />

101 380 380 102<br />

69 7 0 62<br />

64 -66 -64 69<br />

140<br />

82 -19 -16 81<br />

120<br />

89 46 48 80<br />

114 20 16 114<br />

140 11 16 140<br />

100<br />

130 6 0 129<br />

126 6 0 121<br />

80<br />

111 9 16 114<br />

90 12 16 97 60<br />

81 10 16 85<br />

76 -5 0 72<br />

75 -3 0 74<br />

86 -1 0 90<br />

86 2 0 91<br />

Grauwert 0-255<br />

Verlustbehaftete Kompression – DCT<br />

DVT - Quantisierung 4/8 bit<br />

Signal<br />

Approximation<br />

0 2 4 6 8 10 12 14<br />

Pixel xi<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 158 / 235<br />

Kompression<br />

Verlustbehaftete Kompression – DCT<br />

Kryptologie<br />

Kryptologie – Prinzipien<br />

DCT – Anwendung JPEG<br />

Kryptologie – Prinzip<br />

1. Farbraumkonvertierung RGB → YCbCr<br />

2. Blockbildung 8 × 8 Pixel<br />

3. zweidimensionale DCT über Block<br />

4. Quantisierung (skalierbar)<br />

5. Entropiekodierung<br />

6. Artefakte<br />

◮ Nachricht M<br />

◮ Schlüssel K<br />

◮ Verschlüsselungsverfahren E<br />

◮ Chiffre C = E(M, K)<br />

◮ Entschlüsselungsverfahren D (oft ähnlich E)<br />

◮ Entschlüssel K ′ (oft leicht aus K zu ermitteln)<br />

◮ M = D(C, K ′ )<br />

◮ Kerckhoff-Prinzip<br />

◮ Problem: Sicherheit der Schlüssel<br />

JPEG<br />

PNG<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 159 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 160 / 235


Kryptologie<br />

Kryptologie – Elementarverfahren<br />

Kryptologie<br />

Kryptologie – Elementarverfahren<br />

Kryptologie – Typen<br />

Caesar-Chiffre<br />

◮ Klassische Verfahren<br />

◮ Caesar-Chiffre (Verschiebung)<br />

◮ Substitutionschiffre (A, B, C, . . . → P, D, G, . . . )<br />

◮ Vigenere-Chiffre (unterschiedliche Verschiebung)<br />

◮ Vernam-Chiffre<br />

◮ Schlüssellänge = Nachrichtenlänge<br />

◮ One-Time-Pad (Zufall)<br />

◮ XOR<br />

◮ Symmetrische Verfahren<br />

◮ DES (Data Encryption Standard), 3DES (Blockchiffre)<br />

◮ AES (Advanced Encryption Standard), Serpent, Twofish<br />

◮ Asymmetrische Verfahren<br />

◮ RSA (Rivest, Shamir, Adleman)<br />

◮ Elgamal<br />

◮ Alphabet A, n = |A|<br />

◮ Verschiebung k<br />

◮ Zeichen z ′ ← (z + k) mod n<br />

◮ k leicht zu erraten<br />

Beispiel: Rot13 (in Perl):<br />

#!/usr/bin/perl -p<br />

y/a-zA-Z/n-za-mN-ZA-M/;<br />

Übung: Rot13 in beliebiger Programmiersprache<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 161 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 162 / 235<br />

Kryptologie<br />

Symmetrische Kryptologie – DES<br />

Symmetrische Verschlüsselung – DES (IBM)<br />

Kryptologie<br />

Public Key – Diffie Hellman<br />

Asymmetrische Kryptologie<br />

◮ blockweise (64 bit) Verschlüsselung (56 Bit)<br />

◮ iteratives Vertauschen in 19 Schritten<br />

C = E(M, K)<br />

M = D(C, K)<br />

◮ verbessert als Triple-DES (3DES mit 112 Bit Key K)<br />

K = (K 1 , K 2 )<br />

C = E(D(E(M, K 1 ), K 2 ), K 1 )<br />

M = D(E(D(C, K 1 ), K 2 ), K 1 )<br />

Idee:<br />

◮ jeder Teilnehmer verwendet ein Schlüsselpaar (G, P)<br />

◮ G geheim, P öffentlich<br />

◮ G und P einfach gemeinsam berechenbar<br />

◮ M = G(P(M))<br />

◮ Ableiten von G aus P schwierig (Primzahlrechnung)<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 163 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 164 / 235


Kryptologie<br />

Verschlüsselung und Primzahlen<br />

Asymmetrische Kryptologie<br />

Kryptologie<br />

Asymmetrische Kryptologie<br />

Public Key – RSA – Schlüssel-Konstruktion<br />

Berechne:<br />

Teiler von:<br />

1983731287 × 943765649<br />

1781137561759059887<br />

1. wähle Primzahlen p, q ≫ 1 (real über 100 Stellen)<br />

2. N = p · q, z.B. p = 47, q = 79 ⇒ N = 3713<br />

3. N öffentlich<br />

4. berechne Z = (p − 1)(q − 1), hier Z = 3588<br />

5. wähle Primzahl d > p, q, z.B. d = 97<br />

6. bestimme e mit (e · d) mod Z = 1 (z.B. e = 37, meist relativ klein)<br />

7. e öffentlich, d geheim<br />

8. p, q, Z verwerfen<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 165 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 166 / 235<br />

Kryptologie<br />

Asymmetrische Kryptologie<br />

Kryptologie<br />

Kryptologie – Arithmetik großer Zahlen<br />

Public Key – RSA<br />

Public Key – RSA – Umsetzung<br />

◮ Verschlüsseln<br />

◮ öffentliche Schlüssel N und e des Adressaten beschaffen<br />

◮ C = M e mod N<br />

◮ Beispielnachricht: ATTACK..., M = 01 20 20 01 03 11 . . .<br />

◮ blockweise: 0120 37 mod 3713 = 1404, . . .<br />

◮ Entschlüsseln<br />

◮ M = C d mod N<br />

◮ im Beispiel: 1404 97 mod 3713 = 0120<br />

◮ Schwierigkeiten:<br />

◮ Primzahlen p, q finden<br />

◮ Arithmetik großer Zahlen (Karatsuba, FFT)<br />

◮ öffentlichen Schlüssel e aus Geheimschlüssel d finden (erweiterter<br />

Euklidischer Algorithmus)<br />

◮ deutlich rechenaufwändiger/langsamer als symmetrische Verfahren<br />

◮ Kombination mit symmetrischen Verfahren<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 167 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 168 / 235


Kryptologie<br />

Kryptologie – Arithmetik großer Zahlen<br />

Diskurs: Multiplikation großer Zahlen<br />

Karatsuba: teile und herrsche rekursiv A = O(n log 2 3 ) ≈ O(n 1,585 )<br />

x = x 2n−1 b 2n−1 + . . . + x n b n + x n−1 b n−1 + . . . + x 0<br />

= x h B + x l , B = b n<br />

y = y h B + y l<br />

Beispiel: 4853762169725189<br />

} {{ }<br />

2 n=16<br />

= } 48537621 {{ } ·<br />

x h<br />

x · y = (x h B + x l ) · (y h B + y l )<br />

B=10 n<br />

{}}{<br />

10 8 + 69725189 } {{ }<br />

x l<br />

= x h y<br />

}{{} h B 2 + (x h y l + x l y h ) B + x<br />

} {{ } l y<br />

}{{} l<br />

H<br />

M+H+L<br />

L<br />

M = (x h − x l ) · (y l − y h ) = x h y l + x l y h − x h y h − x l y l<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 169 / 235<br />

Kryptologie<br />

Arithmetik mit großen Zahlen – Typen<br />

◮ Datentyp (Ziffer, Zahl, Vorzeichen)<br />

◮ Deklaration<br />

Kryptologie – Arithmetik großer Zahlen<br />

#define BASE 10 /* minimize conversion effort at I/O */<br />

typedef int digit;<br />

struct bignum {<br />

int n; /* number of digits */<br />

int neg; /* sign: 1 - negative, 0 - otherwise */<br />

digit *d; /* digits stored in big endian */<br />

};<br />

typedef struct bignum bignum;<br />

◮ Konstruktor<br />

bignum *newnum(int n, int neg, digit *d) {<br />

bignum *b = (bignum *) resize(NULL, sizeof(bignum));<br />

b->n = n; b->neg = neg;<br />

b->d = (digit *) resize(b->d, n * sizeof(digit));<br />

return b;<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 170 / 235<br />

Kryptologie Kryptologie – Arithmetik großer Zahlen<br />

Arithmetik mit großen Zahlen – Operationen<br />

◮ Beispiel Addition(Annahme: Vorzeichen, Ziffernanzahl gleich)<br />

Kryptologie<br />

Kryptologie – Arithmetik großer Zahlen<br />

Arithmetik mit großen Zahlen – Übungen<br />

◮<br />

bignum *add(bignum *x, bignum *y) {<br />

int i, n = x->n; digit *u = x->d, *v = y->d, *w;<br />

bignum *z = newnum(n+1, x->neg, NULL); w = z->d;<br />

for ( i = 0; i < n; i ++ ) *(w++) = *(u++) + *(v++);<br />

carry(z); return z;<br />

}<br />

Übertrag<br />

void carry(bignum *a) {<br />

digit c = 0, *d = a->d; int n = a->n;<br />

for (d += n; n; n--) {<br />

c += *(--d); *d = c % BASE; c /= BASE;<br />

if ( *d < 0 ) { *d += BASE; c--; }<br />

}<br />

}<br />

◮ Bibliothek implementieren mit<br />

◮ Ein-, Ausgabe,<br />

◮ Addition, Negation, Subtraktion,<br />

◮ Multiplikation (klassisch und Karatsuba),<br />

◮ Hilfsfunktionen (Speicherverwaltung, Normalisierung, Vergleich);<br />

◮ Mit Standardbibliotheken vergleichen.<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 171 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 172 / 235


Diskurs: Modulorechnung<br />

Kryptologie Kryptologie – Arithmetik großer Zahlen<br />

◮ Beispiel: Modul M = 13<br />

◮ implizite Modulorechnung<br />

◮ 7 + 11 =?, 15 + 21 =?<br />

◮ 7 · 5 =?, 8 · 9 =?<br />

◮ 8 − 3 =?, 3 − 7 =?, 7 − 12 = x ⇔ x + 12 = 7<br />

◮ 6 · 11 =?, 6 · 6 −1 = 1 ⇒ 6 −1 = 11 (Inverse)<br />

Kryptologie<br />

Modulorechnung für Potenzen<br />

Kryptologie – Arithmetik großer Zahlen<br />

◮ Beispiel: 87 173 mod 97 =?<br />

◮ implizite Modulorechnung: a ⊙ b ≡ (a · b) mod M<br />

◮ 87 173 mod 97 = 87<br />

}<br />

⊙ 87 ⊙ 87<br />

{{<br />

. . . 87 ⊙ 87<br />

}<br />

mod97<br />

172 Multiplikation<br />

◮<br />

◮<br />

173 D = 10101101 B<br />

⇒ 87 173 mod 97 = 87 128+32+8+4+1 mod 97<br />

= 87 128 ⊙ 87 32 ⊙ 87 8 ⊙ 87 4 ⊙ 87 1 mod 97<br />

a 0 = 87<br />

a k+1 = a k ⊙ a k<br />

⇒ 87 173 mod 97 = a 0 ⊙ a 2 ⊙ a 3 ⊙ a 5 ⊙ a<br />

} {{ } 7<br />

10 Multiplikationen<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 173 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 174 / 235<br />

Kryptologie<br />

Kryptologie – Arithmetik großer Zahlen<br />

Modulorechnung für Potenzen – Programm<br />

typedef unsigned long long int unum;<br />

extern unum M;<br />

unum mprod(unum a, unum b) /* a * b */<br />

{<br />

return( ((a % M) * (b % M)) % M );<br />

}<br />

unum mpow(unum a, unum b) /* a ** b */<br />

{<br />

unum c = 1;<br />

a = a % M;<br />

while ( b ) {<br />

if ( b & 1 ) c = mprod(c, a);<br />

a = mprod(a, a); b >>= 1;<br />

}<br />

return c;<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 175 / 235<br />

RSA – Schlüsselzusammenhang<br />

Kryptologie Kryptologie – Arithmetik großer Zahlen<br />

◮ Modul Z = (p − 1)(q − 1)<br />

◮ Schlüssel d geheim<br />

◮ öffentlicher Schlüssel e =?<br />

◮ e invers zu d bezüglich Modul Z<br />

◮ Erweiterter Euklidischer Algorithmus: xgcd()<br />

e d ≡ 1 (mod Z)<br />

1 ≡ gcd(Z, d)<br />

= x · Z + y · d<br />

(x, y) = xgcd(Z, d)<br />

⇒ e = y mod Z<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 176 / 235


Kryptologie<br />

Erweiterter Euklidischer Algorithmus<br />

g = gcd(a, b)<br />

Kryptologie – Arithmetik großer Zahlen<br />

g = x · a + y · b, (x, y) =?<br />

(x, y) = xgcd(a, b)<br />

r 0 = a = (s 0 = 1) · a + (t 0 = 0) · b<br />

r 1 = b = (s 1 = 0) · a + (t 1 = 1) · b q = ⌊r 0 /r 1 ⌋<br />

r 2 = r 0 − q r 1 =(s 2 = s 0 − q s 1 ) · a+(t 2 = t 0 − q t 1 ) · b q = ⌊r 1 /r 2 ⌋<br />

. . . . . .<br />

r n = 0=r n−2 − q r n−1 =(s n−2 − q s n−1 ) · a+(t n−2 − q t n−1 ) · b<br />

r n−1 = gcd(a, b) ⇒ x = s n−1 , y = t n−1<br />

Kryptologie<br />

Kryptologie – Arithmetik großer Zahlen<br />

Erweiterter Euklidischer Algorithmus – Beispiel<br />

◮ Modul M = 31<br />

◮ bestimme das Inverse e zu d = 13!<br />

◮ (x, y) = xgcd(M, d)<br />

◮ e = y<br />

mod M<br />

i r i = M · s i + d · t i q = ⌊r i−1 /r i ⌋<br />

0 31= 31 · 1 + 13 · 0<br />

1 13= 31 · 0 + 13 · 1 2<br />

2 5 = 31 · 1 + 13 · −2 2<br />

3 3 =31 · −2+ 13 · 5 1<br />

4 2 = 31 · 3 + 13 · −7 1<br />

5 1 =31 · −5+ 13 · 12 2<br />

n = 6 0 = 31 · 13 +13 · −31<br />

⇒ e = t n−1 = 12 wegen 12 · 13 ≡ 1 (mod 31)<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 177 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 178 / 235<br />

Kryptologie<br />

Kryptologie – Arithmetik großer Zahlen<br />

Erweiterter Euklidischer Algorithmus – Implementation<br />

Public Key – Anwendung<br />

Kryptologie<br />

Kryptologie – Anwendung<br />

int xgcd(int a, int b, int *x, int *y) {<br />

int r[2] = {a, b}, s[2] = {1, 0}, t[2] = {0, 1}, i, n;<br />

A<br />

M<br />

}<br />

for ( i = 0; r[n = !i]; i = n ) {<br />

int q = r[i] / r[n];<br />

r[i] -= q * r[n];<br />

s[i] -= q * s[n];<br />

t[i] -= q * t[n];<br />

}<br />

*x = s[i]; *y = t[i]; /* (x, y) = xgcd(a, b) */<br />

return r[i]; /* = gcd(a, b) */<br />

M<br />

S<br />

GS<br />

PS<br />

C<br />

GA<br />

PA<br />

E<br />

GE<br />

PE<br />

M<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 179 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 180 / 235


Kryptologie<br />

Kryptologie – Anwendung<br />

Geometrie<br />

Geometrische Objekte<br />

Public Key – RSA – Übung<br />

Koordinaten<br />

◮ Beispielzahlen p, q, d, e bestimmen/ermitteln,<br />

◮ Nachricht M erstellen und in Chiffre C verschlüsseln,<br />

◮ Chiffre C entschlüsseln.<br />

y<br />

r<br />

(x,y)<br />

◮ kartesisch: (x, y)<br />

◮ polar: (r, ϕ)<br />

◮ komplex:<br />

◮ z = x + i y = r e<br />

i ϕ<br />

◮ x = r cos ϕ, y = r sin ϕ<br />

ϕ<br />

x<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 181 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 182 / 235<br />

Geometrie<br />

Punkte, Strecken, Polygone<br />

Geometrische Objekte<br />

Geometrie<br />

Geometrische Objekte kodieren<br />

Geometrische Objekte<br />

A<br />

Punkt<br />

(x,y)<br />

Strecke<br />

P<br />

(x 1<br />

,y 1<br />

)<br />

A<br />

Q<br />

(x 2<br />

,y 2<br />

)<br />

F<br />

(x 1<br />

,y 1<br />

)<br />

B<br />

Rechteck<br />

(x 1<br />

,y 1<br />

)<br />

E<br />

D<br />

C<br />

Polygon<br />

A B<br />

(x 2<br />

,y 2<br />

)<br />

(x 2<br />

,y 2<br />

)<br />

◮ Koordinaten<br />

◮ Kennzeichen<br />

struct point { int x, int y; char c; };<br />

struct line { struct point p1, p2; };<br />

struct rect { struct point ul, or; };<br />

struct point polygon[N];<br />

typedef struct point point;<br />

typedef struct line line;<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 183 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 184 / 235


Geometrie<br />

Schnitt von Strecken<br />

Geometrie<br />

Schnitt von Strecken<br />

Schnitt von Strecken<br />

Orientierung von Strecken<br />

Funktion ccw(P0, P1, P2) (counter clockwise)<br />

D<br />

B<br />

P2<br />

◮ P 0 P 2 steiler als P 0 P 1<br />

⇒ ccw() = 1<br />

A<br />

C<br />

P0<br />

dx2<br />

ccw<br />

dy2<br />

dx1<br />

P1<br />

dy1<br />

◮ P 0 P 2 flacher als P 0 P 1<br />

⇒ ccw() = −1<br />

◮ P 0 , P 1 , P 2 kollinear:<br />

◮ P 0 → P 1 → P 2<br />

⇒ ccw() = 1<br />

◮ P 0 → P 2 → P 1<br />

⇒ ccw() = 0<br />

◮ P2 → P 0 → P 1<br />

⇒ ccw() = −1<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 185 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 186 / 235<br />

Geometrie<br />

Schnitt von Strecken<br />

Orientierung von Strecken – CCW(Implementierung)<br />

int ccw(point p0, point p1, point p2)<br />

{ /* P2 left to P0->P1 ? */<br />

int dx1, dx2, dy1, dy2;<br />

dx1 = p1.x - p0.x; dy1 = p1.y - p0.y;<br />

dx2 = p2.x - p0.x; dy2 = p2.y - p0.y;<br />

if ( dx1*dy2 > dy1*dx2 ) /* slope P0-P1, P0-P2 */<br />

return 1; /* left - ccw */<br />

if ( dx1*dy2 < dy1*dx2 )<br />

return -1; /* right */<br />

/* else collinear cases */<br />

if ((dx1*dx2 < 0) || (dy1*dy2 < 0))<br />

return -1; /* different directions from P0 */<br />

if ((dx1*dx1 + dy1*dy1) < (dx2*dx2 + dy2*dy2))<br />

return 1; /* P0 -> P1 -> P2 */<br />

return 0; /* P0 -> P2 -> P1 (P2 in between) */<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 187 / 235<br />

Schnitt von Strecken<br />

Strecken schneiden sich, wenn<br />

Geometrie<br />

Schnitt von Strecken<br />

◮ Enden der Strecke AB auf verschiedenen Seiten von CD und<br />

◮ Enden der Strecke CD auf verschiedenen Seiten von AB<br />

int intersect(line l1, line l2)<br />

{<br />

return ( ((ccw(l1.p1, l1.p2, l2.p1)<br />

* ccw(l1.p1, l1.p2, l2.p2))


Geometrie<br />

Einfacher geschlossener Pfad<br />

Polygon<br />

Geometrie<br />

Polygon<br />

Einfacher geschlossener Pfad – Algorithmus<br />

◮ gegeben: Punktemenge P i<br />

◮ gesucht: Linienzug, der<br />

◮ alle Punkte erreicht<br />

◮ sich selbst nicht schneidet<br />

1. wähle einen (innenliegenden) Punkt als Anker A (Ursprung)<br />

2. berechne Winkel α i zwischen Abszisse und A P i<br />

3. sortiere Punkte nach aufsteigendem Winkel<br />

4. verbinde die sortierten Punkte<br />

Aufwand: A =?<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 189 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 190 / 235<br />

Geometrie<br />

Polygon<br />

Einfacher geschlossener Pfad – Ablauf<br />

Geometrie<br />

Polygon<br />

Einfacher geschlossener Pfad – Winkel<br />

M<br />

4<br />

J<br />

α i = atan2(∆y, ∆x)<br />

C<br />

I<br />

H<br />

N<br />

E<br />

B<br />

K<br />

A<br />

F<br />

G<br />

3<br />

L<br />

2<br />

D<br />

1<br />

0<br />

double a(point p1, point p2)<br />

{<br />

/* use if math is fast */<br />

int dx, dy;<br />

dx = p2.x - p1.x;<br />

dy = p2.y - p1.y;<br />

return atan2(dy, dx);<br />

/* radians */<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 191 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 192 / 235


Enthaltensein in Polygon<br />

Geometrie<br />

Polygon<br />

Geometrie<br />

Polygon<br />

Enthaltensein in Polygon – Umlauf<br />

◮ Polygon P i , i = 1 . . . n<br />

◮ Punkt A in Polygon?<br />

◮ Testlinie von außen bis A<br />

◮ Anzahl Schnitte ⇒ innen/außen?<br />

A<br />

A<br />

1. Testlinie −∞ → A<br />

2. laufe um Polygon<br />

3. ignoriere P i auf Testlinie<br />

4. zähle Schnitte m<br />

5. m ungerade ⇒ A innen<br />

P1<br />

Pn<br />

P2<br />

P3<br />

P4<br />

A<br />

A<br />

A<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 193 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 194 / 235<br />

Geometrie<br />

Polygon<br />

Geometrie<br />

Polygon<br />

Enthaltensein in Polygon – Implementation<br />

Enthaltensein in Polygon (einfach, konvex)<br />

int inside(point A, point p[], int N)<br />

{<br />

int i, j = 0, cnt = 0; /* j: last point not on test line*/<br />

line lt, lp; /* lt: test line, lp: intersection line */<br />

p[0] = p[N]; p[N + 1] = p[1]; /* close polygon */<br />

lt.p1 = lt.p2 = A;<br />

lt.p1.x = -INT_MAX; /* test line starts far away */<br />

for ( i = 1; i


Geometrie<br />

Polygon<br />

Geometrie<br />

Polygon<br />

Konvexe Hülle<br />

Konvexe Hülle – Einwickeln<br />

1. Punkte P i , i = 1 . . . n<br />

2. (außenliegender) Ankerpunkt A<br />

3. A P i : Winkel α i<br />

4. α min : Linie<br />

A = O(n 2 )<br />

I<br />

H<br />

J<br />

K<br />

L<br />

O<br />

G<br />

F<br />

M<br />

N<br />

E<br />

C<br />

A<br />

D<br />

B<br />

I<br />

H<br />

J<br />

K<br />

L<br />

O<br />

G<br />

F<br />

M<br />

N<br />

E<br />

C<br />

A<br />

D<br />

B<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 197 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 198 / 235<br />

Geometrie<br />

Polygon<br />

Konvexe Hülle – Einwickeln: Implementation<br />

int wrap(struct point p[], int N)<br />

{<br />

int i = 1, min, M; double th, th0, al; point t;<br />

for (min = 0; i < N; i++)<br />

if (p[i].y < p[min].y) min = i;<br />

p[N] = p[min]; th = 0.0;<br />

for (M = 0; M < N; M++) {<br />

swap(p[M], p[min]); min = N; th0 = th; th = 360.0;<br />

for (i = M + 1; i


Geometrie<br />

Polygon<br />

Geometrie<br />

Polygon<br />

Konvexe Hülle – Graham(Ablauf)<br />

Konvexe Hülle – Graham: Implementation<br />

A<br />

E<br />

C<br />

D<br />

B<br />

int grahamscan(point p[], int N)<br />

{<br />

int i, min, M;<br />

point t;<br />

for (min = 1, i = 2; i


Geometrie<br />

Polygonfläche – Berechnung<br />

Polygon<br />

Geometrie<br />

Polygonfläche – Implementation<br />

Polygon<br />

∑n−1<br />

2A = 2 a i =<br />

i=0<br />

=<br />

=<br />

=<br />

=<br />

∑n−1<br />

x i y i+1 − x i+1 y i<br />

i=0<br />

n−1<br />

∑<br />

x i y i+1 −<br />

i=0<br />

n∑<br />

x i y i+1 −<br />

i=1<br />

n∑<br />

x i y i−1<br />

i=1<br />

n∑<br />

x i y i−1 , P n+1 = P 1<br />

i=1<br />

n∑<br />

x i y i+1 − x i y i−1<br />

i=1<br />

n∑<br />

x i (y i+1 − y i−1 )<br />

i=1<br />

double pgarea(point p[], int n)<br />

{<br />

double a; /* area */<br />

int i;<br />

}<br />

/* initialize area - avoid modulo operation */<br />

a = p[0].x * (p[1].y - p[n-1].y) +<br />

p[n-1].x * (p[0].y - p[n-2].y);<br />

for ( i = 1; i < n-1; i ++ ) {<br />

a += p[i].x * (p[i+1].y - p[i-1].y);<br />

}<br />

a = ( a < 0 ) ? (-a) : a; /* area positive */<br />

return(a/2);<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 205 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 206 / 235<br />

Geometrie<br />

Schnelles Zeichnen – Kreis<br />

Geometrie<br />

Schnelles Zeichnen – Kreis<br />

Kreis im Raster<br />

Kreis im Raster – Trigonometrie<br />

y<br />

45°<br />

ϕ<br />

r<br />

(x,y)<br />

x<br />

y = √ r 2 − x 2<br />

x = r cos ϕ<br />

y = r sin ϕ<br />

◮ Raster-Einheit: 1 Pixel<br />

◮ Symmetrie im Kreis<br />

void trigo(int r)<br />

{<br />

double pi4, phi, rad, x, y;<br />

int i, n;<br />

pi4 = atan(1.0); /* pi/4 */<br />

rad = (double) abs(r);<br />

n = rnd(rad * pi4); /* pixels */<br />

for ( i = 0; i < n; i ++ ) {<br />

phi = (pi4 * i) / n;<br />

x = rad * sin(phi);<br />

y = rad * cos(phi);<br />

plot(r, rnd(x), rnd(y));<br />

}<br />

}<br />

int rnd(double x) {<br />

/* round to */<br />

/* nearest int */<br />

int s = 1, r;<br />

if ( x < 0 ) {<br />

x = -x;<br />

s = -1;<br />

}<br />

r = (int) (x+0.5);<br />

return (s * r);<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 207 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 208 / 235


Geometrie<br />

Schnelles Zeichnen – Kreis<br />

Geometrie<br />

Schnelles Zeichnen – Kreis<br />

Kreis im Raster – Wurzel<br />

Kreis im Raster – Bresenham<br />

y<br />

void wurzel(int r)<br />

{<br />

double x, y, yh, r2;<br />

yh = abs(r) / sqrt(2.0);<br />

r2 = (double) (r * r);<br />

for ( y = 0.0; y 0 ⇒ y → y − 1<br />

Geometrie<br />

Schnelles Zeichnen – Kreis<br />

Kreis im Raster – Bresenham(Implementation)<br />

void bresenham(int r)<br />

{<br />

int x = 0, y, f = 0;<br />

y = abs(r); /* start at top */<br />

while (x < y) {<br />

plot(r, x, y); /* show pixel */<br />

++ x; /* next pixel right */<br />

if (f < 0) { /* edge inside circle? */<br />

f += 2*x - 1; /* yes, move right */<br />

} else {<br />

f += 2*(x - y); /* no */<br />

--y; /* move down */<br />

}<br />

}<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 211 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 212 / 235


Graphen<br />

Graphen<br />

Datenstrukturen<br />

Graphen<br />

Graphen – Datenstrukturen<br />

F<br />

M<br />

D<br />

E<br />

N<br />

1 2<br />

1<br />

2<br />

L<br />

O<br />

A<br />

G<br />

ungerichtet<br />

K<br />

J<br />

C<br />

B<br />

H<br />

I<br />

◮ (un-)gerichtet<br />

◮ (un-)gewichtet<br />

◮ licht/dicht<br />

◮ (a-)zyklisch<br />

◮ V Knoten<br />

◮ E Kanten<br />

◮ Pfad<br />

◮ Graph/Baum<br />

◮ Zusammenhang<br />

◮ Spannbaum<br />

Adjazenzmatrix<br />

ungerichtet<br />

A B C D E F G<br />

A 1 1 1 0 0 1 1<br />

B 1 1 0 0 0 0 0<br />

C 1 0 1 0 0 0 0<br />

D 0 0 0 1 1 1 0<br />

E 0 0 0 1 1 1 1<br />

F 1 0 0 1 1 1 0<br />

G 1 0 0 0 1 0 1<br />

gerichtet<br />

H I J K<br />

H 0 1 1 1<br />

I 0 0 0 0<br />

J 0 0 0 1<br />

K 0 0 0 0<br />

gewichtet<br />

L M N O<br />

L 1 1 0 2<br />

M 1 1 1 0<br />

N 0 1 1 2<br />

O 2 0 2 1<br />

gewichtet<br />

gerichtet<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 213 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 214 / 235<br />

Graphen<br />

Datenstrukturen<br />

Graphen<br />

Datenstrukturen<br />

Graphen – Datenstrukturen<br />

Adjazenzstruktur zu 1)<br />

Liste der Nachbarn<br />

#define Vmax 256<br />

struct nb {<br />

int c, w;<br />

struct nb *next;<br />

};<br />

typedef struct nb nb;<br />

nb *alist[Vmax];<br />

A<br />

B<br />

C<br />

F<br />

G<br />

B<br />

A<br />

C<br />

A<br />

D<br />

E<br />

F<br />

E<br />

D<br />

F<br />

G<br />

F<br />

A<br />

D<br />

E<br />

G<br />

A<br />

E<br />

Graphen – Visualisierung<br />

Beispiel zu 1) mit Graphviz (http://www.graphviz.org)<br />

digraph undir {<br />

fontname=Helvetica;<br />

label = "ungerichtet";<br />

splines = false;<br />

color = none;<br />

edge [arrowhead=none, fontname=Helvetica];<br />

node [shape=circle, width=0.3, fontname=Helvetica];<br />

A -> { B C G };<br />

A -> F [minlen=3];<br />

D -> { E F};<br />

E -> { F G};<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 215 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 216 / 235


Graphen<br />

Graphen – Traversierung/Suche<br />

Graphen – Suche<br />

Graphen<br />

Graphen – Tiefensuche(rekursiv)<br />

Graphen – Suche<br />

int id;<br />

void dfs()<br />

{<br />

node *v;<br />

id = 0;<br />

for (v = fstnode(); v != NULL; v = nxtnode(v)) {<br />

if ( unseen(v) ) {<br />

visit(v);<br />

}<br />

}<br />

}<br />

void visit(node *v)<br />

{<br />

edge *e;<br />

node *t;<br />

}<br />

mark(v, ++id);<br />

for (e = fstout(v); e != NULL; e = nxtout(e)) {<br />

t = e->head;<br />

if ( unseen(t) ) {<br />

visit(t);<br />

}<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 217 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 218 / 235<br />

Graphen Graphen – Suche<br />

Graphen – Verlauf Tiefensuche (rekursiv)<br />

l<br />

k<br />

q<br />

i<br />

r<br />

n<br />

t<br />

h<br />

j<br />

u<br />

s<br />

e<br />

g<br />

f<br />

v<br />

d<br />

w<br />

z<br />

a<br />

x<br />

b<br />

c<br />

y<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 219 / 235<br />

Graphen<br />

Graphen – Suche<br />

Graphen – Tiefen-/Breitensuche(iterativ)<br />

traverse()<br />

{<br />

node *v;<br />

for (v = fstnode(); v != NULL; v = nxtnode(v)) {<br />

if ( unseen(v) ) {<br />

visit(v);<br />

}<br />

}<br />

}<br />

int dfs()<br />

{<br />

stack_init();<br />

empty = stackempty;<br />

insert = push;<br />

extract = pop;<br />

traverse();<br />

}<br />

int bfs()<br />

{<br />

strcpy(method, "bfs");<br />

queue_init();<br />

empty = queueempty;<br />

insert = put;<br />

extract = get;<br />

traverse();<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 220 / 235


Graphen<br />

Graphen – Suche<br />

Graphen<br />

Graphen – Suche<br />

Graphen – Traversierung Tiefen-/Breitensuche<br />

void visit(node *v)<br />

{<br />

edge *e;<br />

node *t;<br />

id = 0;<br />

insert(v);<br />

while ( !empty() ) {<br />

v = extract();<br />

mark(v, ++id);<br />

for (e = fstout(v); e != NULL; e = nxtout(e)) {<br />

t = e->head;<br />

if ( unseen(t) ) {<br />

insert(t);<br />

mark(t, -1);<br />

}<br />

}<br />

}<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 221 / 235<br />

Graphen – Tiefensuche Verlauf (iterativ per Stack)<br />

l<br />

k<br />

q<br />

i<br />

r<br />

n<br />

t<br />

h<br />

j<br />

u<br />

s<br />

e<br />

g<br />

f<br />

v<br />

d<br />

w<br />

z<br />

a<br />

x<br />

b<br />

c<br />

y<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 222 / 235<br />

Graphen<br />

Graphen – Suche<br />

Graphen<br />

Graphen – Suche<br />

Graphen – Breitensuche Verlauf (per Queue)<br />

Graphen – Tiefen-/Breitensuche Vergleich<br />

k<br />

l<br />

h<br />

i<br />

j<br />

q<br />

r<br />

n<br />

t<br />

◮ Tiefensuche: Bestimmung der Pfadlängen<br />

◮ Breitensuche: Bestimmung kürzester Pfade<br />

e<br />

f<br />

g<br />

d<br />

s<br />

u<br />

v<br />

a<br />

b<br />

c<br />

z<br />

w<br />

x<br />

y<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 223 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 224 / 235


Graphen<br />

Graphen – Suche<br />

Graphen<br />

Graphen – Suche<br />

Graphentraversierung – Aufwand<br />

Graphen – Zusammenhang<br />

◮ Adjazenzmatrix: A = O(n 2 )<br />

◮ Adjazenzstruktur: A = O(n)<br />

int traverse()<br />

{<br />

node *v;<br />

int n = 0;<br />

for (v = fstnode(); v != NULL; v = nxtnode(v)) {<br />

if ( unseen(v) ) {<br />

visit(v);<br />

n ++;<br />

}<br />

}<br />

return n;<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 225 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 226 / 235<br />

Graphen<br />

Graphen – Suche<br />

Graphen<br />

Graphen – Suche<br />

Graphen – Zyklen<br />

Graphen – Topologisches Sortieren<br />

◮ zusammenhängender Graph<br />

◮ zyklenfrei: jeder Knoten ist Kantenende (Ausnahme: Wurzel)<br />

◮ V − E = 1 ⇒ zyklenfrei<br />

◮ V = E ⇒ ein Zyklus<br />

◮ E − V = n ⇒ n + 1 Zyklen<br />

◮ DAG (directed, acyclic<br />

graph)<br />

◮ Topologische Sortierung:<br />

A B F E D J K L M G C H I<br />

◮ Tiefensuche mit<br />

umgekehrter Richtung<br />

→ umgekehrte<br />

topologische Sortierung<br />

E<br />

D<br />

F<br />

A<br />

C<br />

B<br />

H<br />

G<br />

L<br />

J<br />

M<br />

K<br />

I<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 227 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 228 / 235


Graphen – Kürzeste Pfade<br />

Graphen Graphen – kürzeste Pfade<br />

◮ gegeben: Netz aus Knoten mit gewichteten Kanten<br />

◮ gesucht: die kürzesten Wege im Netz<br />

◮ Anwendung:<br />

◮ Transport<br />

◮ Netzwerktechnik (Routing: OSPF)<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 229 / 235<br />

Graphen<br />

Graphen – kürzeste Pfade<br />

1: procedure ShortestPath(Graph, start):<br />

2: for all v ∈ Graph do<br />

3: dist(v) ← ∞, pre(v) ← 0<br />

4: end for<br />

5: dist(start) ← 0, Q ← v ∈ Graph<br />

6: while |Q| > 0 do<br />

7: u ← v ∈ Q, dist(v) = min<br />

8: if dist(u) < ∞ then<br />

9: remove(u) from Q<br />

10: for all v ∈ Neighbour(u) do<br />

11: d ← dist(u) + dist(u, v)<br />

12: if d < dist(v) then<br />

13: dist(v) ← d, pre(v) ← u<br />

14: end if<br />

15: end for<br />

16: end if<br />

17: end while<br />

18: end procedure<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 230 / 235<br />

Graphen<br />

Graphen – kürzeste Pfade<br />

Graphen – Kürzeste Pfade/Prioritätssuche<br />

#define unseen -(INT_MAX - 1)<br />

int dist[Vmax], pre[Vmax], id = 0;<br />

listpfs()<br />

{<br />

int k;<br />

pqinitialize();<br />

for ( k = 0; k < N; k++ )<br />

dist[k] = -unseen;<br />

for ( k = 0; k < N; k++ )<br />

if ( dist[k] == -unseen )<br />

visit(idx[k]);<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 231 / 235<br />

Graphen<br />

Graphen – kürzeste Pfade<br />

Graphen – Kürzeste Pfade/Traversierung<br />

void visit(int k)<br />

{<br />

struct node *t; int prio;<br />

if (pqupdate(k, unseen) != 0) pre[k] = 0;<br />

while (!pqempty()) {<br />

id++; k = pqremove(); dist[k] = -dist[k];<br />

if (dist[k] == unseen) dist[k] = 0;<br />

for (t = alist[k]; t != t->next; t = t->next) {<br />

if (dist[t->c] < 0) {<br />

if (pqupdate(t->c, prio = dist[k]+t->w)) {<br />

dist[t->c] = -prio; pre[t->c] = k;<br />

}<br />

}<br />

}<br />

}<br />

}<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 232 / 235


Graphen<br />

Graphen – kürzeste Pfade<br />

Graphen – Kürzeste Pfade/Implementation<br />

Schwierige Probleme<br />

Weiterführende Themen<br />

Schwierige Probleme<br />

◮ Prioritätswarteschlange: Heap<br />

◮ A = O((E + V ) log V )<br />

◮ Analogie zu Tiefen-/Breitensuche<br />

◮<br />

Ähnliche Probleme: z.B. minimaler Spannbaum<br />

◮ Aufwand steigt stärker als polynomial<br />

◮ Beispiele:<br />

◮ Handelsreisendenproblem<br />

◮ Rucksackproblem<br />

◮ Aussagenlogik (Cook)<br />

◮ diophantische Gleichungen<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 233 / 235<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 234 / 235<br />

NP-Vollständigkeit<br />

Weiterführende Themen<br />

NP-Vollständigkeit<br />

◮ Klasseneinteilung Probleme:<br />

P: können mit deterministischen Automaten in<br />

polynomialer Zeit gelöst werden<br />

NP: können mit nondeterministischen Automaten in<br />

polynomialer Zeit gelöst werden<br />

NP-vollständig: eines lösbar ⇒ alle lösbar<br />

◮ Nondeterministischer Automat<br />

◮ Ungelöst: P = NP?<br />

◮ Approximation<br />

Prof. Dr.-Ing. <strong>Torsten</strong> <strong>Finke</strong> (FOM) Algorithmen 2013-12-01 235 / 235

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!