Zum Inhalt springen
L

Wikipedia · einfach zusammengefasst · Stand

LCP-Array

Das LCP-Array ist eine Datenstruktur aus der Informatik, welche meist in Kombination mit dem Suffixarray verwendet wird. Die Bezeichnung „LCP“ ist eine …

Inhalt4 Abschnitte
  1. 1. Grundidee und Definition
  2. 2. Beispiel mit „mississippi“
  3. 3. Berechnung in linearer Zeit
  4. 4. Beschleunigte Mustersuche

Grundidee und Definition

Das LCP-Array ist eine Datenstruktur der Informatik, die meist zusammen mit einem Suffixarray verwendet wird. „LCP“ steht für „longest common prefix“, also „längstes gemeinsames Präfix“. Ein Präfix ist ein zusammenhängender Anfang eines Strings. Das LCP-Array speichert für jeweils zwei lexikographisch aufeinanderfolgende Suffixe eines Textes die Länge ihres längsten gemeinsamen Präfixes.

Sei T = t₁, t₂, …, tₙ ein Text der Länge n und A das Suffixarray von T. Das Suffix Tⁱ ist definiert als tᵢ, tᵢ₊₁, …, tₙ. Mit lcp(s,t) wird die Länge des längsten gemeinsamen Präfixes zweier Strings s und t bezeichnet. Das LCP-Array H hat die Größe n und ist definiert durch:

H[i] = undefiniert für i = 1, H[i] = lcp(Tᴬ⁽ⁱ⁻¹⁾, Tᴬ⁽ⁱ⁾) für 2 ≤ i ≤ n.

Das Suffixarray A enthält alle Suffixe von T in lexikographischer Reihenfolge. Daher bezieht sich H[i] immer auf das Suffix an der Stelle A[i] und dessen Vorgänger an der Stelle A[i−1]. H[1] ist undefiniert, weil das lexikographisch kleinste Suffix keinen Vorgänger besitzt.

Das LCP-Array benötigt im Verhältnis zur Textgröße linearen Speicherplatz. Es wird unter anderem zur Konstruktion von Suffixbäumen und zur effizienten Suche aller Vorkommen eines Musters in einem Text eingesetzt.

Beispiel mit „mississippi“

Betrachtet wird der Text T = „mississippi“$. Das zusätzliche Zeichen $ markiert das Textende; der Text hat damit die Länge 12. Die Zeichen an den Positionen 1 bis 12 sind:

m, i, s, s, i, s, s, i, p, p, i, $.

Das Suffixarray speichert die Anfangspositionen der Suffixe in lexikographischer Reihenfolge. Für diesen Text lautet es:

A = (12, 11, 8, 5, 2, 1, 10, 9, 7, 4, 6, 3).

Das erste Suffix ist also T¹² = „$“, das zweite T¹¹ = „i$“, danach folgen unter anderem T⁸ = „ippi$“, T⁵ = „issippi$“ und T² = „ississippi$“.

Das LCP-Array vergleicht jeweils benachbarte Suffixe in dieser Sortierung. Für H[10] werden beispielsweise die Suffixe an den Positionen A[10] = 4 und A[9] = 7 verglichen: T⁴ = „sissippi$“ und T⁷ = „sippi$“. Ihr längstes gemeinsames Präfix ist „si“ und hat die Länge 2. Deshalb gilt H[10] = 2.

Das vollständige LCP-Array lautet:

H = (⊥, 0, 1, 1, 4, 0, 0, 1, 0, 2, 1, 3).

Der Wert ⊥ an der ersten Stelle steht für „undefiniert“. Die übrigen Werte geben jeweils die Länge des gemeinsamen Anfangs der beiden benachbarten Suffixe an.

Berechnung in linearer Zeit

Eine direkte Berechnung vergleicht jedes Paar lexikographisch aufeinanderfolgender Suffixe Zeichen für Zeichen. Im ungünstigsten Fall benötigt dieses Verfahren O(n²) Zeit. Enthält ein Text beispielsweise n gleiche Zeichen, entstehen insgesamt 1 + 2 + 3 + … + (n−1) = O(n²) Vergleiche.

