Technopedia Center
PMB University Brochure
Faculty of Engineering and Computer Science
S1 Informatics S1 Information Systems S1 Information Technology S1 Computer Engineering S1 Electrical Engineering S1 Civil Engineering

faculty of Economics and Business
S1 Management S1 Accountancy

Faculty of Letters and Educational Sciences
S1 English literature S1 English language education S1 Mathematics education S1 Sports Education
  • Registerasi
  • Brosur UTI
  • Kip Scholarship Information
  • Performance
  1. Weltenzyklopädie
  2. LCP-Array – Wikipedia
LCP-Array – Wikipedia 👆 Click Here!
aus Wikipedia, der freien Enzyklopädie

Das LCP-Array ist eine Datenstruktur aus der Informatik, welche meist in Kombination mit dem Suffixarray verwendet wird. Die Bezeichnung „LCP“ ist eine Abkürzung für „longest common prefix“ (dt. längstes gemeinsames Präfix). Das Array selbst enthält die Länge des längsten gemeinsamen Präfixes von je zwei lexikographisch aufeinanderfolgenden Suffixen.

Für das LCP-Array gibt es zahlreiche Anwendungen aus dem Bereich der Textsuche und -indizierung, wie beispielsweise die Konstruktion des Suffixbaums oder eine effiziente Suche aller Vorkommen eines Suchmusters in einem Text. Der benötigte Speicherplatz des LCP-Arrays ist linear im Vergleich zur Textgröße und es gibt Algorithmen, die das LCP-Array in linearer Zeit mit Hilfe des Suffixarrays konstruieren. Es wurde erstmals in einer Veröffentlichung von Manber und Myers (1993)[1] benutzt, in der es als Hgt-Array bezeichnet wurde.

Definition

[Bearbeiten | Quelltext bearbeiten]

Sei T = t 1 , t 2 , . . . , t n {\displaystyle T=t_{1},t_{2},...,t_{n}} {\displaystyle T=t_{1},t_{2},...,t_{n}} ein Text der Länge n {\displaystyle n} {\displaystyle n} und sei A {\displaystyle A} {\displaystyle A} das Suffixarray über dem Text T {\displaystyle T} {\displaystyle T}. Außerdem bezeichne T i {\displaystyle T^{i}} {\displaystyle T^{i}} das Suffix t i , t i + 1 , . . . , t n {\displaystyle t_{i},t_{i+1},...,t_{n}} {\displaystyle t_{i},t_{i+1},...,t_{n}} und l c p ( s , t ) {\displaystyle lcp(s,t)} {\displaystyle lcp(s,t)} die Länge des längsten gemeinsamen Präfixes der beiden Strings s {\displaystyle s} {\displaystyle s} und t {\displaystyle t} {\displaystyle t}.

Das LCP-Array H {\displaystyle H} {\displaystyle H} ist ein Array der Größe n {\displaystyle n} {\displaystyle n}, wobei die einzelnen Felder wie folgt definiert sind:

