Notizen
Algorithmen und Datenstrukturen (f¨ur ET/IT) Sommersemester 2016 Dr. Tobias Lasser Computer Aided Medical Procedures Technische Universit¨ at M¨ unchen
Programm heute
Notizen
7 Fortgeschrittene Datenstrukturen
8 Such-Algorithmen
Lineare Suche Bin¨are Suche Bin¨are Suchb¨aume Balancierte Suchb¨aume Suchen mit Hashtabellen Suchen in Zeichenketten
2
W¨orterb¨ucher
Notizen
W¨orterbuch Ein W¨ orterbuch (auch genannt Dictionary oder Assoziatives Array) speichert eine Menge von Elementen M. Jedes Element e ∈ M wird durch einen Schl¨ ussel key (e) eindeutig identifiziert. Unterst¨ utzte Operationen sind: • search(key k): finde e ∈ M mit key (e) = k • insert(Element e): erweitere M um e • erase(key k): entferne e aus M, wobei key (e) = k
Beispiele: • Telefonbuch • Element: Name, Adresse und Telefonnummer • Schl¨ ussel: Name
• Compiler-Symboltabelle • Element: Bezeichner und Typ-/Speicher-Informationen • Schl¨ ussel: Bezeichner 3
Such-Algorithmen f¨ur W¨orterb¨ucher
Notizen
Sei M W¨ orterbuch mit |M| = n. • M als verkettete Liste mit linearer Suche • search O(n), insert O(1), erase O(n) • M als sortierte verkettete Liste mit bin¨ arer Suche • search O(log n), insert O(n), erase O(log n) • M als AVL-Suchbaum • search O(log n), insert O(log n), erase O(log n) • M als Hashtabelle • search O(1), insert O(1), erase O(1)
im Mittel!
• Worst case: search O(n), insert O(1), erase O(n)
4
Adresstabellen
Notizen
Sei M W¨ orterbuch. • Setze U := key (e) : e ∈ M die Menge aller Schl¨ ussel • Annahme: key (e1 ) 6= key (e2 ) f¨ ur alle e1 6= e2 , e1 , e2 ∈ M
W¨orterbuch mit Adresstabelle: • sequentielle Liste T der L¨ ange |U| Schlüsselmenge U
4 1
6 3 2
Adresstabelle T
2
8 7 5
3
5
7
5
Operationen auf Adresstabellen
Notizen
Adresstabelle T mit L¨ange |U|. • Input: Tabelle T , Schl¨ ussel k
Output: Element mit Schl¨ ussel k search(T , k): return T [k]; • Input: Tabelle T , Element e
insert(T , e): T [key (e)] = e; • Input: Tabelle T , Schl¨ ussel k
erase(T , k): T [k] = null; Alle Operationen: Laufzeit O(1) Speicherkomplexit¨at: O(|U|) →
Problem falls U groß! 6
Reduktion von Adresstabellen mittels Hashfunktion
Notizen
• Beobachtung: Menge K der tats¨ achlich benutzten Schl¨ ussel
aus U oft klein Schlüsselmenge U
4 1
6 3
Menge K der tatsächlich benutzten Schlüssel
8
2
Adresstabelle T
7 5
2
3
5
7
• Idee: wende Hashfunktion h auf key (e) an, um Adresstabelle
auf |K | Elemente zu reduzieren
→
Hashtabelle 7
Hashtabellen
Notizen
W¨orterbuch mit Hashtabelle: • sequentielle Liste T mit L¨ ange m := |K | • Hashfunktion h : U → {0, . . . , m − 1} Schlüsselmenge U
4 1
6 3
Menge K der tatsächlich benutzten Schlüssel
2
h Hashtabelle T
2
5
h 3
8 7
h
h 5
7
8
Operationen auf Hashtabellen
Notizen
Hashtabelle T mit L¨ange m und Hashfunktion h. • Input: Tabelle T , Schl¨ ussel k
Output: Element mit Schl¨ ussel k search(T , k): return T [h(k)]; • Input: Tabelle T , Element e
insert(T , e): T [h(key (e))] = e; • Input: Tabelle T , Schl¨ ussel k
erase(T , k): T [h(k)] = null; Alle Operationen: Laufzeit O(1) Speicherkomplexit¨at: O(m)
(sofern h auch O(1)) 9
Kollisionen bei Hashtabellen
Notizen
• Problem: falls h nicht injektiv → Kollision! • h ist nie injektiv da |K | < |U| Schlüsselmenge U
4 1
6 3
8 9
2
h
7 5
h
h
h
h Kollision!
Hashtabelle T
2
3
5
7
• Offene Fragen: • Strategie zur Kollisionsaufl¨ osung • Wahl von h 10
Verkettung zur Kollisionsaufl¨osung
Notizen
Schlüsselmenge U
4 1
• jeder Slot in T enth¨ alt
6 3
statt Element Referenz auf verkettete Liste
-1
-2
2
9 5
8 7
• bei Kollision: f¨ uge
Element am Anfang der Liste ein → O(1)
h
h
h
h
h
Hashtabelle T
• search und erase m¨ ussen
nun die Liste durchlaufen → O(1) gef¨ahrdet!
-1
3
5
2
9 7
-2
11
Analyse von Hashing mit Verkettung
Notizen
Sei T Hashtabelle mit m Slots und n gespeicherten Elementen. • Belegungsfaktor α = n/m • mittlere Anzahl von Elementen in verketteten Listen • es kann gezeigt werden:
Anzahl der Listendurchl¨aufe ist O(1+α) • Annahme: es ist n = cm mit c Konstante, dann
α = n/m = O(m)/m = O(1) • Komplexit¨ at von search und erase: • im Mittel: O(1) • worst case: O(n)
12
Hashfunktionen
Notizen
Sei U Menge aller Schl¨ ussel, T Hashtabelle mit m Eintr¨agen. h : U → {0, . . . , m − 1}
• Anforderungen an Hashfunktion: • einfache Auswertung O(1) • m¨ oglichst wenige Kollisionen • viele Ans¨ atze, zum Beispiel: • Divisionsmethode • Multiplikationsmethode • universelles Hashing • Vereinbarung: U = N0 zur Vereinfachung • Strings z.B. via ASCII Code auf Zahlen abbilden
13
Divisionsmethode
Notizen
Divisionsmethode Sei U = N0 die Schl¨ usselmenge, sei T Hashtabelle mit m Eintr¨agen. Die Divisionsmethode w¨ahlt die Hashfunktion folgendermaßen: h : U → {0, . . . , m − 1},
h(k) = k mod m.
• Beispiel: m = 12, k = 100, dann ist h(k) = 4. • Problem: geschickte Wahl von m • eher schlecht ist m = 2p (wertet nur die unteresten p Bits von k aus) • eher gut ist oft eine Primzahl, nicht nahe an Zweierpotenz • Beispiel: erwartete Anzahl von Eintr¨ agen in Hashtabelle: 2000, gew¨ unschter Belegungsfaktor 3 → m = 701 geeignete Primzahl 14
Multiplikationsmethode
Notizen
Multiplikationsmethode Sei U = N0 die Schl¨ usselmenge, sei T Hashtabelle mit m Eintr¨agen. Die Multiplikationsmethode w¨ahlt die Hashfunktion folgendermaßen: h : U → {0, . . . , m − 1},
h(k) = bm(kA mod 1)c,
wobei A ∈ (0, 1) Konstante. √
• Vorschlag von Knuth: A ≈ 21 ( 5 − 1) • typische Wahl: m = 2p • Beispiel: m = 214 = 16384, A = 2654435769/232 , und
k = 123456, dann ist h(k) = 67.
15
Universelles Hashing
Notizen
• Problem: f¨ ur jede feste Hashfunktion gibt es
Eingabesequenzen, die worst-case Laufzeit O(n) verursachen • L¨ osung:
Universelles Hashing Sei U = N0 die Schl¨ usselmenge, sei T Hashtabelle mit m Eintr¨agen. Sei H eine endliche Menge von Hashfunktionen: H = h : U → {0, . . . , m − 1} | h Hashfunktion . H heißt universell, falls f¨ ur jedes Schl¨ usselpaar k, l ∈ U, k 6= l, die Anzahl der Hashfunktionen h mit h(k) = h(l) durch |H|/m nach oben beschr¨ankt ist. • Idee: w¨ ahle zuf¨allig ein h ∈ H • Resultat: Hashing mit Verkettung liefert im Mittel O(1)
Laufzeit der W¨ orterbuch-Operationen 16
Kollisionsaufl¨osung mit offener Adressierung
Notizen
• Idee: statt Verkettung bei Kollision, suche systematisch
n¨achsten freien Platz in Hashtabelle → Sondieren Schlüsselmenge U
4 1
6 3
8
9 2
h Hashtabelle T
2
h 3
7
5
h 5
h
h Kollision! 7
9 Sondieren
• Probleme: • L¨ oschen von Elementen (erase) sehr problematisch • Falls Hashtabelle T voll, kein insert mehr m¨ oglich 17
Offene Adressierung
Notizen
Sei U Schl¨ usselmenge, T Hashtabelle mit m Eintr¨agen. • erweitere Hashfunktion zu
h : U × {0, . . . , m − 1} → {0, . . . , m − 1} • fordere, daß Sondierungssequenz
h(k, 0), h(k, 1), . . . , h(k, m − 1) eine Permutation von (0, . . . , m − 1) ist → jeder Slot in T ist m¨ ogliches Ziel f¨ ur Schl¨ ussel k • viele m¨ ogliche Sondierungssequenzen, zum Beispiel: • lineares Sondieren • quadratisches Sondieren • doppeltes Hashing 18
Hashing: Ausblick
Notizen
¨ • nachtr¨ agliche Anderung der Tabellengr¨oße aufwendig • erfordert neue Tabelle und neue Hashfunktion • u ¨bertragen aller Elemente (und Berechnung neuer Hashfunktion) n¨ otig • ist U statisch, so ist perfektes Hashing m¨ oglich • auch im worst-case sind alle Operationen O(1) • umgesetzt durch zwei Ebenen von universellem Hashing • Zeitgewinn erkauft durch zus¨ atzlichen Speicherbedarf von O(n)
19
Programm heute
Notizen
7 Fortgeschrittene Datenstrukturen
8 Such-Algorithmen
Lineare Suche Bin¨are Suche Bin¨are Suchb¨aume Balancierte Suchb¨aume Suchen mit Hashtabellen Suchen in Zeichenketten
20
Suchen in Zeichenketten
Notizen
• Problem: find Teilwort in (langem) anderen Wort • auch genannt: String-Matching • Beispiele: • Suche Text in Textverarbeitung / Web-Browser • Suche Text in Dateien auf Festplatte (z.B. Spotlight, Windows Search) • Suche Text im Internet (z.B. Google) • Maß der Effizienz: Anzahl der Vergleiche zwischen Buchstaben
der Worte
21
Brute-Force Suche D A S 1 1 3
S
I
S T E
Notizen
I N S
I N N L O S E R T E X T
I N N S
I N N S
1 2 4 4
I N N S
I N N S
I N N
... S
I N N
16 Vergleiche
22
Notationen
Notizen
• Zu durchsuchender Text: • text[0..n − 1] • L¨ ange n • gesuchtes Muster = Pattern: • pat[0..m − 1] • L¨ ange m • Problem: finde Position i, so daß pat == text[i..i + m − 1]
23
Brute-Force Algorithmus
Notizen
Input: zu durchsuchender Text text L¨ange n, gesuchtes Muster pat L¨ange m Output: Index i von Match (oder -1 falls nicht gefunden) bruteForceSearch(text, pat): for i = 0 to n − m { j = 0; while ( (j < m) && (pat[j] == text[i + j]) ) j = j + 1; if (j ≥ m) return i; // f¨ undig geworden } return -1; // nichts gefunden
• Komplexit¨ at: O((n − m)m) = O(nm)
24
Knuth-Morris-Pratt Algorithmus
Notizen
Knuth-Morris-Pratt Algorithmus (kurz: KMP) • Idee: verbessere Brute-Force Algorithmus durch Ausnutzung
der bereits gelesenen Information bei einem Mismatch • Mismatch an Stelle j von pat impliziert
pat[0..j − 1] == text[i..i + j − 1]
text: D A S
I
pat:
I N N
S
S T E
I N S
I N N L O S E R T E X T
• Vorverarbeitungsschritt: analysiere vor Suche das Muster pat,
¨ speichere m¨ ogliche Uberspringungen in Feld shift
25
Alphabet und W¨orter
Notizen
W¨orter Ein Alphabet Σ ist eine endliche Menge von Symbolen. Ein Wort w der L¨ange n u ¨ber Σ ist eine endliche Folge von Symbolen w = w1 · · · wn ,
wi ∈ Σ, i = 1, . . . , n.
Beispiel: • Alphabet Σ = { a,...,z, A,...,Z } • W¨ orter: Daten, Algorithmen, aabb • keine W¨ orter: ¨ uber, t35t
• Alphabet Σ = { 0,...,9,A,B,C,D,E,F } • W¨ orter: 09FF, ABC, A3E • keine W¨ orter: 1f, 1gH
Das leere Wort wird mit ε bezeichnet. 26
Pr¨afix und Suffix von einem Wort
Notizen
Pr¨afix, Suffix Sei w = w1 · · · wn Wort der L¨ange n u ¨ber einem Alphabet Σ. 0 • Das Wort w heißt Pr¨ afix von w , falls w 0 = w1 · · · wl f¨ ur 0 ≤ l ≤ n. • Das Wort w 0 heißt Suffix von w , falls w 0 = wl · · · wn f¨ ur
1 ≤ l ≤ n + 1. Beispiele f¨ ur Wort w = Algorithmen: • Pr¨ afixe von w sind: A, Alg, Algorit, Algorithmen • Suffixe von w sind: n, men, gorithmen, Algorithmen
27
Rand von einem Wort
Notizen
Rand Sei w Wort u ¨ber einem Alphabet Σ. Ein Wort r heißt Rand von w , falls r sowohl Pr¨afix als auch Suffix von w ist. Ein Rand r von w heißt eigentlicher Rand, wenn r 6= w und wenn es außer w selbst keinen l¨angeren Rand gibt. Der eigentliche Rand von w wird mit ∂(w ) bezeichnet. Beispiel: Wort w = aabaabaa hat folgende R¨ander: • ε • a • aa • aabaa
← eigentlicher Rand
• aabaabaa = w 28
¨ Uberspringen beim Suchen
Notizen
text: pat: shift
• Idee: verschiebe Pattern so, daß im bereits gepr¨ uften Bereich
¨ wieder Ubereinstimmung herrscht
• dazu m¨ ussen Pr¨afix und Suffix dieses Bereichs u ¨bereinstimmen
→ eigentlicher Rand
29
Shift-Tabelle
Notizen
Shift-Tabelle Sei pat = s0 · · · sm−1 Wort der L¨ange m. Die Shift-Tabelle von pat gibt die L¨ange des eigentlichen Randes des Pr¨afixes der L¨ange j von pat an. Sie hat folgende Gestalt: ( −1 f¨ ur j = 0 shift[j] = ∂(s0 · · · sj−1 ) f¨ ur j ≥ 1 wobei j = 0, . . . , m − 1. • Ist das Pr¨ afix der L¨ange j gematcht, und an Stelle j ein
Mismatch, so ist der Shift j − shift[j] > 0 korrekt
30
KMP Algorithmus: Beispiel I
Notizen
text:
A B C A B A B A B C A A B A B
pat:
A B C A A B A B C A A B A B C A A B A B C A A B
j
0
1
2
3
4
5
shift[j]
-1
0
0
0
1
1
31
KMP Algorithmus
Notizen
Input: zu durchsuchender Text text L¨ange n, gesuchtes Muster pat L¨ange m Output: Index i von Match (oder -1 falls nicht gefunden) KMPSearch(text, pat): initShift(pat); // Initialisierung shift Tabelle, siehe sp¨ater i = 0; j = 0; while (i ≤ n − m) { while (text[i + j] == pat[j]) { j = j + 1; if (j == m) return i; // f¨ undig geworden } i = i + (j − shift[j]); // j − shift[j] ist immer > 0 j = max(0, shift[j]); } return -1; // war wohl nix 32
KMP Algorithmus: Beispiel II i=
0
3
5
Notizen
7
text:
A B C A B A B A B C A A B A B
pat:
A B C A A B
j=
0 1 2 3 4 A B C A A B j=
0 1 2 A B C A A B j=
0 1 2 A B C A A B j=
0 1 2 3 4 5
j
0
1
2
3
4
5
shift[j]
-1
0
0
0
1
1 33
Shift Tabelle Beispiel I
Notizen
j 1
shift[j] A B C A A B
0
A B C A A B 2
A B C A A B
0
A B C A A B 3
A B C A A B
0
A B C A A B 4
A B C A A B
1
A B C A A B 5
A B C A A B
1
A B C A A B
34
KMP Algorithmus: Shift Tabelle
Notizen
Input: Muster pat der L¨ange m initShift(pat): shift[0] = −1; shift[1] = 0; i = 0; for j = 2 to m { // hier ist: i == shift[j − 1] while (i ≥ 0 && pat[i] 6= pat[j − 1]) i = shift[i]; i = i + 1; shift[j] = i; }
35
KMP Algorithmus: Komplexit¨at
Notizen
Komplexit¨at von KMP Algorithmus: • KMPSearch: • erfolglose Vergleiche (¨ außere while-Schleife): maximal
n − m + 1 Vergleiche • erfolgreiche Vergleiche (innere while-Schleife): ingesamt
maximal n Vergleiche • insgesamt: maximal 2n − m + 1 Vergleiche
• initShift: • erfolgreiche Vergleiche (for-Schleife): maximal m − 1 Vergleiche • erfolglose Vergleiche (while-Schleife): maximal m Vergleiche • insgesamt: maximal 2m − 1 Vergleiche • insgesamt: maximal 2n + m Vergleiche, also O(n + m) • Platzbedarf: O(m)
36
Ausblick: Suchen in Zeichenketten
Notizen
• Brute-Force Algorithmus • Komplexit¨ at: O(mn) • Knuth-Morris-Pratt Algorithmus • Komplexit¨ at: O(m + n) • Rabin-Karp Algorithmus: Suchen mit Hash-Funktion • Komplexit¨ at im Mittel: O(m + n) • Komplexit¨ at worst-case: O(mn) • Boyer-Moore Algorithmus: Suchen r¨ uckw¨arts • Komplexit¨ at: O(n) • Komplexit¨ at best-case: O(n/m) • Regul¨ are Ausdr¨ ucke mit endlichen Automaten • Suche nach ¨ ahnlichen Zeichenketten
37
Zusammenfassung
Notizen
7 Fortgeschrittene Datenstrukturen
8 Such-Algorithmen
Lineare Suche Bin¨are Suche Bin¨are Suchb¨aume Balancierte Suchb¨aume Suchen mit Hashtabellen Suchen in Zeichenketten
38