Der effizientere Ansatz berechnet die LCP-Werte in Textreihenfolge. Haben die Suffixe Tⁱ und Tʲ ein gemeinsames Präfix der Länge h, dann haben Tⁱ⁺¹ und Tʲ⁺¹ mindestens h−1 gemeinsame Zeichen. Diese beiden verschobenen Suffixe müssen im Suffixarray nicht benachbart sein. Wegen der lexikographischen Ordnung gilt jedoch: Steht ein Suffix Tᵏ zwischen ihnen, besitzt Tⁱ⁺¹ mit Tᵏ ebenfalls mindestens h−1 gemeinsame Zeichen. Deshalb müssen beim nächsten Vergleich höchstens die Zeichen ab Position h neu geprüft werden.

Dafür wird das inverse Suffixarray A⁻¹ benötigt. Es ist die inverse Permutation von A; A⁻¹[i] gibt an, an welcher Stelle i im Suffixarray A steht. Der Algorithmus von Kasai et al. (2001) arbeitet im Wesentlichen so:

  • Zuerst wird für jede Position i der Rang A⁻¹[i] im Suffixarray bestimmt.
  • H[1] wird auf 0 gesetzt und eine Variable h mit 0 initialisiert.
  • Für jede Textposition i wird geprüft, ob das zugehörige Suffix im Suffixarray einen Vorgänger besitzt.
  • Der Vorgänger ist j = A[A⁻¹[i] − 1]. Die beiden Suffixe Tⁱ und Tʲ werden ab dem bereits bekannten gemeinsamen Präfix verglichen.
  • Solange T[i+h] = T[j+h] gilt, wird h um 1 erhöht. Danach wird H[A⁻¹[i]] = h gespeichert und h auf max(0, h−1) gesetzt.

Die Laufzeit ist O(n). Die Variable h kann insgesamt höchstens bis n anwachsen und wird zwischen zwei Schritten nur um 1 verringert; deshalb wird die innere While-Schleife insgesamt höchstens O(n)-mal ausgeführt.

Manzini (2004) entwickelte eine verbesserte Version, die neben Text, Suffixarray und LCP-Array keinen zusätzlichen Speicher benötigt. Der φ-Algorithmus von Kärkkäinen, Manzini und Puglisi reduziert die Zahl der Cache-Misses bei langen Texten von bis zu 4n auf 3n. Es gibt außerdem Verfahren, die LCP-Array und Suffixarray gleichzeitig berechnen; der zur Zeit der Darstellung schnellste Linearzeit-Algorithmus stammt von Fischer (2011). Die Algorithmen von Gog und Ohlebusch (2011) haben im Worst Case zwar quadratische Laufzeit, sind in der Praxis aber schneller als die genannten Linearzeit-Verfahren.

Beschleunigte Mustersuche

Mit einem Suffixarray kann ein Suchmuster P der Länge m in einem Text T der Länge n durch binäre Suche gefunden werden. Weil die Suffixe lexikographisch sortiert sind, reichen O(log n) Vergleiche, um das lexikographisch kleinste beziehungsweise größte Suffix zu bestimmen, das P enthält. Werden bei jedem Vergleich bis zu m Zeichen geprüft, beträgt die Laufzeit O(m log n).

Das LCP-Array verbessert diese Laufzeit auf O(m + log n). Bereits gelesene Zeichen des Musters P müssen bei der binären Suche nicht erneut vom Anfang an verglichen werden. Sei k = lcp(P, Tᴬ⁽ᵐ⁾) die Länge des gemeinsamen Präfixes von P und dem Suffix in der Mitte des aktuellen Intervalls. Ist P lexikographisch kleiner als dieses Suffix, wird im linken Teilintervall weitergesucht; der andere Fall ist analog.