H [ i ] = { undefiniert , für  i = 1 l c p ( T A [ i − 1 ] , T A [ i ] ) , für  2 ≤ i ≤ n {\displaystyle H[i]={\begin{cases}{\text{undefiniert}},&{\text{für }}i=1\\lcp(T^{A[i-1]},T^{A[i]}),&{\text{für }}2\leq i\leq n\end{cases}}} {\displaystyle H[i]={\begin{cases}{\text{undefiniert}},&{\text{für }}i=1\\lcp(T^{A[i-1]},T^{A[i]}),&{\text{für }}2\leq i\leq n\end{cases}}}

Das Suffixarray A {\displaystyle A} {\displaystyle A} enthält eine lexikographische Sortierung aller Suffixe von T {\displaystyle T} {\displaystyle T}. Etwas informeller ausgedrückt bezieht sich ein Eintrag das LCP-Array immer auf zwei lexikographisch aufeinanderfolgende Suffixe von T {\displaystyle T} {\displaystyle T} und beschreibt die Länge des längsten gemeinsamen Präfixes der betrachteten Suffixe. Der Wert von H [ 1 ] {\displaystyle H[1]} {\displaystyle H[1]} ist undefiniert, weil T A [ 1 ] {\displaystyle T^{A[1]}} {\displaystyle T^{A[1]}} bereits das lexikographisch kleinste Suffix von T {\displaystyle T} {\displaystyle T} ist und keinen Vorgänger besitzt.

Beispiel

[Bearbeiten | Quelltext bearbeiten]

Betrachte den Text T = mississippi $ {\displaystyle T={\text{mississippi}}\$} {\displaystyle T={\text{mississippi}}\$}.

i 1 2 3 4 5 6 7 8 9 10 11 12
T[i] m i s s i s s i p p i $

Das Suffixarray von T {\displaystyle T} {\displaystyle T} repräsentiert die Sortierung der Suffixe des Textes, wobei im Array jeweils der Index des ersten Buchstabens des jeweiligen Suffixes gespeichert wird. Für den Text T {\displaystyle T} {\displaystyle T} sieht die Suffixsortierung wie folgt aus:

i 1 2 3 4 5 6 7 8 9 10 11 12
A[i] 12 11 8 5 2 1 10 9 7 4 6 3
1 $ i i i i m p p s s s s
2 $ p s s i i p i i s s
3 p s s s $ i p s i i
4 i i i s $ p s p s
5 $ p s i i i p s
6 p s s $ p i i
7 i i s p $ p
8 $ p i i p
9 p p $ i
10 i p $
11 $ i
12 $

Das LCP-Array H {\displaystyle H} {\displaystyle H} enthält die Länge des längsten gemeinsamen Präfixes zweier aufeinanderfolgender Suffixe. Es kann konstruiert werden, indem die Suffixe in der Suffixsortierung zeichenweise miteinander verglichen werden. Beispielsweise werden für die Berechnung des Wertes H [ 10 ] {\displaystyle H[10]} {\displaystyle H[10]} die bei A [ 10 ] {\displaystyle A[10]} {\displaystyle A[10]} und A [ 9 ] {\displaystyle A[9]} {\displaystyle A[9]} beginnenden Suffixe miteinander verglichen: Das längste gemeinsame Präfix von T A [ 10 ] = T 4 = sissippi $ {\displaystyle T^{A[10]}=T^{4}={\text{sissippi}}\$} {\displaystyle T^{A[10]}=T^{4}={\text{sissippi}}\$} und T A [ 9 ] = T 7 = sippi $ {\displaystyle T^{A[9]}=T^{7}={\text{sippi}}\$} {\displaystyle T^{A[9]}=T^{7}={\text{sippi}}\$} ist si {\displaystyle {\text{si}}} {\displaystyle {\text{si}}} und hat damit eine Länge von 2. Dementsprechend ist H [ 10 ] = 2 {\displaystyle H[10]=2} {\displaystyle H[10]=2}. Die restlichen Werte des LCP-Arrays können auf die gleiche Weise berechnet werden. Der Wert von H [ 1 ] {\displaystyle H[1]} {\displaystyle H[1]} bleibt dabei undefiniert, da es kein Suffix gibt, das lexikographisch vor T A [ 1 ] = T 12 = $ {\displaystyle T^{A[1]}=T^{12}=\$} {\displaystyle T^{A[1]}=T^{12}=\$} liegt. Das LCP-Array für den Text T {\displaystyle T} {\displaystyle T} sieht wie folgt aus:

i 1 2 3 4 5 6 7 8 9 10 11 12
H[i] ⊥ {\displaystyle \bot } {\displaystyle \bot } 0 1 1 4 0 0 1 0 2 1 3

Berechnung

[Bearbeiten | Quelltext bearbeiten]

Die einfachste Art, das LCP-Array zu berechnen, wäre (so wie im obigen Beispiel) mit Hilfe des Suffixarrays die lexikographisch aufeinanderfolgenden Suffixe zeichenweise zu vergleichen, um so die Länge des längsten gemeinsamen Präfixes zu berechnen. Allerdings ergibt sich mit diesem Verfahren im schlimmsten Fall eine Laufzeit von O ( n 2 ) {\displaystyle O(n^{2})} {\displaystyle O(n^{2})}. Enthält ein Text beispielsweise n {\displaystyle n} {\displaystyle n} gleiche Zeichen, so müssten insgesamt 1 + 2 + 3 + . . . + ( n − 1 ) = O ( n 2 ) {\displaystyle 1+2+3+...+(n-1)=O(n^{2})} {\displaystyle 1+2+3+...+(n-1)=O(n^{2})} Vergleiche getätigt werden.

Ein effizienterer Ansatz basiert auf der Grundidee, die LCP-Einträge in Textreihenfolge zu berechnen. Angenommen i {\displaystyle i} {\displaystyle i} und j {\displaystyle j} {\displaystyle j} sind aufeinanderfolgende Werte im Suffixarray und T i {\displaystyle T^{i}} {\displaystyle T^{i}} und T j {\displaystyle T^{j}} {\displaystyle T^{j}} haben ein gemeinsames Präfix von h {\displaystyle h} {\displaystyle h} Zeichen. Die Suffixe T i + 1 {\displaystyle T^{i+1}} {\displaystyle T^{i+1}} und T j + 1 {\displaystyle T^{j+1}} {\displaystyle T^{j+1}} besitzen dann h − 1 {\displaystyle h-1} {\displaystyle h-1} gemeinsame Zeichen. Allerdings müssen i + 1 {\displaystyle i+1} {\displaystyle i+1} und j + 1 {\displaystyle j+1} {\displaystyle j+1} im Suffixarray nicht nebeneinander stehen; es kann durchaus Suffixe geben, die lexikographisch zwischen T i + 1 {\displaystyle T^{i+1}} {\displaystyle T^{i+1}} und T j + 1 {\displaystyle T^{j+1}} {\displaystyle T^{j+1}} liegen. Angenommen k {\displaystyle k} {\displaystyle k} sei der Wert, der vor dem Wert i + 1 {\displaystyle i+1} {\displaystyle i+1} im Suffixarray steht. Dann müssen T i + 1 {\displaystyle T^{i+1}} {\displaystyle T^{i+1}} und T k {\displaystyle T^{k}} {\displaystyle T^{k}} wegen der lexikographischen Sortierung der Suffixe mindestens h − 1 {\displaystyle h-1} {\displaystyle h-1} gemeinsame Zeichen haben (denn k {\displaystyle k} {\displaystyle k} liegt im Suffixarray zwischen i + 1 {\displaystyle i+1} {\displaystyle i+1} und j + 1 {\displaystyle j+1} {\displaystyle j+1}), das heißt, es würde reichen die beiden Suffixe ab dem h {\displaystyle h} {\displaystyle h}-ten Zeichen miteinander zu vergleichen.

Für diesen Ansatz wird das inverse Suffixarray A − 1 {\displaystyle A^{-1}} {\displaystyle A^{-1}} benötigt, um herauszufinden, an welcher Stelle ein bestimmter Wert in A {\displaystyle A} {\displaystyle A} vorkommt. Bei A − 1 {\displaystyle A^{-1}} {\displaystyle A^{-1}} handelt es sich um die inverse Permutation von A {\displaystyle A} {\displaystyle A}, das heißt A − 1 [ i ] {\displaystyle A^{-1}[i]} {\displaystyle A^{-1}[i]} gibt an, an welcher Stelle im Suffixarray A {\displaystyle A} {\displaystyle A} der Wert i {\displaystyle i} {\displaystyle i} steht.

Es ergibt sich folgender Algorithmus:

LCP-Array(T, A, n)
   for (i=1 to n)  {
      Ainv[A[i]] = i;
   }
   H[1] = 0;
   h = 0;
   for (i=1 to n) {
      if (Ainv[i] ≠ 1) {
         j = A[Ainv[i] - 1]
         while T[i+h] = T[j+h]
            h = h + 1
         H[Ainv[i]] = h
         h = max(0, h - 1)
      }
   }

Die Laufzeit ist linear, da h {\displaystyle h} {\displaystyle h} maximal den Wert n {\displaystyle n} {\displaystyle n} annehmen kann. Da h {\displaystyle h} {\displaystyle h} in jedem Schritt nur um 1 dekrementiert wird, wird die innere While-Schleife höchstens O ( n ) {\displaystyle O(n)} {\displaystyle O(n)} mal ausgeführt. Es ergibt sich somit eine Gesamtlaufzeit von O ( n ) {\displaystyle O(n)} {\displaystyle O(n)}.

Der oben vorgestellte Ansatz stammt von Kasai et al. (2001)[2] und ist der erste veröffentlichte Algorithmus, der das LCP-Array in linearer Zeit berechnet. Manzini (2004)[3] hat eine verbesserte Version entwickelt, die neben dem eigentlichen Text, dem Suffix-Array und dem LCP-Array keinen zusätzlichen Speicher benötigt. Eine weitere Verbesserung ist der φ-Algorithmus von Kärkkäinen, Manzini und Puglisi:[4] Während der ursprüngliche Algorithmus durch nicht sequentielle Zugriffe auf die Arrays für entsprechend lange Texte bis zu 4 n {\displaystyle 4n} {\displaystyle 4n} Cache-Misses verursacht (nämlich in den Zeilen 3, 9, 10 und 12), kommt der φ-Algorithmus mit nur 3 n {\displaystyle 3n} {\displaystyle 3n} Cache-Misses aus.

Die oben genannten Algorithmen benutzen für die Berechnung des LCP-Arrays ein bereits vorhandenes Suffixarray. Es gibt Algorithmen, die das LCP-Array gleichzeitig mit dem Suffix-Array berechnen. Der zur Zeit schnellste Linearzeit-Algorithmus stammt von Fischer (2011).[5]

Gog & Ohlebusch (2011)[6] haben zwei Algorithmen veröffentlicht, die im Worst-Case eine quadratische Laufzeit haben, aber in der Praxis schneller sind, als die oben erwähnten Linearzeit-Algorithmen.

Beschleunigung der Textsuche mit Hilfe des LCP-Arrays

[Bearbeiten | Quelltext bearbeiten]

Mit dem Suffixarray kann das Vorkommen eines Musters P {\displaystyle P} {\displaystyle P} der Länge m {\displaystyle m} {\displaystyle m} in einem Text T {\displaystyle T} {\displaystyle T} der Länge n {\displaystyle n} {\displaystyle n} mit Hilfe von binärer Suche bestimmt werden. Da die Suffixe im Suffixarray lexikographisch sortiert sind, genügen O ( log ⁡ n ) {\displaystyle O(\log {n})} {\displaystyle O(\log {n})} Vergleiche, um das lexikographisch kleinste (bzw. größte) Suffix zu finden, welches P {\displaystyle P} {\displaystyle P} enthält. Für jeden Vergleich müssen dabei bis zu m {\displaystyle m} {\displaystyle m} Zeichen verglichen werden, wodurch dieses Verfahren eine Laufzeit von O ( m log ⁡ n ) {\displaystyle O(m\log {n})} {\displaystyle O(m\log {n})} besitzt.

Mit Hilfe des LCP-Arrays lässt sich die Laufzeit auf O ( m + log ⁡ n ) {\displaystyle O(m+\log {n})} {\displaystyle O(m+\log {n})} verbessern, indem verhindert wird, dass bei jedem Schritt der binären Suche das Muster P {\displaystyle P} {\displaystyle P} erneut von Beginn an gelesen werden muss.

Bei jedem Schritt der binären Suche liegt eine linke Intervallgrenze l {\displaystyle l} {\displaystyle l}, eine rechte Intervallgrenze r {\displaystyle r} {\displaystyle r} und ein mittleres Element m {\displaystyle m} {\displaystyle m} vor. Dabei wird P {\displaystyle P} {\displaystyle P} mit dem lexikographisch A [ m ] {\displaystyle A[m]} {\displaystyle A[m]}-ten Suffix (also mit T A [ m ] {\displaystyle T^{A[m]}} {\displaystyle T^{A[m]}}) verglichen. Stimmen beide Strings überein, ist die binäre Suche fertig, ansonsten muss entweder in der linken oder rechten Intervallhälfte weitergesucht werden. Wir schauen uns den Fall an, dass P {\displaystyle P} {\displaystyle P} lexikographisch kleiner als T A [ m ] {\displaystyle T^{A[m]}} {\displaystyle T^{A[m]}} ist – der andere Fall ist analog. Sei k = l c p ( P , T A [ m ] ) {\displaystyle k=lcp(P,T^{A[m]})} {\displaystyle k=lcp(P,T^{A[m]})} die Länge des längsten gemeinsamen Präfixes der beiden Strings. Das heißt, dass das k + 1 {\displaystyle k+1} {\displaystyle k+1}-te Zeichen von P {\displaystyle P} {\displaystyle P} lexikographisch kleiner als das von T A [ m ] {\displaystyle T^{A[m]}} {\displaystyle T^{A[m]}} ist.

Das neue Intervall besitzt die Grenzen l {\displaystyle l} {\displaystyle l} und m {\displaystyle m} {\displaystyle m} und das mittlere Element m ′ {\displaystyle m'} {\displaystyle m'}. Sei k ′ = l c p ( T A [ m ] , T A [ m ′ ] ) {\displaystyle k'=lcp(T^{A[m]},T^{A[m']})} {\displaystyle k'=lcp(T^{A[m]},T^{A[m']})} die Länge des längsten gemeinsamen Präfixes zwischen dem alten und dem neuen mittleren Element. Es folgt eine Fallunterscheidung:

  • k < k ′ {\displaystyle k<k'} {\displaystyle k<k'}: Das k + 1 {\displaystyle k+1} {\displaystyle k+1}-te Zeichen der Suffixe T A [ m ] {\displaystyle T^{A[m]}} {\displaystyle T^{A[m]}} und T A [ m ′ ] {\displaystyle T^{A[m']}} {\displaystyle T^{A[m']}} ist gleich. Daher muss P {\displaystyle P} {\displaystyle P} auch lexikographisch kleiner als T A [ m ′ ] {\displaystyle T^{A[m']}} {\displaystyle T^{A[m']}} sein und die binäre Suche kann ohne weitere Vergleiche in der linken Intervallhälfte fortgesetzt werden.
  • k > k ′ {\displaystyle k>k'} {\displaystyle k>k'}: Wegen m ′ < m {\displaystyle m'<m} {\displaystyle m'<m} ist das Suffix T A [ m ′ ] {\displaystyle T^{A[m']}} {\displaystyle T^{A[m']}} lexikographisch kleiner als das Suffix T A [ m ] {\displaystyle T^{A[m]}} {\displaystyle T^{A[m]}}. Das bedeutet, dass das k ′ + 1 {\displaystyle k'+1} {\displaystyle k'+1}-te Zeichen von Suffix T A [ m ′ ] {\displaystyle T^{A[m']}} {\displaystyle T^{A[m']}} kleiner als das k ′ + 1 {\displaystyle k'+1} {\displaystyle k'+1}-te Zeichen von Suffix T A [ m ] {\displaystyle T^{A[m]}} {\displaystyle T^{A[m]}} sein muss. Da T A [ m ] {\displaystyle T^{A[m]}} {\displaystyle T^{A[m]}} und P {\displaystyle P} {\displaystyle P} ein gemeinsames Präfix von mindestens k ′ + 1 {\displaystyle k'+1} {\displaystyle k'+1} Zeichen haben, folgt hier, dass T A [ m ′ ] {\displaystyle T^{A[m']}} {\displaystyle T^{A[m']}} lexikographisch kleiner ist als P und die binäre Suche wird in der rechten Hälfte fortgesetzt.
  • k = k ′ {\displaystyle k=k'} {\displaystyle k=k'}: P {\displaystyle P} {\displaystyle P} und T A [ m ′ ] {\displaystyle T^{A[m']}} {\displaystyle T^{A[m']}} haben ein gemeinsames Präfix von mindestens k {\displaystyle k} {\displaystyle k} Zeichen. Hier müssen beide Strings verglichen werden, wobei der Vergleich erst beim k + 1 {\displaystyle k+1} {\displaystyle k+1}-ten Zeichen beginnen muss.

