Algorithmen und Datenstrukturen II: Suchen in Texten Prof. Dr. Oliver Braun Letzte Änderung: 29.06.2017 13:51 Algorithmen und Datenstrukturen II: Suchen in Texten 1/40 Ein Text ▶ Texte spielen in vielen Anwendungen eine zentrale Rolle ▶ z.B. in Texteditoren, Literaturdatenbanken, Systemen zur Symbolmanipulation ▶ Texte sind nicht weiter strukturierte Folgen beliebiger Länge über einem endlichen Alphabet ▶ das Alphabet kann Buchstaben, Ziffern und zahlreiche Sonderzeichen enthalten ▶ der zugrundeliegende Datentyp kann auf verschiedene Arten realisiert sein ▶ z.B. Array-of-Characters, verkettete Liste von Zeichen ▶ Zeichenkette soll nicht-negative, ganzzahlige Länge zugeordnet sein ▶ Zugriff auf das i. Zeichen für jedes i ≥ 1 soll möglich sein Algorithmen und Datenstrukturen II: Suchen in Texten 2/40 Das Suchproblem Gegeben sind eine Zeichenkette (Text) a1 ...aN von Zeichen aus einem endlichen Alphabet Σ und eine Zeichenkette, das Muster (Pattern), b1 ...bM , mit bi ∈ Σ, 1 ≤ i ≤ M Gesucht sind ein oder alle Vorkommen von b1 ...bM und a1 ...aN , d.h. Indizes i mit 1 ≤ i ≤ (N − M + 1) und ai = b1 , ai+1 = b2 , ..., ai+M−1 = bM ▶ in der Regel ist N sehr viel größer als M ▶ wir unterscheiden Suche in ▶ ▶ statischen Texten und in dynamischen Texten Algorithmen und Datenstrukturen II: Suchen in Texten 3/40 Suche in dynamischen Texten Algorithmen und Datenstrukturen II: Suchen in Texten 4/40 Das naive Verfahren zur Textsuche ▶ Idee: Muster wird, beginnend beim ersten Zeichen des Textes, der Reihe nach an jeden Teilstring des Textes angelegt ▶ wird zeichenweise verglichen ▶ bei einem Mismatch wird vom nächsten Zeichen an weiter probiert ▶ das Muster B muss im worst-case (N − M + 1)-mal an den Text A angelegt werden und dann jeweils ganz durchlaufen werden ▶ das bedeutet es müssen (N − M + 1) · M Vergleiche ausgeführt werden ▶ Laufzeit also von der Größenordnung Θ(N · M) Algorithmen und Datenstrukturen II: Suchen in Texten 5/40 Naheliegende Verbesserung des naiven Verfahrens ▶ Muster wird nur bis zum ersten Mismatch durchlaufen und nicht (trotzdem) komplett ▶ Wahrscheinlichkeit ist am höchsten, dass das Muster an der ersten Stelle nicht passt ▶ in der Praxis reichen dann oft nur noch O(M + N) Vergleiche ▶ im worst case schlägt es immer erst beim letzten Zeichen fehl: Ω(N · M) ▶ naives Verfahren ist gedächtnislos Algorithmen und Datenstrukturen II: Suchen in Texten 6/40 Beispiel er sprach abrakadabra, es bewegte sich aber nichts a a a ... ab ... abe a ... a aber Algorithmen und Datenstrukturen II: Suchen in Texten 7/40 Das Verfahren von Knuth-Morris-Pratt ▶ Idee: Tritt an der j-ten Stelle ein Mismatch auf, haben die vorangegangenen j − 1 Stellen übereingestimmt ▶ mit dieser Information soll das Muster soweit wie möglich nach rechts verschoben werden ▶ Beispiel i Text: ... 010110101 Muster: 010101 ▶ ▶ wird das Muster um nur eine Stelle verschoben, tritt sofort wieder ein Mismatch auf offensichtlich kann es gleich um zwei Stellen verschoben werden Algorithmen und Datenstrukturen II: Suchen in Texten 8/40 Allgemeine Situation beim Mismatch 1. Die letzten j − 1 gelesenen Zeichen im Text stimmen mit den ersten j − 1 Zeichen im Muster überein. 2. Das gerade gelesene i-te Zeichen im Text ist verschieden vom j-ten Zeichen im Muster. Frage Mit welchem Zeichen im Muster kann man das i-te Textzeichen als nächstes vergleichen, so dass man kein Vorkommen im Text übersieht? Algorithmen und Datenstrukturen II: Suchen in Texten 9/40 Das Verfahren von Knuth-Morris-Pratt … ▶ vom Anfangsstück des Musters mit der Länge j − 1 ein längstes Endstück suchen, das ebenfalls Anfangsstück des Musters ist ▶ hat Endstück die Länge l, dann nennen wir die Position l + 1 next[j] ▶ next[j] muss als nächstes mit Position i verglichen werden ▶ Beispiel: ▶ ▶ ▶ ▶ Text abababb, Muster ababb Mismatch beim 5. Zeichen, also Anfangsstück des Musters ist abab Endstück ab ist zugleich Anfangsstück d.h. Muster kann sofort zwei Stellen weiter verschoben werden Algorithmen und Datenstrukturen II: Suchen in Texten 10/40 Das Verfahren von Boyer-Moore ▶ Zeichen im Muster werden nicht von links nach rechts, sondern von rechts nach links mit den Zeichen im Text verglichen ▶ das Muster wird zwar trotzdem der Reihe nach von links nach rechts an wachsende Textpositionen angelegt, aber der Vergleich beginnt immer mit dem letzten Zeichen des Textes ▶ tritt bis zum Vergleich des ersten Zeichens im Muster kein Mismatch auf, ist ein Vorkommen gefunden ▶ tritt ein Mismatch auf, wird eine (möglichst große) Verschiebung des Musters berechnet Algorithmen und Datenstrukturen II: Suchen in Texten 11/40 Minimale Verschiebung des Textzeigers ▶ seien ▶ ▶ ▶ ▶ ▶ ▶ i der aktuelle Wert des Textzeigers j der aktuelle Wert des Musterzeigers M die Länge des Musters erfolgt ein Mismatch bei i und j kann das Muster um eine Position nach rechts geschoben werden damit der Textzeiger auf das Zeichen zeigt das nach der Verschiebung mit dem letzten Zeichen des verglichen wird, muss er um M − j + 1 Stellen nach rechts verschoben werden, also i = i + M − j + 1 Beispiel: i ... Wettervorhersage ... Alter j neuer Wert von i muss auf das v zeigen Algorithmen und Datenstrukturen II: Suchen in Texten 12/40 Beispiele Boyer-Moore ▶ Beispiel 1: er sprach... aber ▶ ▶ ▶ als erstes wird s mit r verglichen ⇒ Mismatch da s im gesamten Muster nicht vorkommt, kann das Muster gleich um die Musterlänge verschoben werden Beispiel 2: abrakadabra... aber ▶ ▶ Vergleich a mit r � Mismatch da a im Muster vorkommt, kann man es nur so weit verschieben, bis erstmals das Text- und das Musterzeichen untereinander stehen Algorithmen und Datenstrukturen II: Suchen in Texten 13/40 Berechnung der Verschiebung bei einem Bad-Character ▶ für die Weite der Sprünge wird, nur abhängig vom Muster und vom Alphabet, aber nicht vom Text, eine delta-1-Tabelle erstellt ▶ delta − 1-Funktion berechnet für jedes c ∈ Σ die Entfernung c vom letzten Zeichen { delta−1(c) = ▶ M, M-j, falls c in b1 ...bM nicht vorkommt falls c = bj und c ̸= bk mit j < k ≤ M das Vorgehen heisst auch Vorkommens-Heuristik bzw. Bad-Character-Shift Algorithmen und Datenstrukturen II: Suchen in Texten 14/40 Verschiebung des Textzeigers ▶ eigentlich wollen wir nicht das Muster verschieben, sondern den Textzeiger möglichst weit nach rechts ▶ Textzeiger soll mindestens über die Position hinaus geschoben werden auf die er gerade zeigt ▶ kann aus delta − 1-Wert berechnet werden ▶ sei im Folgenden ▶ ▶ c das den Mismatch verursachende Zeichen und i und j die aktuellen Positionen im Text bzw. im Muster ▶ bei einem Mismatch an Position j kann der Textzeiger mindestens so verschoben werden, dass ▶ 2 Fälle beim Mismatch ▶ ▶ c kommt rechts vom Mismatch im Muster bereits vor c kommt nicht rechts vom Mismatch vor Algorithmen und Datenstrukturen II: Suchen in Texten 15/40 Fall 1: M − j + 1 > delta − 1(c) ▶ ▶ ▶ ▶ c kommt rechts vom Mismatch im Muster bereits vor wir wissen außerdem, dass die Zeichen im Muster rechts von c ungleich c sind also können wir den Textzeiger um den Abstand von c vom letzten Zeichen weiter verschieben d.h. i = i + M − j + delta − 1(c) und j = M Quelle: Ottmann & Widmayer, Algorithmen und Datenstrukturen Algorithmen und Datenstrukturen II: Suchen in Texten 16/40 Beispiel für Fall 1 TODO: Beispiel passt nicht!! i ... Datenstrukturen ... Tinktur j j' ▶ ▶ ▶ M−j+1=7−3+1=5 delta − 1(u) = M − j′ = 7 − 6 = 1 also i = i + 7 − 3 + 1 = i + 5 und j = M i ... Datenstrukturen ... Tinktur j Algorithmen und Datenstrukturen II: Suchen in Texten 17/40 Fall 2: M − j + 1 ≤ delta − 1(c) ▶ ▶ c kommt nicht rechts vom Mismatch vor (vielleicht sogar nicht im Muster) setze i = i + delta − 1(c) und j = M Quelle: Ottmann & Widmayer, Algorithmen und Datenstrukturen Algorithmen und Datenstrukturen II: Suchen in Texten 18/40 Beispiel für Fall 2 i ... Wasserstelle ... Tankstelle j ▶ ▶ ▶ M − j + 1 = 10 − 4 + 1 = 7 delta − 1(r) = M = 10 also i = i + 10 und j = M i ... Wasserstelle ... Tankstelle j Algorithmen und Datenstrukturen II: Suchen in Texten 19/40 Im schlimmsten Fall naiv ▶ im schlechtesten Fall nicht besser als das naive Verfahren ▶ Beispiel: Text besteht nur aus Nullen, Muster 10...0 i ...0000000000000000000000000000000... 1000000000 j ▶ M − j + 1 = 10 − 1 + 1, delta − 1(0) = M − M = 0 ⇒ i = i + 10 i ...0000000000000000000000000000000... 1000000000 j ▶ Verbesserung durch zweite Heuristik: Match-Heuristik Algorithmen und Datenstrukturen II: Suchen in Texten 20/40 Berechnung der Verschiebung bei einem Good-Suffix ▶ ▶ ähnlich Knuth-Morris-Pratt Beispiel: orange ananas banana banana ▶ ▶ ▶ ▶ Annahme: die letzten m Zeichen stimmen überein und an Position j von rechts ist erster Mismatch nennen wir die letzten m Zeichen das Submuster dann suchen wir von rechts her nach einem weiteren Vorkommen des Submusters im Muster haben wir so ein Vorkommen gefunden, können wir das Muster so weit nach rechts verschieben, dass das weitere Vorkommen dem entsprechenden Text gegenüber steht ▶ im Beispiel können wir um 2 Positionen nach rechts schieben orange ananas banana banana Algorithmen und Datenstrukturen II: Suchen in Texten 21/40 Formalisierung ▶ sei wrw(j) die Position an der das von rechts her nächste Vorkommen des Submusters beginnt ▶ ▶ ▶ ▶ j ist die Position des Mismatches das Submuster also bj+1 ...bM Annahme: das dem weiteren Vorkommen vorangehende Zeichen ist verschieden von dem das am Mismatch beteiligt war die Funktion delta − 2 gibt an um welche Distanz der Zeiger i im Text bewegt werden kann: delta − 2(j) = M + 1 − wrw(j) Algorithmen und Datenstrukturen II: Suchen in Texten 22/40 Beispiel i orange ananas banana banana j ▶ j = 3, wrw(3) = 2 und delta − 2(3) = 6 + 1 − 2 = 5 i orange ananas banana banana j Algorithmen und Datenstrukturen II: Suchen in Texten 23/40 Berechnung der delta − 2-Tabelle für banana j Suffix vorangehend 5 4 3 2 1 a na ana nana anana n a n a b ▶ weiteres Vorkommen banana **banana banana ****banana *****banana wrw(j) 2 -1 2 -3 -4 delta − 2(j) 5 8 5 10 11 Anfügen von don’t care-Symbolen rechts, wenn kein Vorkommen im Muster Position j: -4 -3 -2 -1 Muster: ... * * * * Submuster: n a n Algorithmen und Datenstrukturen II: Suchen in Texten 0 1 2 3 4 5 6 * b a n a n a a 24/40 Das Verfahren von Boyer-Moore ▶ Verknüpfung der beiden Heuristiken ▶ i wird um max{delta − 1(ai ) + 1, delta − 2(j)} verschoben ▶ j wird M gesetzt ▶ Hoorspool hat gezeigt, dass die delta − 2-Tabelle in der Praxis kaum zur Schnelligkeit beiträgt ▶ in der Praxis kommen oft kurze Muster vor, bei denen gar keine mehrfach auftretenden Submuster enthalten sind ▶ man kann erwarten, dass das Verfahren für genügend kurze Muster und hinreichend große Alphabete etwas O(N/M) Schritte ausführt und fast immer um die gesamte Musterlänge nach rechts verschoben werden kann Algorithmen und Datenstrukturen II: Suchen in Texten 25/40 Signaturen ▶ weiteres Verfahren zur Mustersuche in einem Text ▶ Muster der Länge M, Text der Länge N ▶ von dem Muster wird ein Hashwert berechnet ▶ von allen Teilstrings des Textes der Länge N wird auch der Hashwert berechnet ▶ nur wenn der Hashwert gleich ist, kann ein Vorkommen gefunden worden sein Algorithmen und Datenstrukturen II: Suchen in Texten 26/40 Beispiel für Signaturen: Verfahren von Karp und Rabin ▶ Muster über einem Alphabet der Größe d wird als d-adische Zahl interpretiert ▶ als Hashfunktion dient dann h(k) = k mod p für eine geeignet gewählte, große Primzahl ▶ man kann zeigen, dass das Verfahren mit hoher Wahrscheinlichkeit nur O(M + N) Schritte benötigt Algorithmen und Datenstrukturen II: Suchen in Texten 27/40 Suchen in statischen Texten Algorithmen und Datenstrukturen II: Suchen in Texten 28/40 Aufbereitung von Texten — Suffix-Bäume ▶ ▶ wenn häufig der selbe Text σ nach vielen verschiedenen Mustern durchsucht wird, kann es sich lohnen für σ einen Suchindex aufzubauen ein Suffix-Baum ist ein in linearer Zeit konstruierbare Baum, der linearen Platz benötigt und folgendes effizient ausführt: ▶ ▶ ▶ ▶ Teilwortsuche in Zeit O(|α|) mit Teilword α, d.h. unabhängig von der Textlänge! Präfixsuche: findet alle Stellen in σ an denen Worte mit dem Präfix α vorkommen Bereichs-Suche: findet alle Stellen in σ, die Worte enthalten, die lexikographisch zwischen zwei Grenzen fallen Beispiel: der Bereich [abc, acc] enthält abrakadarba, acacia, aber nicht abacus ein Suffix-Baum unterstützt auch Anfragen an σ selbst, z.B. Was ist das längste wiederholt auftretende Teilwort von σ, das an mindestens 2 Stellen auftritt? Algorithmen und Datenstrukturen II: Suchen in Texten 29/40 Einschub: Tries ▶ ▶ ▶ ▶ ▶ ▶ ▶ ▶ Tries (gesprochen wie das englische Wort try) sind Suchbäume und repräsentieren eine Menge M von Schlüsseln Schlüssel sind Zeichenketten über einem endlichen Alphabet Σ jede Kante eines Tries T ist mit einem Zeichen aus Σ beschriftet benachbarte Kanten müssen mit verschiedenen Zeichen beschriftet sein maximaler Grad eines Knoten ist damit |Σ| einem einfachen Weg von der Wurzel zu einem Knoten v wird eine Zeichenkette als Konkatenation der Beschriftungen zugeordnet damit repräsentiert jeder Knoten eine eindeutige Zeichenkette um zu testen, ob ein Wort α = a1 a2 ...an in M enthalten ist, stellt man fest, ob es einen Weg von der Wurzel zu einem Blatt gibt, dessen Beschriftung gleich α ist Algorithmen und Datenstrukturen II: Suchen in Texten 30/40 Suffix-Tries ▶ ▶ Suffix-Tries (auch Position-Trees) sind Tries die alle Suffixe einer Zeichenkette σ repräsentieren Beispiel für σ = ababc Algorithmen und Datenstrukturen II: Suchen in Texten 31/40 Suffix-Bäume ▶ Wege die nur aus unären Knoten bestehen, werden zu einer Kante zusammengezogen, Beispiel: Suffix-Trie zu σ = ababc ▶ damit erhält man einen Suffix-Baum (=kontrahierter Suffix-Trie) ▶ Beispiel für σ = ababc Quelle: Ottmann & Widmayer, Algorithmen und Datenstrukturen Algorithmen und Datenstrukturen II: Suchen in Texten 32/40 Konstruktion von Suffix-Bäumen ▶ zunächst naiver Algorithmus ▶ das Verfahren setzt voraus, dass kein Suffix Prafix eines anderen Suffix ist ▶ d.h. jedem Suffix entspricht eindeutig ein Blatt ▶ dies ist automatisch gewährleistet, wenn das letzte Zeichen von σ nirgends sonst in σ auftritt ▶ ggfs. wird ein neues Endezeichen $ ergänzt Algorithmen und Datenstrukturen II: Suchen in Texten 33/40 Naiver Algorithmus ▶ Voraussetzung: Das letzte Zeichen von σ tritt nirgends sonst in σ auf ▶ sei n = |σ| ▶ damit der zu σ konstruierende Suffix-Baum T eine lineare Größe in n hat, fordert man für T: ▶ ▶ ▶ ▶ jede Kante in T repräsentiert ein nicht-leeres Teilwort von σ die Teilworte, die benachbarten Kanten zugeordnet sind, beginnen mit verschiedenen Buchstaben jeder innere Knoten (außer der Wurzel) hat wenigstens zwei Nachfolger jedes Blatt repräsentiert ein nicht-leeres Suffix von σ ▶ damit Anzahl Blätter gleich n und Anzahl der inneren Knoten höchstens gleich n − 1 ▶ Speicherbedarf also O(n) Algorithmen und Datenstrukturen II: Suchen in Texten 34/40 Begriffe zur Beschreibung des naiven Verfahrens ▶ ▶ ▶ ▶ ▶ ▶ ▶ ▶ eine zusammenhängende Folge, bei der Wurzel beginnender Kanten, heisst partieller Weg endet ein partieller Weg bei einem Blatt, heisst er Weg der Knoten am Ende des mit α bezeichneten Weges heisst Ort einer Zeichenkette α (falls er existiert) jede Zeichenkette, die α als Präfix hat, heisst Erweiterung von α der Ort der kürzesten Zeichenkette, die α als Präfix hat und deren Ort definiert ist, heisst erweiterter Ort der Zeichenkette α der Ort des längsten Präfix von α, dessen Ort definiert ist, heisst kontrahierter Ort der Zeichenkette α mit sufi bezeichnen wir das an der Position i beginnende Suffix von σ, also suf1 = σ und sufn = $ mit headi bezeichnen wir das längste Präfix von sufi , das auch Präfix für ein sufj für ein j < i ist Algorithmen und Datenstrukturen II: Suchen in Texten 35/40 Naives Verfahren zur Konstruktion des Suffix-Baumes ▶ wir beginnen mit dem leeren Baum T0 ▶ Ti+1 entsteht aus Ti durch Einfügen des Suffixes sufi+1 ▶ in Ti haben alle Suffixe sufj , j < i bereits einen Ort ▶ headi ist das längste Präfix von sufi , dessen erweiterter Ort in Ti−1 existiert ▶ taili = sufi − headi , d.h. sufi = headi taili ▶ taili ̸= ϵ da letztes Zeichen nirgends sonst in σ auftreten darf Algorithmen und Datenstrukturen II: Suchen in Texten 36/40 Beispiel Quelle: Ottmann & Widmayer, Algorithmen und Datenstrukturen Algorithmen und Datenstrukturen II: Suchen in Texten 37/40 Naives Verfahren zur Konstruktion des Suffix-Baumes … ▶ Ti+1 kann aus Ti wie folgt konstruiert werden (headi+1 ̸= ϵ) ▶ ▶ ▶ bestimme den erweiterten Ort von headi+1 in Ti teile die letzte zu diesem Ort führende Kante in zwei neue auf (durch Einfügen eines neuen Knotens) schaffe ein neues Blatt als Ort für sufi+1 = headi+1 taili+1 Algorithmen und Datenstrukturen II: Suchen in Texten 38/40 Beispiel Quelle: Ottmann & Widmayer, Algorithmen und Datenstrukturen Algorithmen und Datenstrukturen II: Suchen in Texten 39/40 Effiziente Implementierung durch kompakte Repräsentation Quelle: Ottmann & Widmayer, Algorithmen und Datenstrukturen Algorithmen und Datenstrukturen II: Suchen in Texten 40/40