• Keine Ergebnisse gefunden

Auswahl eines geeigneten Algorithmus in der Praxis

Im Dokument Algorithmen auf Sequenzen (Seite 48-53)

10 w i n d o w += m - j +2

3.10 Auswahl eines geeigneten Algorithmus in der Praxis

Einen ¨Uberblick, wann in Abh¨angigkeit von Alphabetgr¨oße und Patternl¨ange welcher Algo-rithmus in der Praxis vorteilhaft ist, findet sich bei?, Figure 2.22.

Zusammenfassend l¨asst sich Folgendes sagen: Ab einer hinreichend großen Alphabetgr¨oße ist immer der Horspool-Algorithmus der schnellste. Bei sehr kleinen Alphabeten und kurzen Patterns ist Shift-Or gut (ein optimierter Shift-And). BNDM ist gut, solange der Automat bitparallel in einem Register verarbeitet werden kann. F¨ur lange Muster bei einem kleinen Alphabet hat sich BOM als am effizientesten erwiesen.

Gute Algorithmen werden bei zunehmender Patternl¨ange nicht langsamer (O(mn) ist naiv!), sondern schneller (O(n/m) ist anzustreben!).

KAPITEL 4

Volltext-Indizes

Wenn wir in einem feststehenden Text (der L¨angen) oft nach verschiedenen Mustern (der L¨ange m) suchen wollen, dann kann es sinnvoll sein, den Text vorzuverarbeiten und eine Index-Datenstruktur aufzubauen. Das kann einen Vorteil in der Gesamtlaufzeit bringen:

Online Index-basierte Mustersuche Mustersuche

O(m) O(n) Vorverarbeitung

O(n) O(m) Suche (ein Muster)

O k(m+n)

O(n+km) insgesamt (kMuster)

Um nat¨urlichsprachliche Texte zu indizieren (z.B. f¨ur Suchmaschinen), bieten sich Wort-basierte Verfahren an. Beim Indizieren von biologischen Texten ohne Wortstruktur, beispiels-weise DNA, ben¨otigen wir hingegen Index-Datenstrukturen, die die Suche nach beliebigen Teilstrings (ohne R¨ucksicht auf Wortgrenzen) erlauben. Diese werden Volltext-Indizes ge-nannt. In diesem Kapitel geht es um Datenstrukturen, die dies erm¨oglichen. Hierzu gibt es zwei popul¨are Indexstrukturen, n¨amlich denSuffixbaum und dasSuffixarray. Zudem gibt es den q-gram-Index, den wir aber aus Zeitgr¨unden nicht diskutieren. Achtung: Nicht jede der genannten Datenstrukturen erreicht die oben genannten Laufzeiten.

4.1 Suffixb¨ aume

Der Grundgedanke hinter Suffixb¨aumen ist, dass man einem beliebigen Muster p schnell ansehen kann, ob es in einem zuvor indizierten Texttvorkommt. Dazu wird zuteine Baum-struktur so aufgebaut, dass jedes Suffix von t einem Pfad von der Wurzel zu einem Blatt

entspricht. Da jeder Teilstring von t ein Pr¨afix eines Suffixes von t ist, muss man zur Teil-stringsuche nur den richtigen Pfad von der Wurzel des Baums verfolgen; dies sollte sich in O(|t|) Zeit machen lassen. Ein Problem dabei k¨onnte aber der Platzbedarf des Baumes wer-den: Erzeugen wir aus allen Suffixen einen Trie (so dass wir im Prinzip den Aho-Corasick-Algorithmus anwenden k¨onnen), ben¨otigen wir zu viel Platz, denn die Gesamtl¨ange aller Suffixe istn+ (n−1) + (n−2) +· · ·+ 1 = Θ(n2), wobei |t|=n.

Es w¨are sch¨on, wenn jedes Blatt des (zu definierenden) Suffixbaums genau einem Suffix vont entsprechen w¨urde. Da es aber m¨oglich ist, dass gewisse Suffixe noch an anderer Stelle als Teilstrings (also als Pr¨afix eines anderen Suffix) vorkommen, ist dieser Wunsch nicht notwen-digerweise erf¨ullbar. Dies kann nur garantiert werden, wenn das letzte Zeichen des Strings eindeutig ist, also sonst nicht vorkommt. Es hat sich daher etabliert, einenW¨achter (sentinel) an den zu indizierenden String anzuh¨angen; dieser wird gew¨ohnlich mit $ bezeichnet.

Wir listen nun einige w¨unschenswerte Eigenschaften des Suffixbaums zu t$ auf:

• Es gibt eine Bijektion zwischen den Bl¨attern des Suffixbaums und den Suffixen vont$.

• Die Kanten des Baums sind mit nicht-leeren Teilstrings vont$ annotiert.

• Ausgehende Kanten eines Knotens beginnen mit verschiedenen Buchstaben.

• Jeder innere Knoten hat ≥2 Kinder (es gibt also keine Knoten, wenn sich die Kante nicht verzweigt).

• Jeder Teilstring von t$ kann auf einem Pfad von der Wurzel ausgehend

”abgelesen“

werden.

Wir definieren nun einige hilfreiche Begriffe, um danach Suffixb¨aume formal zu definieren.

4.1 Definition. Ein gewurzelter Baum ist ein zusammenh¨angender azyklischer Graph mit einem speziellen Knotenr, derWurzel, so dass alle Kanten von der Wurzel weg weisen. Die Tiefe depth(v) eines Knotens v ist seine Distanz von der Wurzel; das ist die Anzahl der Kanten auf dem eindeutigen Pfad von der Wurzel zuv. Insbesondere istdepth(r) := 0.