Durch das beschriebene Verfahren ist es bei der binären Suche niemals notwendig bereits gelesene Zeichen von P {\displaystyle P} {\displaystyle P} nochmals zu lesen. Das Verfahren stammt von Manber und Myers[1]. Da sich im LCP-Array nur die l c p {\displaystyle lcp} {\displaystyle lcp}-Werte für lexikographisch aufeinanderfolgende Suffixe befinden, wird im Folgenden noch gezeigt, wie sich beliebige l c p {\displaystyle lcp} {\displaystyle lcp}-Werte effizient berechnen lassen.

Im Allgemeinen lässt sich das längste gemeinsame Präfix von zwei Suffixen mit Hilfe einer Range Minimum Query über dem LCP-Array finden[7]. Für zwei Suffixe T A [ i ] , T A [ j ] {\displaystyle T^{A[i]},T^{A[j]}} {\displaystyle T^{A[i]},T^{A[j]}}, betrachtet man alle Suffixe, die lexikographisch dazwischen liegen: Falls zwei aufeinanderfolgende Suffixe ein längstes gemeinsames Präfix der Länge k {\displaystyle k} {\displaystyle k} besitzen, so können T A [ i ] {\displaystyle T^{A[i]}} {\displaystyle T^{A[i]}} und T A [ j ] {\displaystyle T^{A[j]}} {\displaystyle T^{A[j]}} wegen der lexikographischen Sortierung kein längeres gemeinsames Präfix haben. Der Wert l c p ( T A [ i ] , T A [ j ] ) {\displaystyle lcp(T^{A[i]},T^{A[j]})} {\displaystyle lcp(T^{A[i]},T^{A[j]})} entspricht daher genau dem Minimum über den LCP-Einträgen H [ i + 1 ] , . . . , H [ j ] {\displaystyle H[i+1],...,H[j]} {\displaystyle H[i+1],...,H[j]}. Dieses Minimum lässt sich mit geeigneten Verfahren für Range Minimum Queries in konstanter Zeit finden.[8]