Für das neue mittlere Element m′ sei k′ = lcp(Tᴬ⁽ᵐ⁾, Tᴬ⁽ᵐ′⁾). Dann gelten drei Fälle:

  • Ist k < k′, stimmen die Suffixe auch an der für P entscheidenden Stelle k+1 überein. P ist daher ebenfalls kleiner als das neue mittlere Suffix; die Suche kann ohne weitere Vergleiche in der linken Hälfte fortgesetzt werden.
  • Ist k > k′, ist das neue mittlere Suffix wegen m′ < m an der Stelle k′+1 kleiner als das bisherige mittlere Suffix. Da P mit dem bisherigen Suffix mindestens k′+1 Zeichen gemeinsam hat, ist das neue Suffix kleiner als P. Die Suche wird in der rechten Hälfte fortgesetzt.
  • Ist k = k′, müssen P und das neue mittlere Suffix verglichen werden. Der Vergleich beginnt erst beim Zeichen k+1.

Allgemeine LCP-Werte zweier Suffixe lassen sich durch eine Range Minimum Query über dem LCP-Array bestimmen. Für Tᴬ⁽ⁱ⁾ und Tᴬ⁽ʲ⁾ mit i < j betrachtet man die Einträge H[i+1], …, H[j]. Es gilt:

lcp(Tᴬ⁽ⁱ⁾, Tᴬ⁽ʲ⁾) = min(H[i+1], …, H[j]).

Der Grund ist, dass zwei Suffixe kein längeres gemeinsames Präfix besitzen können als ein Paar aufeinanderfolgender Suffixe zwischen ihnen. Mit geeigneten Verfahren für Range Minimum Queries kann dieses Minimum in konstanter Zeit berechnet werden.

Weiterlesen

Datenstruktur In der Informatik und Softwaretechnik ist eine Datenstruktur ein Objekt, welches zur Speicherung und Organisation von Daten dient. Es handelt sich um eine … Informatik Als einfache Rechengeräte leisteten Abakus und später der Rechenschieber unschätzbare Dienste. 1641 konstruierte Blaise Pascal eine mechanische … Suffixarray Ein Suffixarray ist in der Informatik ein Array, das die Suffixe einer Zeichenkette in lexikographischer Reihenfolge angibt. Präfix In der deutschen Morphologie finden sich Präfixe in der Wortbildung bei Verben, Substantiven und Adjektiven. Im Sprachvergleich findet man vielfältige weitere … Lexikographische Ordnung Die lexikographische Ordnung ist eine Methode, um aus einer linearen Ordnung für einfache Objekte, beispielsweise alphabetisch angeordnete Buchstaben, … Suffix In der Wortbildung des Deutschen spielen Suffixe die größte Rolle bei Nomina / Substantiven; hier gibt es zwar auch einige Präfixe, aber wesentlich mehr Suffixe … Algorithmus Algorithmen bestehen aus endlich vielen, wohldefinierten Einzelschritten. ... Damit können sie zur Ausführung in ein Computerprogramm implementiert, aber auch in … Laufzeit (Informatik) Der Begriff Laufzeit (englisch runtime) beschreibt in der Informatik einerseits die Zeitdauer, die ein Programm, ausgeführt durch einen Rechner, … Permutation Unter einer Permutation (von lateinisch permutare ‚vertauschen') versteht man in der Kombinatorik eine Anordnung von Objekten in einer bestimmten Reihenfolge. Cache Cache ([kæʃ], auch [ kaʃ]) bezeichnet in der Informationstechnik einen schnellen Pufferspeicher, der (wiederholte) Zugriffe auf vergleichsweise langsame … Binäre Suche Die binäre Suche ist ein Algorithmus, der in einem Array sehr effizient ein gesuchtes Element entweder findet oder dessen Vorhandensein zuverlässig … Range Minimum Query Range Minimum Queries (RMQs) adressieren innerhalb der Informatik das Problem, eine Anfrage nach dem kleinsten Element innerhalb eines spezifizierten …