Sei Σ ein Alphabet. Ein Σ-Baum oderTrie ist ein gewurzelter Baum, dessen Kanten jeweils mit einem einzelnen Buchstaben aus Σ annotiert sind, so dass kein Knoten zwei ausgehende Kanten mit dem gleichen Buchstaben hat. Ein Σ+-Baum ist ein gewurzelter Baum, dessen Kanten jeweils mit einem nichtleeren String ¨uber Σ annotiert sind, so dass kein Knoten zwei ausgehende Kanten hat, die mit dem gleichen Buchstaben beginnen.

Ein Σ+-Baum heißtkompakt, wenn kein Knoten (außer ggf. der Wurzel) genau ein Kind hat (d.h., wenn jeder innere Knoten mindestens zwei Kinder hat).

Sei v ein Knoten in einem Σ- oder Σ+-Baum. Dann sei string(v) die Konkatenation der Kantenbeschriftungen auf dem eindeutigen Pfad von der Wurzel zu v. Wir definieren die Stringtiefe eines Knoten v als stringdepth(v) := |string(v)|. Diese ist in einem Σ+-Baum normalerweise verschieden vondepth(v).

Seix∈Σ ein String. Existiert ein Knotenv mitstring(v) =x, dann schreiben wirnode(x) f¨urv. Ansonsten ist node(x) nicht definiert. Es ist node(ε) =r, die Wurzel.

Ein Σ- oder ein Σ+-BaumT buchstabiert x∈Σ, wennxentlang eines Pfades von der Wurzel abgelesen werden kann, d.h., wenn ein (m¨oglicherweise leerer) String y und ein Knoten v

4.1 Suffixb¨aume

Abbildung 4.1: Suffixb¨aume f¨ur die Strings cabca und cabca$. Der W¨achter sorgt daf¨ur, dass f¨ur jedes Suffix genau ein Blatt existiert. Die Zahlenfolge unter dem rechten Bild gibt die Positionen im Text an und entspricht dem Suffixarray, da in jedem Knoten die ausgehenden Kanten sortiert sind.

existieren mit string(v) = xy (dabei liegt v ggf.

”unterhalb“ von x). Es sei words(T) die Menge der Strings, dieT buchstabiert.

4.2 Definition (Suffixbaum). Der Suffixbaum von s∈Σ ist der kompakte Σ+-Baum mit words(T) ={s0 |s0 ist ein Teilstring von s}. Man beachte, dass wir im Normalfall zusden Suffixbaum von s$ betrachten, nicht den von s selbst, um eine Bijektion zwischen Suffixen und Bl¨attern herzustellen.

Wir wollen erreichen, dass der Speicherplatzbedarf f¨ur einen Suffixbaum nur linear in der Stringl¨ange ist. Die Kompaktheit des Σ+-Baums ist ein wichtiger Schritt, wie das folgende Lemma zeigt.

4.3 Lemma. Sei T der Suffixbaum zu s$ mit |s$| = n. Dann hat T genau n Bl¨atter, es existieren≤n−1 innere Knoten und ≤2(n−1) Kanten.

Beweis. Im Detail: ¨Ubung. Idee: Der Verzweigungsgrad ist ≥2 in jedem inneren Knoten.

Z¨ahle eingehende, ausgehende Kanten, innere Knoten und Bl¨atter.

An den Kanten des Suffixbaums zu s$ stehen Teilstrings von s$, deren Gesamtl¨ange noch quadratisch sein kann. Dies kann man verhindern, indem man die Teilstrings an den Kanten durch Indexpaare (i, j) repr¨asentiert: Das Paar (i, j) entspricht dem Label s[i . . . j] und ben¨otigt daher nur konstanten Platz. Insgesamt ben¨otigt ein Suffixbaum also (nur) O(n) Platz, obwohlO(n2) Teilstrings indiziert werden. Abbildung 4.1 illustriert einen Suffixbaum.

Man kann einen (einzigen) Suffixbaum zu mehreren verschiedenen Strings s1, . . . , sk erzeu-gen. Da man jedoch beim Aneinanderh¨angen Teilstrings erzeugen k¨onnte, die in keinem der Eingabestrings vorkommen, muss man dabei die Strings voneinander durch verschiedene Trennzeichen trennen.

4.4 Definition. Seien s1, . . . , skStrings ¨uber Σ. Seien $1 <$2 <· · ·<$k Zeichen, die nicht in Σ vorkommen und lexikographisch kleiner sind als jedes Zeichen in Σ. Der (verallgemei-nerte) Suffixbaum zus1, . . . , sk ist der Suffixbaum zus1$1s2$2. . . sk$k.

F¨ur die Konstruktion eines Suffixbaums gibt es mehrere M¨oglichkeiten (wobei wir bei den Laufzeiten voraussetzen, dass das Alphabet konstante Gr¨oße hat).

• O(n2) durch Einf¨ugen aller Suffixe in einen Trie (unter Ber¨ucksichtigung der genannten Tricks, um den Speicherplatzbedarf linear zu halten)

• Algorithmus von ?: O(n), online (String kann verl¨angert werden). Diesen Algorith-mus stellen wir in Abschnitt 4.3 vor. Es ist bemerkenswert (und wichtig), dass die Konstruktion eines Suffixbaums in Linearzeit m¨oglich ist.

Wir fassen die wichtigste Aussage in einem Satz zusammen.

4.5 Satz. Zu einem Stringskann der Suffixbaum vons$inO(n)Zeit konstruiert werden und ben¨otigt O(n) Platz. Es besteht eine Bijektion zwischen den echten Suffixen von s$ und den Bl¨attern des Suffixbaums; jedes Blatt ist mit der eindeutigen Startposition des entsprechenden Suffixes von sannotiert.

Im Dokument Algorithmen auf Sequenzen (Seite 48-53)