Literatur

[Bearbeiten | Quelltext bearbeiten]
  • Enno Ohlebusch Bioinformatics Algorithms: Sequence Analysis, Genome Rearrangements, and Phylogenetic Reconstruction. Oldenbusch Verlag, 2013, Kapitel 4.

Einzelnachweise

[Bearbeiten | Quelltext bearbeiten]
  1. ↑ a b Udi Manber, Gene Myers: Suffix Arrays: A New Method for On-Line String Searches. In: SIAM Journal on Computing. 22. Jahrgang, Nr. 5, 1993, S. 935, doi:10.1137/0222058. 
  2. ↑ Kasai, T. et al.: Linear-Time Longest-Common-Prefix Computation in Suffix. In: Proceedings of the 12th Annual Symposium on Combinatorial Pattern Matching, 2001.
  3. ↑ Manzini, Giovanni: Two Space Saving Tricks for Linear Time LCP Array Computation. In: Lecture Notes in Computer Science, Volume 3111, Seite 372, 2004.
  4. ↑ Kärkkäinen, Juha; Manzini, Giovanni; Puglisi, Simon J.: Permuted Longest-Common-Prefix Array. In: Lecture Notes in Computer Science, Volume 5577, Seite 181, 2009.
  5. ↑ Fischer, Johannes: Inducing the LCP-Array. In: Lecture Notes in Computer Science, Volume 6844, Seite 374–385, 2011.
  6. ↑ Gog, Simon; Ohlebusch, Enno: Fast and Lightweight LCP-Array Construction Algorithms. In: Proceedings of the Workshop on Algorithm Engineering and Experiments, ALENEX, Seite 25–34, 2011.
  7. ↑ Fischer, J. and V. Heun: Theoretical and practical improvements on the RMQ-problem, with applications to LCA and LCE. In: Combinatorial Pattern Matching. 2006, S. 36–48, doi:10.1007/11780441_5. 
  8. ↑ Fischer, J. and V. Heun: Space-Efficient Preprocessing Schemes for Range Minimum Queries on Static Arrays. In: SIAM J. Comput. 40 (apr). 2011, S. 465–492, doi:10.1137/090779759. 
Abgerufen von „https://de.teknopedia.teknokrat.ac.id/w/index.php?title=LCP-Array&oldid=261116903“
Kategorie:
  • Datenstruktur
Versteckte Kategorie:
  • Wikipedia:Vorlagenfehler/Vorlage:Cite journal/temporär

  • indonesia
  • Polski
  • العربية
  • Deutsch
  • English
  • Español
  • Français
  • Italiano
  • مصرى
  • Nederlands
  • 日本語
  • Português
  • Sinugboanong Binisaya
  • Svenska
  • Українська
  • Tiếng Việt
  • Winaray
  • 中文
  • Русский
Sunting pranala
Pusat Layanan

UNIVERSITAS TEKNOKRAT INDONESIA | ASEAN's Best Private University
Jl. ZA. Pagar Alam No.9 -11, Labuhan Ratu, Kec. Kedaton, Kota Bandar Lampung, Lampung 35132
Phone: (0721) 702022
Email: pmb@teknokrat.ac.id