Volltext-Indizes - Lehrstuhl 11 Algorithm Engineering

Werbung
Algorithmen auf Sequenzen
Volltext-Indizes
Dominik Kopczynski
Lehrstuhl für Algorithm Engineering (LS11)
Fakultät für Informatik
TU Dortmund
Überblick
Bei wiederholten Suchen auf (langen) Texten, ist es sinnvoll
den Text vorzuverarbeiten.
Durch Indizierung des Textes kann die Laufzeit so gesenkt
werden, dass sie nur noch von der Länge des Patterns
abhängt, also O(m).
Bei natürlichsprachlichen Texten können Wort-basierte Indizes
eingesetzt werden.
Indizes, die die Suche nach beliebigen Teilstrings (auch
wortübergreifend) erlauben, werden Volltext-Indizes genannt.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
2
Überblick
Bei wiederholten Suchen auf (langen) Texten, ist es sinnvoll
den Text vorzuverarbeiten.
Durch Indizierung des Textes kann die Laufzeit so gesenkt
werden, dass sie nur noch von der Länge des Patterns
abhängt, also O(m).
Bei natürlichsprachlichen Texten können Wort-basierte Indizes
eingesetzt werden.
Indizes, die die Suche nach beliebigen Teilstrings (auch
wortübergreifend) erlauben, werden Volltext-Indizes genannt.
Im Folgenden wird ein Alphabet konstanter Größe
angenommen, also O(1).
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
2
Überblick
n
$
$
5
$
4
s
$
0
1
6
$
0
ananas$
2
anas$
4
as$
1
nanas$
3
nas$
5
s$
3
s$
s
$
nas$
a
s$
a
nas$
s
s$
n
s$
6
s
na
$
a
na
a
s
a n
s
a
$
n
2
$ananas
ananas$
anas$an
as$anan
nanas$a
nas$ana
s$anana
$
Suffix-Trie
Suffix-Tree
Suffix-Array
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
FM-Index
3
Grundidee der Volltext-Indizes
Indizierung sämtlicher Suffixe eines Textes:
mississippi
ississippi
ssissippi
sissippi
issippi
ssippi
sippi
ippi
ppi
pi
i
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
4
Grundidee der Volltext-Indizes
Indizierung sämtlicher Suffixe eines Textes:
mississippi
ississippi
ssissippi
sissippi
issippi
ssippi
sippi
ippi
ppi
Quadratisch viele
pi
(n · (n + 1))/2 Zeichen,
i
wenn alle Suffixe betrachtet werden.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
4
Suffix-Trie
Alle Suffixe sollen in einen Trie hinzugefügt werden, ähnlich
wie beim Aho-Corasick.
Solch ein Trie sollte folgende Eigenschaften erfüllen: Es gibt
eine Bijektion zwischen den den Blättern des Baums und den
Suffixen des Textes.
Um diese Eigenschaft zu gewährleisten, wird im Folgenden ein
Wächter (Sentinel) $ am Ende des Textes eingeführt, für den
folgende Eigenschaften
gelten: Σ ∩ $ = ∅, für alle σ ∈ Σ : $ < σ.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
5
Suffix-Trie
Suffix-Trie für den Text T = aaa mit und ohne Sentinal:
a
$
a
$
a
a
$
a
a
$
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
6
Alphabet-Abhängigkeit
Ist die Alphabetgröße nicht konstant, hängt die Laufzeit von der
Datenstruktur ab, mit der Kinderknoten gesucht werden, sei
dabei cv ∈ O(|Σ|) die Anzahl der Kinder von Knoten v .
Datenstruktur
Verkettete Liste
Balancierter Baum
Array Größe |Σ|
Perfektes Hashing1
1
Laufzeit
O(cv )
O(log cv )
O(1)
O(1)
Platz pro Knoten
O(cv )
O(cv )
O(|Σ|)
O(cv )
Platz gesamt
O(n)
O(n)
O(n|Σ|)
O(n)
theoretisch möglich
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
7
Suffix-Trie
Mustersuche:
Jeder Teilstring des Textes T ist auch Präfix eines Suffixes
von T .
Die Mustersuche beginnt an der Wurzel.
Der Trie wird Zeichen für Zeichen des Patterns
durchtraversiert, bis entweder das komplette Pattern erkannt
wurde (match), oder von einem Knoten aus keine ausgehende
Kante P[j] vorhanden ist (mismatch).
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
8
Suffix-Trie
$
Beispiel-Trie
für den Text
T = ananas$:
n
a
n
a
s
s
a n
s
a
$
n
s
a
$
$
s
$
s
$
$
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
9
Implementierung
1
2
3
4
5
6
7
8
9
def build_trie(T):
root, n = dict(), len(T)
for t in [T[j:] for j in range(n)]:
node = root
for c in t:
if c not in node:
node[c] = dict()
node = node[c]
return root
10
11
12
13
14
15
def has_pattern(node, P):
for c in P:
if c not in node: return False
node = node[c]
return True
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
10
Zusammenfassung
Mit Hilfe des Suffix-Tries kann eine Patternsuche in O(m)
durchgeführt werden.
Sowohl die Laufzeit für der Erstellung des Suffix-Tries als auch
der Speicherverbrauch beträgt O(n2 ).
Ein Suffix-Trie ist eine naive Implementierung eines
Volltext-Indexes und wird aufgrund seines hohen
Speicherverbrauchs nicht genutzt.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
11
Beobachtungen
Der Trie kann lediglich das Vorkommen von Pattern im Text
feststellen, jedoch nicht die Position.
Im Suffix-Trie kommen oft Ketten von Knoten vor, die nur
einen Nachfolger haben.
Bei der Erstellung des Tries wird der i-te Buchstabe i + 1 mal
betrachtet. Wünschenswert wäre, wenn dies nur einmal
geschähen würde.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
12
Beobachtungen
Der Trie kann lediglich das Vorkommen von Pattern im Text
feststellen, jedoch nicht die Position.
Im Suffix-Trie kommen oft Ketten von Knoten vor, die nur
einen Nachfolger haben.
Bei der Erstellung des Tries wird der i-te Buchstabe i + 1 mal
betrachtet. Wünschenswert wäre, wenn dies nur einmal
geschähen würde.
All diese Verbesserungen realisiert der Suffix-Tree.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
12
Σ+ -Baum
Definition (Σ+ -Baum)
Sei Σ ein Alphabet, dann ist ein Σ+ -Baum ein gewurzelter Baum,
dessen Kanten jeweils mit einem nichtleeren String über Σ
annotiert sind, so dass kein Knoten zwei ausgehende Kanten hat,
die mit dem gleichen Buchstaben beginnen.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
13
Σ+ -Baum
Definition (Σ+ -Baum)
Sei Σ ein Alphabet, dann ist ein Σ+ -Baum ein gewurzelter Baum,
dessen Kanten jeweils mit einem nichtleeren String über Σ
annotiert sind, so dass kein Knoten zwei ausgehende Kanten hat,
die mit dem gleichen Buchstaben beginnen.
Definition (Kompakter Σ+ -Baum)
Ein Σ+ -Baum heißt kompakt, wenn kein Knoten (außer ggf. der
Wurzel) genau ein Kind besitzt.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
13
(String)Tiefe eines Baums
Definition (Tiefe eines Baums)
Die Tiefe dep(s) eines Knotens s ist die Anzahl der Kanten eines
eindeutig beschrifteten Pfades von der Wurzel zu s. Die Wurzel r
hat per Definition dep(r ) := 0.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
14
(String)Tiefe eines Baums
Definition (Tiefe eines Baums)
Die Tiefe dep(s) eines Knotens s ist die Anzahl der Kanten eines
eindeutig beschrifteten Pfades von der Wurzel zu s. Die Wurzel r
hat per Definition dep(r ) := 0.
Definition (Stringtiefe eines Suffix-Trees)
Für Knoten s sei str(s) die Konkatenation der Kantenbeschriftungen auf einem eindeutigen Pfad von der Wurzel zu s. Dabei sei
die Stringtiefe strdep(s) = |str(s)|.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
14
(String)Tiefe eines Baums
Definition (Tiefe eines Baums)
Die Tiefe dep(s) eines Knotens s ist die Anzahl der Kanten eines
eindeutig beschrifteten Pfades von der Wurzel zu s. Die Wurzel r
hat per Definition dep(r ) := 0.
Definition (Stringtiefe eines Suffix-Trees)
Für Knoten s sei str(s) die Konkatenation der Kantenbeschriftungen auf einem eindeutigen Pfad von der Wurzel zu s. Dabei sei
die Stringtiefe strdep(s) = |str(s)|.
Die Tiefe eines Knotens s muss nicht der Stringtiefe entsprechen.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
14
Suffix-Tree
Ein Suffix-Tree soll folgende Eigenschaften für einen Text T $
erfüllen:
Es gibt eine Bijektion zwischen den Blättern der Trees und
den Suffixen des Textes.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
15
Suffix-Tree
Ein Suffix-Tree soll folgende Eigenschaften für einen Text T $
erfüllen:
Es gibt eine Bijektion zwischen den Blättern der Trees und
den Suffixen des Textes.
Die Kanten des Baums sind mit nicht-leeren Teilstrings
von T $ annotiert.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
15
Suffix-Tree
Ein Suffix-Tree soll folgende Eigenschaften für einen Text T $
erfüllen:
Es gibt eine Bijektion zwischen den Blättern der Trees und
den Suffixen des Textes.
Die Kanten des Baums sind mit nicht-leeren Teilstrings
von T $ annotiert.
Ausgehende Kanten eines Knotens beginnen mit
verschiedenen Buchstaben.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
15
Suffix-Tree
Ein Suffix-Tree soll folgende Eigenschaften für einen Text T $
erfüllen:
Es gibt eine Bijektion zwischen den Blättern der Trees und
den Suffixen des Textes.
Die Kanten des Baums sind mit nicht-leeren Teilstrings
von T $ annotiert.
Ausgehende Kanten eines Knotens beginnen mit
verschiedenen Buchstaben.
Jeder innere Knoten hat ≥ 2 Kinder.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
15
Suffix-Tree
Ein Suffix-Tree soll folgende Eigenschaften für einen Text T $
erfüllen:
Es gibt eine Bijektion zwischen den Blättern der Trees und
den Suffixen des Textes.
Die Kanten des Baums sind mit nicht-leeren Teilstrings
von T $ annotiert.
Ausgehende Kanten eines Knotens beginnen mit
verschiedenen Buchstaben.
Jeder innere Knoten hat ≥ 2 Kinder.
Jeder Teilsting von T $ kann auf einem Pfad von der Wurzel
abgelesen werden.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
15
Suffix-Tree
]
[6
:7
a [0
:1]
$
]
:7
[5
s$
1:3]
na [
Beispiel-Tree
für den Text
T = ananas$:
5
[1:
na
4
7]
[5:
s$
nas$ [3:7]
s$ [5:7]
3]
6
1
3
7]
[5:
s$
nas$ [3:7]
0
2
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
16
Eigenschaften des Suffix-Tree
Der Speicherverbrauch pro Knoten sinkt auf O(1), da nur
noch das Indexpaar (b, e) und die Nachkommen des Knotens
gespeichert werden.
Das Paar (b, e) entspricht dem Teilstring T [b : e].
Da es genau n Blätter gibt und jeder innere Knoten mind.
zwei Kinder hat, ist die Anzahl der inneren Knoten auf n
beschränkt.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
17
Eigenschaften des Suffix-Tree
Der Speicherverbrauch pro Knoten sinkt auf O(1), da nur
noch das Indexpaar (b, e) und die Nachkommen des Knotens
gespeichert werden.
Das Paar (b, e) entspricht dem Teilstring T [b : e].
Da es genau n Blätter gibt und jeder innere Knoten mind.
zwei Kinder hat, ist die Anzahl der inneren Knoten auf n
beschränkt.
Der Speicherverbrauch liegt somit bei O(n).
Durch die Nummerierung der Blätter mit der Startposition
ihres entsprechenden Suffixes lässt sich bei einer Mustersuche
die Position im Text bestimmen.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
17
Konstruktion des Suffix-Trees
Beim naiven Ansatz behilft man sich eines Suffix-Tries, den
man zum Suffix-Tree erweitert.
Durch Zählen der Knoten im Pfad zu den Blättern, kann man
diese beschriften und die Kanten indizieren.
Die Erweiterung lässt sich in O(n2 ) realisieren, die
Gesamtlaufzeit beträgt also immer noch O(n2 ).
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
18
Konstruktion des Suffix-Trees
Beim naiven Ansatz behilft man sich eines Suffix-Tries, den
man zum Suffix-Tree erweitert.
Durch Zählen der Knoten im Pfad zu den Blättern, kann man
diese beschriften und die Kanten indizieren.
Die Erweiterung lässt sich in O(n2 ) realisieren, die
Gesamtlaufzeit beträgt also immer noch O(n2 ).
Umso bemerkenswerter ist es, dass der Ukkonen-Algorithmus
zur Konstruktion eines Suffix-Trees eine Laufzeit von O(n)
hat.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
18
Ukkonen-Algorithmus für Suffix-Trees
Der Algorithmus konstruiert zu einem Text T $ mit n := |T $|
einen Suffix-Tree in n Iterationen 0, 1, . . . , n − 1.
In jeder Iteration i wird das Zeichen T [i] zum Suffix-Tree
hinzugefügt.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
19
Ukkonen-Algorithmus für Suffix-Trees
Der Algorithmus konstruiert zu einem Text T $ mit n := |T $|
einen Suffix-Tree in n Iterationen 0, 1, . . . , n − 1.
In jeder Iteration i wird das Zeichen T [i] zum Suffix-Tree
hinzugefügt.
Der Algorithmus ist ein online-Algorithmus, das bedeutet,
dass nach jeder Iteration i der Baum ein (gültiger) Suffix-Tree
für das Präfix T [: i + 1] ist.
Um Linearlaufzeit zu erreichen, darf jede Iteration nur
amortisiert O(1) dauern. Mit verschiedenen Tricks lässt sich
diese Laufzeit erreichen.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
19
Tricks des Ukkonen-Algorithmus
1
Es wird das Tupel (s, k) verwaltet, wobei k der Anzahl der
Buchstaben an allen bereits beschrittenen Kanten und s dem
aktiven Knoten entspricht.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
20
Tricks des Ukkonen-Algorithmus
1
Es wird das Tupel (s, k) verwaltet, wobei k der Anzahl der
Buchstaben an allen bereits beschrittenen Kanten und s dem
aktiven Knoten entspricht.
2
Einmal eingeführte Blattknoten können nicht mehr erreicht
werden. Das Indexpaar zu dem Blattknoten wird mit (b, ∞)
beschriftet. So wird das Ende automatisch weitergeführt.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
20
Tricks des Ukkonen-Algorithmus
1
Es wird das Tupel (s, k) verwaltet, wobei k der Anzahl der
Buchstaben an allen bereits beschrittenen Kanten und s dem
aktiven Knoten entspricht.
2
Einmal eingeführte Blattknoten können nicht mehr erreicht
werden. Das Indexpaar zu dem Blattknoten wird mit (b, ∞)
beschriftet. So wird das Ende automatisch weitergeführt.
3
Um vom Knoten s mit str(s) = ax und a ∈ Σ, x ∈ Σ+ zum
Knoten w mit str(w ) = x in konstanter Zeit zu gelangen,
werden Verbindungen (Suffixlinks) eingesetzt.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
20
Tricks des Ukkonen-Algorithmus
1
Es wird das Tupel (s, k) verwaltet, wobei k der Anzahl der
Buchstaben an allen bereits beschrittenen Kanten und s dem
aktiven Knoten entspricht.
2
Einmal eingeführte Blattknoten können nicht mehr erreicht
werden. Das Indexpaar zu dem Blattknoten wird mit (b, ∞)
beschriftet. So wird das Ende automatisch weitergeführt.
3
Um vom Knoten s mit str(s) = ax und a ∈ Σ, x ∈ Σ+ zum
Knoten w mit str(w ) = x in konstanter Zeit zu gelangen,
werden Verbindungen (Suffixlinks) eingesetzt.
4
Beim Traversieren des Baums können Kanten mit bekanntem
Indexpaar (b, e) in konstanter Zeit übersprungen werden.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
20
Implementierung
Die Klasse STNode verwaltet die Knoten im Suffix-Tree S mit
folgenden Attributen:
Ein Dictionary targets : c → (s, b, e) mit c := T [b],
s ∈ nodes(S), 0 ≤ b < e ≤ n zum Speichern der Kinderknoten und Indexpaaren (b, e) auf den hinführenden Kanten.
Eine Referenz s link auf das längste Suffix.
Startposition pos des Suffixes im Text.
1
2
3
4
5
class STNode():
def __init__(self, s_link = None, pos= -1):
self.targets = dict()
self.s_link = s_link
self.pos = pos
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
21
Implementierung
Vorbereitung:
Der Algorithmus startet mit einem leeren Baum, bestehend
aus einer Wurzel root.
Da root selber ein sich ändernder Knoten ist, muss es noch
einen Knoten top oberhalb der Wurzel geben, der nur für die
Konstruktion relevant ist.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
22
Implementierung
Vorbereitung:
Der Algorithmus startet mit einem leeren Baum, bestehend
aus einer Wurzel root.
Da root selber ein sich ändernder Knoten ist, muss es noch
einen Knoten top oberhalb der Wurzel geben, der nur für die
Konstruktion relevant ist.
Von top aus soll root beim Lesen aller Zeichen aus dem
Alphabet erreichbar sein.
Der Suffixlink von root zeigt auf top.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
22
Implementierung
Vorbereitung:
Der Algorithmus startet mit einem leeren Baum, bestehend
aus einer Wurzel root.
Da root selber ein sich ändernder Knoten ist, muss es noch
einen Knoten top oberhalb der Wurzel geben, der nur für die
Konstruktion relevant ist.
Von top aus soll root beim Lesen aller Zeichen aus dem
Alphabet erreichbar sein.
Der Suffixlink von root zeigt auf top.
Es wird von der Wurzel gestartet.
Mit der Einfüge-Operation update sollen in jeder Iteration die
Zeichen aus T in den Baum eingefügt werden.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
22
Implementierung
1
2
3
4
5
6
def ukkonen(T):
top = STNode()
root = STNode(s_link = top)
for c in T:
if c not in top.targets:
top.targets[c] = (root, -1, 0)
7
8
9
10
11
s, k, pos = root, 0, 0
for i in range(len(T)):
s, k, pos = update(s, k, i, T, pos)
return root
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
23
Implementierung
Eine aktuelle Position kann sich entweder direkt an einem
inneren Knoten befinden, oder an einer Kante, die von einem
Knoten ausgeht.
Wenn k = i, dann befindet sich die aktuelle Position an einem
Knoten.
Wenn k < i, dann befindet sich die aktuelle Position an einer
Kante. Dabei sei s der ausgehende Knoten.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
24
Implementierung
Eine aktuelle Position kann sich entweder direkt an einem
inneren Knoten befinden, oder an einer Kante, die von einem
Knoten ausgeht.
Wenn k = i, dann befindet sich die aktuelle Position an einem
Knoten.
Wenn k < i, dann befindet sich die aktuelle Position an einer
Kante. Dabei sei s der ausgehende Knoten.
i
z
}|
{
Beispiel: T = ...xyzabc...xyz ab ...:
|
{z
}
k
x y z
s
a b
c
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
24
Implementierung
Definition (Referenz)
Sei w ein Teilstring von T [: i] mit w = uv , wobei u = T [j : b]
und v = T [b : e]. Ist str(s) = u dann ist (s, (b, e)) eine Referenz
auf w .
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
25
Implementierung
Definition (Referenz)
Sei w ein Teilstring von T [: i] mit w = uv , wobei u = T [j : b]
und v = T [b : e]. Ist str(s) = u dann ist (s, (b, e)) eine Referenz
auf w .
abcde
Beispiel: w =
=
b (abc, (6, 8)) =
b (a, (4, 8)) =
b (, (3, 8))
34567
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
25
Implementierung
Definition (Referenz)
Sei w ein Teilstring von T [: i] mit w = uv , wobei u = T [j : b]
und v = T [b : e]. Ist str(s) = u dann ist (s, (b, e)) eine Referenz
auf w .
abcde
Beispiel: w =
=
b (abc, (6, 8)) =
b (a, (4, 8)) =
b (, (3, 8))
34567
Definition (Kanonische Referenz)
Eine Referenz (s, (b, e)) heißt kanonisch, wenn e − b minimal für
alle Referenzen auf w ist.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
25
Implementierung
Beim Update wird zuerst überprüft, ob der aktuell
einzufügende Buchstabe von der aktuellen Position gelesen
werden kann.
Dabei muss unterschieden werden, ob die aktuelle Position
sich in einem Knoten befindet oder nicht.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
26
Implementierung
Beim Update wird zuerst überprüft, ob der aktuell
einzufügende Buchstabe von der aktuellen Position gelesen
werden kann.
Dabei muss unterschieden werden, ob die aktuelle Position
sich in einem Knoten befindet oder nicht.
Wenn sich die aktuelle Position an einer Kante befindet, und
der nächste Buchstabe nicht gelesen werden kann, wird ein
innerer Knoten hinzugefügt.
Diese Schritte werden in der Funktion test and split realisiert.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
26
Implementierung
1
2
3
def test_and_split(s, k, i, T):
if k == i:
return T[i] in s.targets, s
4
5
6
7
8
s1, b, e =
active = i
if T[i] ==
return
s.targets[T[k]]
- k + b
T[active]:
True, s
9
10
11
12
13
r = STNode()
s.targets[T[b]] = (r, b, active)
r.targets[T[active]] = (s1, active, e)
return False, r
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
27
Implementierung
Während eines Updatevorgangs kommt es vor, dass von der
aktuellen Position auf einen inneren Knoten geringerer Tiefe
gewechselt wird.
Um zu wahren, dass die Referenz (s, (k, i)) wieder kanonisch
wird, wird die Funktion canonize aufgerufen.
Beispiel: T = ...abcdefghi...abcdefgh...
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
28
Implementierung
Während eines Updatevorgangs kommt es vor, dass von der
aktuellen Position auf einen inneren Knoten geringerer Tiefe
gewechselt wird.
Um zu wahren, dass die Referenz (s, (k, i)) wieder kanonisch
wird, wird die Funktion canonize aufgerufen.
Beispiel: T = ...abcdefghi...abcdefgh...
↑k 0
↑k ↑i
fgh
i
e
cd
i
fgh
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
cd
e
ab
ab
(k 0 , i) → (k, i)
28
Implementierung
1
2
3
4
5
6
7
8
def canonize(s, k, i, T):
if i < k: return s, k
s1, b, e = s.targets[T[k]]
while e - b <= i + 1 - k:
s, k = s1, k + e - b
if k <= i:
s1, b, e = s.targets[T[k]]
return s, k
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
29
Implementierung
1
2
3
def update(s, k, i, T, pos):
old_r, n = None, len(T)
endPoint, r = test_and_split(s, k, i, T)
4
5
6
7
8
9
10
while not endPoint:
r.targets[T[i]] = (STNode(pos=pos), i, n)
if old_r != None: old_r.s_link = r
old_r, pos = r, pos + 1
s, k = canonize(s.s_link, k, i - 1, T)
endPoint, r = test_and_split(s, k, i, T)
11
12
13
14
if old_r != None: old_r.s_link = s
s, k = canonize(s, k, i, T)
return s, k, pos
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
30
endPoint
k
r
, 0)
(−1
(−1, 0)
$
a
b
, 0)
babacbab$
0
r
−
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
c
r
0
−
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
endPoint
k
r
, 0)
(−1
(−1, 0)
$
a
b
, 0)
babacbab$
0
r
−
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
c
r
0
−
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
endPoint
k
r
s1
e
, 0)
(−1
(−1, 0)
$
a
b
, 0)
babacbab$
0
r
−
−
(−1, 0)
1 def test_and_split(s, k, i, T):
2
if k == i:
3
return T[i] in s.targets, s
4
5
s1, b, e = s.targets[T[k]]
6
active = i - k + b
7
if T[i] == T[active]:
8
return True, s
9
10
r = STNode()
11
s.targets[T[b]] = (r, b, active)
12
r.targets[T[active]] = (s1, active, e)
13
return False, r
T
i
s
old r
b
t
(−1
Implementierung
c
r
0
−
−
−
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
endPoint
k
r
s1
e
, 0)
(−1
(−1, 0)
$
a
b
, 0)
babacbab$
0
r
−
−
(−1, 0)
1 def test_and_split(s, k, i, T):
2
if k == i:
3
return T[i] in s.targets, s
4
5
s1, b, e = s.targets[T[k]]
6
active = i - k + b
7
if T[i] == T[active]:
8
return True, s
9
10
r = STNode()
11
s.targets[T[b]] = (r, b, active)
12
r.targets[T[active]] = (s1, active, e)
13
return False, r
T
i
s
old r
b
t
(−1
Implementierung
c
r
0
−
−
−
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
endPoint
k
r
, 0)
(−1
(−1, 0)
$
a
b
, 0)
babacbab$
0
r
−
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
c
r
false
0
r
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
r
9)
endPoint
k
r
$
(0,
babacbab$
0
r
r
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
b
false
0
r
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
r
9)
endPoint
k
r
$
(0,
babacbab$
0
r
r
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
b
false
0
r
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
r
9)
endPoint
k
r
s1
e
$
(0,
babacbab$
−1
t
r
−
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
T
i
s
old r
b
t
(−1
Implementierung
b
false
0
r
−
−
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
r
9)
endPoint
k
r
s1
e
$
(0,
babacbab$
−1
t
r
−
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
T
i
s
old r
b
t
(−1
Implementierung
b
false
0
r
−
−
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
r
9)
endPoint
k
r
$
(0,
babacbab$
0
t
r
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
b
false
0
r
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
r
9)
endPoint
k
r
s1
e
$
(0,
babacbab$
0
t
r
−
(−1, 0)
1 def test_and_split(s, k, i, T):
2
if k == i:
3
return T[i] in s.targets, s
4
5
s1, b, e = s.targets[T[k]]
6
active = i - k + b
7
if T[i] == T[active]:
8
return True, s
9
10
r = STNode()
11
s.targets[T[b]] = (r, b, active)
12
r.targets[T[active]] = (s1, active, e)
13
return False, r
T
i
s
old r
b
t
(−1
Implementierung
b
false
0
r
−
−
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
r
9)
endPoint
k
r
s1
e
$
(0,
babacbab$
0
t
r
−
(−1, 0)
1 def test_and_split(s, k, i, T):
2
if k == i:
3
return T[i] in s.targets, s
4
5
s1, b, e = s.targets[T[k]]
6
active = i - k + b
7
if T[i] == T[active]:
8
return True, s
9
10
r = STNode()
11
s.targets[T[b]] = (r, b, active)
12
r.targets[T[active]] = (s1, active, e)
13
return False, r
T
i
s
old r
b
t
(−1
Implementierung
b
false
0
r
−
−
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
r
9)
endPoint
k
r
$
(0,
babacbab$
0
t
r
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
b
true
0
t
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
r
9)
endPoint
k
r
s1
e
$
(0,
babacbab$
0
t
r
−
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
T
i
s
old r
b
t
(−1
Implementierung
b
true
0
t
−
−
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
r
9)
endPoint
k
r
s1
e
$
(0,
babacbab$
0
t
r
−1
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
T
i
s
old r
b
t
(−1
Implementierung
b
true
0
t
r
0
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
r
9)
endPoint
k
r
s1
e
$
(0,
babacbab$
0
r
r
−1
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
T
i
s
old r
b
t
(−1
Implementierung
b
true
1
t
r
0
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
r
9)
endPoint
k
r
s1
e
$
(0,
babacbab$
0
r
r
−1
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
T
i
s
old r
b
t
(−1
Implementierung
b
true
1
t
r
0
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
r
9)
endPoint
k
r
$
(0,
babacbab$
0
r
r
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
b
true
1
t
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
r
9)
endPoint
k
r
$
(0,
babacbab$
1
r
−
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
b
a
1
−
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
r
9)
endPoint
k
r
$
(0,
babacbab$
1
r
−
(−1, 0)
1 def test_and_split(s, k, i, T):
2
if k == i:
3
return T[i] in s.targets, s
4
5
s1, b, e = s.targets[T[k]]
6
active = i - k + b
7
if T[i] == T[active]:
8
return True, s
9
10
r = STNode()
11
s.targets[T[b]] = (r, b, active)
12
r.targets[T[active]] = (s1, active, e)
13
return False, r
T
i
s
old r
t
(−1
Implementierung
b
a
1
−
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
r
9)
endPoint
k
r
$
(0,
babacbab$
1
r
−
(−1, 0)
1 def test_and_split(s, k, i, T):
2
if k == i:
3
return T[i] in s.targets, s
4
5
s1, b, e = s.targets[T[k]]
6
active = i - k + b
7
if T[i] == T[active]:
8
return True, s
9
10
r = STNode()
11
s.targets[T[b]] = (r, b, active)
12
r.targets[T[active]] = (s1, active, e)
13
return False, r
T
i
s
old r
t
(−1
Implementierung
b
a
1
−
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
r
9)
endPoint
k
r
$
(0,
babacbab$
1
r
−
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
b
a
false
1
r
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
(1
,9
)
r
a
9)
endPoint
k
r
$
(0,
babacbab$
1
r
−
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
b
a
false
1
r
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
(1
,9
)
r
a
9)
endPoint
k
r
$
(0,
babacbab$
1
r
r
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
b
a
false
1
r
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
(1
,9
)
r
a
9)
endPoint
k
r
s1
e
$
(0,
babacbab$
0
t
r
−
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
T
i
s
old r
b
t
(−1
Implementierung
b
a
false
1
r
−
−
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
(1
,9
)
r
a
9)
endPoint
k
r
s1
e
$
(0,
babacbab$
0
t
r
−
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
T
i
s
old r
b
t
(−1
Implementierung
b
a
false
1
r
−
−
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
(1
,9
)
r
a
9)
endPoint
k
r
$
(0,
babacbab$
1
t
r
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
b
a
false
1
r
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
(1
,9
)
r
a
9)
endPoint
k
r
s1
e
$
(0,
babacbab$
1
t
r
−
(−1, 0)
1 def test_and_split(s, k, i, T):
2
if k == i:
3
return T[i] in s.targets, s
4
5
s1, b, e = s.targets[T[k]]
6
active = i - k + b
7
if T[i] == T[active]:
8
return True, s
9
10
r = STNode()
11
s.targets[T[b]] = (r, b, active)
12
r.targets[T[active]] = (s1, active, e)
13
return False, r
T
i
s
old r
b
t
(−1
Implementierung
b
a
false
1
r
−
−
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
(1
,9
)
r
a
9)
endPoint
k
r
s1
e
$
(0,
babacbab$
1
t
r
−
(−1, 0)
1 def test_and_split(s, k, i, T):
2
if k == i:
3
return T[i] in s.targets, s
4
5
s1, b, e = s.targets[T[k]]
6
active = i - k + b
7
if T[i] == T[active]:
8
return True, s
9
10
r = STNode()
11
s.targets[T[b]] = (r, b, active)
12
r.targets[T[active]] = (s1, active, e)
13
return False, r
T
i
s
old r
b
t
(−1
Implementierung
b
a
false
1
r
−
−
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
(1
,9
)
r
a
9)
endPoint
k
r
$
(0,
babacbab$
1
t
r
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
b
a
true
1
t
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
(1
,9
)
r
a
9)
endPoint
k
r
s1
e
$
(0,
babacbab$
1
t
r
−
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
T
i
s
old r
b
t
(−1
Implementierung
b
a
true
1
t
−
−
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
(1
,9
)
r
a
9)
endPoint
k
r
s1
e
$
(0,
babacbab$
1
t
r
−1
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
T
i
s
old r
b
t
(−1
Implementierung
b
a
true
1
t
r
0
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
(1
,9
)
r
a
9)
endPoint
k
r
s1
e
$
(0,
babacbab$
1
r
r
−1
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
T
i
s
old r
b
t
(−1
Implementierung
b
a
true
2
t
r
0
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
(1
,9
)
r
a
9)
endPoint
k
r
s1
e
$
(0,
babacbab$
1
r
r
−1
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
T
i
s
old r
b
t
(−1
Implementierung
b
a
true
2
t
r
0
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
(1
,9
)
r
a
9)
endPoint
k
r
$
(0,
babacbab$
1
r
r
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
b
a
true
2
t
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
c
(1
a
b
9)
,9
)
r
(0,
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
(−1, 0)
, 0)
t
(−1
Implementierung
b
a
b
T
i
s
old r
babacbab$
2
r
−
endPoint
k
r
2
−
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
1 def test_and_split(s, k, i, T):
2
if k == i:
3
return T[i] in s.targets, s
4
5
s1, b, e = s.targets[T[k]]
6
active = i - k + b
7
if T[i] == T[active]:
8
return True, s
9
10
r = STNode()
11
s.targets[T[b]] = (r, b, active)
12
r.targets[T[active]] = (s1, active, e)
13
return False, r
(−1, 0)
, 0)
t
(−1
Implementierung
c
(1
b
9)
a
(0,
,9
)
r
b
a
b
T
i
s
old r
b
babacbab$
2
r
−
−
endPoint
k
r
s1
e
2
−
−
−
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
1 def test_and_split(s, k, i, T):
2
if k == i:
3
return T[i] in s.targets, s
4
5
s1, b, e = s.targets[T[k]]
6
active = i - k + b
7
if T[i] == T[active]:
8
return True, s
9
10
r = STNode()
11
s.targets[T[b]] = (r, b, active)
12
r.targets[T[active]] = (s1, active, e)
13
return False, r
(−1, 0)
, 0)
t
(−1
Implementierung
c
(1
b
9)
a
(0,
,9
)
r
b
a
b
T
i
s
old r
b
babacbab$
2
r
−
−
endPoint
k
r
s1
e
2
−
−
−
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
c
(1
a
b
9)
,9
)
r
(0,
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
(−1, 0)
, 0)
t
(−1
Implementierung
b
a
b
T
i
s
old r
babacbab$
2
r
−
endPoint
k
r
true
2
r
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
(−1, 0)
, 0)
t
(−1
Implementierung
c
(1
b
9)
a
(0,
,9
)
r
b
a
b
T
i
s
old r
b
babacbab$
2
r
−
−
endPoint
k
r
s1
e
true
2
r
−
−
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
(−1, 0)
, 0)
t
(−1
Implementierung
c
(1
b
9)
a
(0,
,9
)
r
b
a
b
T
i
s
old r
b
babacbab$
2
r
−
0
endPoint
k
r
s1
e
true
2
r
0
9
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
(−1, 0)
, 0)
t
(−1
Implementierung
c
(1
b
9)
a
(0,
,9
)
r
b
a
b
T
i
s
old r
b
babacbab$
2
r
−
0
endPoint
k
r
s1
e
true
2
r
0
9
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
c
(1
a
b
9)
,9
)
r
(0,
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
(−1, 0)
, 0)
t
(−1
Implementierung
b
a
b
T
i
s
old r
babacbab$
2
r
−
endPoint
k
r
2
r
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
(−1, 0)
, 0)
t
(−1
Implementierung
c
(1
b
9)
a
(0,
,9
)
r
b
a
b
a
T
i
s
old r
babacbab$
3
r
−
endPoint
k
r
2
−
a
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
1 def test_and_split(s, k, i, T):
2
if k == i:
3
return T[i] in s.targets, s
4
5
s1, b, e = s.targets[T[k]]
6
active = i - k + b
7
if T[i] == T[active]:
8
return True, s
9
10
r = STNode()
11
s.targets[T[b]] = (r, b, active)
12
r.targets[T[active]] = (s1, active, e)
13
return False, r
(−1, 0)
, 0)
t
(−1
Implementierung
c
(1
b
9)
a
(0,
,9
)
r
b
a
b
a
T
i
s
old r
b
babacbab$
3
r
−
−
endPoint
k
r
s1
e
2
−
−
−
a
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
1 def test_and_split(s, k, i, T):
2
if k == i:
3
return T[i] in s.targets, s
4
5
s1, b, e = s.targets[T[k]]
6
active = i - k + b
7
if T[i] == T[active]:
8
return True, s
9
10
r = STNode()
11
s.targets[T[b]] = (r, b, active)
12
r.targets[T[active]] = (s1, active, e)
13
return False, r
(−1, 0)
, 0)
t
(−1
Implementierung
c
(1
b
9)
a
(0,
,9
)
r
b
a
b
a
T
i
s
old r
b
babacbab$
3
r
−
0
endPoint
k
r
s1
e
2
−
0
9
a
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
(−1, 0)
, 0)
t
(−1
Implementierung
c
(1
b
9)
a
(0,
,9
)
r
b
a
b
a
T
i
s
old r
babacbab$
3
r
−
endPoint
k
r
true
2
r
a
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
(−1, 0)
, 0)
t
(−1
Implementierung
c
(1
b
9)
a
(0,
,9
)
r
b
a
b
a
T
i
s
old r
b
babacbab$
3
r
−
−
endPoint
k
r
s1
e
true
2
r
−
−
a
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
(−1, 0)
, 0)
t
(−1
Implementierung
c
(1
b
9)
a
(0,
,9
)
r
b
a
b
a
T
i
s
old r
b
babacbab$
3
r
−
0
endPoint
k
r
s1
e
true
2
r
0
9
a
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
(−1, 0)
, 0)
t
(−1
Implementierung
c
(1
b
9)
a
(0,
,9
)
r
b
a
b
a
T
i
s
old r
b
babacbab$
3
r
−
0
endPoint
k
r
s1
e
true
2
r
0
9
a
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
(−1, 0)
, 0)
t
(−1
Implementierung
c
(1
b
9)
a
(0,
,9
)
r
b
a
b
a
T
i
s
old r
babacbab$
3
r
−
endPoint
k
r
true
2
r
a
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
b
c
(1
,9
)
r
a
b
9)
2
−
a
, 0)
endPoint
k
r
$
(0,
babacbab$
4
r
−
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
b
a
b
a
c
a
c
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
a
b
, 0)
c
(1
,9
)
r
a
b
2
−
0
9
9)
endPoint
k
r
s1
e
$
(0,
babacbab$
4
r
−
0
(−1, 0)
1 def test_and_split(s, k, i, T):
2
if k == i:
3
return T[i] in s.targets, s
4
5
s1, b, e = s.targets[T[k]]
6
active = i - k + b
7
if T[i] == T[active]:
8
return True, s
9
10
r = STNode()
11
s.targets[T[b]] = (r, b, active)
12
r.targets[T[active]] = (s1, active, e)
13
return False, r
T
i
s
old r
b
t
(−1
Implementierung
b
a
b
a
c
a
c
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
1 def test_and_split(s, k, i, T):
2
if k == i:
3
return T[i] in s.targets, s
4
5
s1, b, e = s.targets[T[k]]
6
active = i - k + b
7
if T[i] == T[active]:
8
return True, s
9
10
r = STNode()
11
s.targets[T[b]] = (r, b, active)
12
r.targets[T[active]] = (s1, active, e)
13
return False, r
(−1, 0)
, 0)
t
(−1
Implementierung
c
)
,2
(1
(0
,9
)
r
b
a
a
b
9)
n0
T
i
s
old r
b
babacbab$
4
r
−
0
endPoint
k
r
s1
e
2
n0
0
9
(2 ,
a
c
b
a
c
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
1 def test_and_split(s, k, i, T):
2
if k == i:
3
return T[i] in s.targets, s
4
5
s1, b, e = s.targets[T[k]]
6
active = i - k + b
7
if T[i] == T[active]:
8
return True, s
9
10
r = STNode()
11
s.targets[T[b]] = (r, b, active)
12
r.targets[T[active]] = (s1, active, e)
13
return False, r
(−1, 0)
, 0)
t
(−1
Implementierung
c
)
,2
(1
(0
,9
)
r
b
a
a
b
9)
n0
T
i
s
old r
b
babacbab$
4
r
−
0
endPoint
k
r
s1
e
2
n0
0
9
(2 ,
a
c
b
a
c
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
b
c
(1
,9
)
r
)
,2
false
2
n0
a
, 0)
endPoint
k
r
$
(0
babacbab$
4
r
−
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
b
a
a
b
9)
n0
(2 ,
a
c
b
a
c
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
b
c
(1
,9
)
r
)
,2
b
a
a
b
n0
9)
(4,
(2 ,
a
c
9)
false
2
n0
a
, 0)
endPoint
k
r
$
(0
babacbab$
4
r
−
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
c
b
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
b
c
(1
,9
)
r
)
,2
b
a
a
b
n0
9)
(4,
(2 ,
a
c
9)
false
2
n0
a
, 0)
endPoint
k
r
$
(0
babacbab$
4
r
n0
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
c
b
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
(−1, 0)
, 0)
t
(−1
Implementierung
c
)
,2
(1
(0
,9
)
r
b
a
a
b
n0
9)
(4,
babacbab$
3
t
n0
−
endPoint
k
r
s1
e
false
2
n0
−
−
(2 ,
a
c
9)
T
i
s
old r
b
c
b
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
(−1, 0)
, 0)
t
(−1
Implementierung
c
)
,2
(1
(0
,9
)
r
b
a
a
b
n0
9)
(4,
babacbab$
3
t
n0
−1
endPoint
k
r
s1
e
false
2
n0
r
0
(2 ,
a
c
9)
T
i
s
old r
b
c
b
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
(−1, 0)
, 0)
t
(−1
Implementierung
c
)
,2
(1
(0
,9
)
r
b
a
a
b
n0
9)
(4,
babacbab$
3
r
n0
−1
endPoint
k
r
s1
e
false
3
n0
r
0
(2 ,
a
c
9)
T
i
s
old r
b
c
b
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
(−1, 0)
, 0)
t
(−1
Implementierung
c
)
,2
(1
(0
,9
)
r
b
a
a
b
n0
9)
(4,
babacbab$
3
r
n0
1
endPoint
k
r
s1
e
false
3
n0
1
9
(2 ,
a
c
9)
T
i
s
old r
b
c
b
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
(−1, 0)
, 0)
t
(−1
Implementierung
c
)
,2
(1
(0
,9
)
r
b
a
a
b
n0
9)
(4,
babacbab$
3
r
n0
1
endPoint
k
r
s1
e
false
3
n0
1
9
(2 ,
a
c
9)
T
i
s
old r
b
c
b
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
b
c
(1
,9
)
r
)
,2
b
a
a
b
n0
9)
(4,
(2 ,
a
c
9)
false
3
n0
a
, 0)
endPoint
k
r
$
(0
babacbab$
4
r
n0
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
c
b
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
1 def test_and_split(s, k, i, T):
2
if k == i:
3
return T[i] in s.targets, s
4
5
s1, b, e = s.targets[T[k]]
6
active = i - k + b
7
if T[i] == T[active]:
8
return True, s
9
10
r = STNode()
11
s.targets[T[b]] = (r, b, active)
12
r.targets[T[active]] = (s1, active, e)
13
return False, r
(−1, 0)
, 0)
t
(−1
Implementierung
c
)
,2
(1
(0
,9
)
r
b
a
a
b
n0
9)
(4,
babacbab$
4
r
n0
−
endPoint
k
r
s1
e
false
3
n0
−
−
(2 ,
a
c
9)
T
i
s
old r
b
c
b
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
, 0)
(−1, 0)
1 def test_and_split(s, k, i, T):
2
if k == i:
3
return T[i] in s.targets, s
4
5
s1, b, e = s.targets[T[k]]
6
active = i - k + b
7
if T[i] == T[active]:
8
return True, s
9
10
r = STNode()
11
s.targets[T[b]] = (r, b, active)
12
r.targets[T[active]] = (s1, active, e)
13
return False, r
(−1, 0)
, 0)
t
(−1
Implementierung
c
)
,2
(1
(0
,9
)
r
b
a
a
b
n0
9)
(4,
babacbab$
4
r
n0
1
endPoint
k
r
s1
e
false
3
n0
1
9
(2 ,
a
c
9)
T
i
s
old r
b
c
b
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
r
)
,2
,2
c
(0
)
(1
, 0)
(−1, 0)
1 def test_and_split(s, k, i, T):
2
if k == i:
3
return T[i] in s.targets, s
4
5
s1, b, e = s.targets[T[k]]
6
active = i - k + b
7
if T[i] == T[active]:
8
return True, s
9
10
r = STNode()
11
s.targets[T[b]] = (r, b, active)
12
r.targets[T[active]] = (s1, active, e)
13
return False, r
(−1, 0)
, 0)
t
(−1
Implementierung
b
a
n1
(2,
9)
a
b
n0
endPoint
k
r
s1
e
false
3
n1
1
9
a
c
9)
babacbab$
4
r
n0
1
(2 ,
9)
(4,
T
i
s
old r
b
c
b
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
r
)
,2
,2
c
(0
)
(1
, 0)
(−1, 0)
1 def test_and_split(s, k, i, T):
2
if k == i:
3
return T[i] in s.targets, s
4
5
s1, b, e = s.targets[T[k]]
6
active = i - k + b
7
if T[i] == T[active]:
8
return True, s
9
10
r = STNode()
11
s.targets[T[b]] = (r, b, active)
12
r.targets[T[active]] = (s1, active, e)
13
return False, r
(−1, 0)
, 0)
t
(−1
Implementierung
b
a
n1
(2,
9)
a
b
n0
endPoint
k
r
s1
e
false
3
n1
1
9
a
c
9)
babacbab$
4
r
n0
1
(2 ,
9)
(4,
T
i
s
old r
b
c
b
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
b
)
(1
,2
c
r
)
,2
b
a
n1
(2,
9)
a
b
n0
a
c
9)
(2 ,
9)
(4,
false
3
n1
a
, 0)
endPoint
k
r
$
(0
babacbab$
4
r
n0
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
c
b
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
)
,2
c
r
)
,2
(1
, 0)
b
(0
b
a
(2,
9)
n1
b
a
c
n0
a
c
9)
(2 ,
9)
(4,
false
3
n1
a
9)
endPoint
k
r
$
(4,
babacbab$
4
r
n0
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
c
b
3
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
)
,2
c
r
)
,2
(1
, 0)
b
(0
b
a
(2,
9)
n1
b
a
c
n0
a
c
9)
(2 ,
9)
(4,
false
3
n1
a
9)
endPoint
k
r
$
(4,
babacbab$
4
r
n0
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
c
b
3
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
)
,2
c
r
)
,2
(1
, 0)
b
(0
b
a
(2,
9)
n1
b
a
c
n0
a
c
9)
(2 ,
9)
(4,
false
3
n1
a
9)
endPoint
k
r
$
(4,
babacbab$
4
r
n1
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
c
b
3
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
r
)
,2
,2
c
(0
)
(1
, 0)
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
(−1, 0)
, 0)
t
(−1
Implementierung
b
a
(2,
a
9)
b
(4,
9)
n1
c
n0
endPoint
k
r
s1
e
false
3
n1
−
−
a
c
9)
babacbab$
3
t
n1
−
(2 ,
9)
(4,
T
i
s
old r
b
c
b
3
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
r
)
,2
,2
c
(0
)
(1
, 0)
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
(−1, 0)
, 0)
t
(−1
Implementierung
b
a
(2,
a
9)
b
(4,
9)
n1
c
n0
endPoint
k
r
s1
e
false
3
n1
r
0
a
c
9)
babacbab$
3
t
n1
−1
(2 ,
9)
(4,
T
i
s
old r
b
c
b
3
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
r
)
,2
,2
c
(0
)
(1
, 0)
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
(−1, 0)
, 0)
t
(−1
Implementierung
b
a
(2,
a
9)
b
(4,
9)
n1
c
n0
endPoint
k
r
s1
e
false
4
n1
r
0
a
c
9)
babacbab$
3
r
n1
−1
(2 ,
9)
(4,
T
i
s
old r
b
c
b
3
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
(−1
$
a
b
r
)
,2
,2
c
(0
)
(1
, 0)
(−1, 0)
1 def canonize(s, k, i, T):
2
if i < k: return s, k
3
4
s1, b, e = s.targets[T[k]]
5
while e - b <= i + 1 - k:
6
k += e - b
7
s = s1
8
if k <= i:
9
s1, b, e = s.targets[T[k]]
10
return s, k
(−1, 0)
, 0)
t
(−1
Implementierung
b
a
(2,
a
9)
b
(4,
9)
n1
c
n0
endPoint
k
r
s1
e
false
4
n1
r
0
a
c
9)
babacbab$
3
r
n1
−1
(2 ,
9)
(4,
T
i
s
old r
b
c
b
3
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
)
,2
c
r
)
,2
(1
, 0)
b
(0
b
a
(2,
9)
n1
b
a
c
n0
a
c
9)
(2 ,
9)
(4,
false
4
n1
a
9)
endPoint
k
r
$
(4,
babacbab$
4
r
n1
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
c
b
3
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
)
,2
c
r
)
,2
(1
, 0)
b
(0
b
a
(2,
9)
n1
b
a
c
n0
a
c
9)
(2 ,
9)
(4,
false
4
r
a
9)
endPoint
k
r
$
(4,
babacbab$
4
r
n2
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
c
b
3
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
)
,2
r
c
(4,
9)
)
,2
(1
, 0)
b
(0
c
b
a
(2,
9)
n1
b
a
c
4
n0
a
c
9)
(2 ,
9)
(4,
false
4
r
a
9)
endPoint
k
r
$
(4,
babacbab$
4
r
n1
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
c
b
3
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
)
,2
r
c
(4,
9)
)
,2
(1
, 0)
b
(0
c
b
a
(2,
9)
n1
b
a
c
4
n0
a
c
9)
(2 ,
9)
(4,
false
4
r
a
9)
endPoint
k
r
$
(4,
babacbab$
4
r
n1
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
c
b
3
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
)
,2
r
c
(4,
9)
)
,2
(1
, 0)
b
(0
c
b
a
(2,
9)
n1
b
a
c
4
n0
a
c
9)
(2 ,
9)
(4,
false
4
r
a
9)
endPoint
k
r
$
(4,
babacbab$
4
t
r
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
c
b
3
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
)
,2
r
c
(4,
9)
)
,2
(1
, 0)
b
(0
c
b
a
(2,
9)
n1
b
a
c
4
n0
a
c
9)
(2 ,
9)
(4,
true
4
t
a
9)
endPoint
k
r
$
(4,
babacbab$
4
t
r
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
c
b
3
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
)
,2
r
c
(4,
9)
)
,2
(1
, 0)
b
(0
c
b
a
(2,
9)
n1
b
a
c
4
n0
a
c
9)
(2 ,
9)
(4,
true
5
t
a
9)
endPoint
k
r
$
(4,
babacbab$
4
r
r
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
c
b
3
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
)
,2
r
c
(4,
9)
)
,2
(1
, 0)
b
(0
c
b
a
(2,
9)
n1
b
a
c
4
n0
a
c
9)
(2 ,
9)
(4,
true
5
t
a
9)
endPoint
k
r
$
(4,
babacbab$
4
r
r
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
c
b
3
a
c
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
)
,2
r
c
(4,
9)
)
,2
(1
, 0)
b
(0
c
b
b
a
(2,
9)
n1
b
a
c
b
9)
(2 ,
9)
a
c
b
4
n0
(4,
5
−
a
9)
endPoint
k
r
$
(4,
babacbab$
5
r
−
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
c
b
b
3
a
c
b
2
1
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
)
,2
r
c
(4,
9)
)
,2
(1
, 0)
b
(0
c
b
a
b
a
(2,
9)
n1
b
a
c
b
a
9)
(2 ,
9)
a
c
b
a
c
b
a
b
3
1
4
n0
(4,
7
−
a
9)
endPoint
k
r
$
(4,
babacbab$
6
n0
−
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
a
c
b
a
2
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
)
,2
r
c
(4,
9)
)
,2
(1
, 0)
b
(0
c
b
a
b
a
b
a
a
c
b
a
b
3
1
4
n0
9)
c
b
a
b
9)
b
(2 ,
(2,
9)
n1
(4,
7
−
a
9)
endPoint
k
r
$
(4,
babacbab$
7
n0
−
(−1, 0)
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
c
b
a
b
b
a
c
b
a
b
2
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
r
)
,2
c
(4,
9)
c
)
,2
(1
, 0)
b
(0
b
b
a
a
b
$
a
(
5
9)
b
n2
$
1
4
n0
(4,
a
c
b
a
b
$
)
3
2,
9)
c
b
a
b
$
3
9)
b
(8,
(2,
9)
n1
(3 ,
7
−
(−1, 0)
endPoint
k
r
a
9)
babacbab$
8
n1
−
$
(4,
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
a
c
b
a
b
$
c
b
a
b
$
2
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
, 0)
(−1, 0)
r
(4,
)
,2
(2
b
$
a
4
n0
(
9)
$
5
9)
b
n2
9)
1
)
3
2,
(3 ,
a
c
b
a
b
$
c
b
a
b
$
3
(8,
9)
a
(4,
(8,
b
n1
b
n3
6
c
b
a
)
,3
9)
(0
,2
c
9)
7
−
b
(4,
endPoint
k
r
a
)
$
babacbab$
8
r
−
$
(1
)
(3, 9
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
a
c
b
a
b
$
c
b
a
b
$
2
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
, 0)
(−1
(−1, 0)
(0
9)
(8,
a
b
$
a
$
4
c 7
) n0
3
,
b
(2
a
b
b
c
n2
$
b
a
3
b
a
$
$
c
b
2
5
a
b
$
(4,
9)
9)
9)
1
(3 ,
a
c
b
a
b
$
(8,
9)
b
)
,2
(8,
c
(1
6
9)
)
,1
(2
n4
n1
b
n3
(4,
b
a
)
,3
, 0)
(−1, 0)
r
,2
c
9)
8
−
b
(4,
endPoint
k
r
a
)
$
babacbab$
8
r
−
$
(1
)
(3, 9
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
c
, 0)
(−1
(−1, 0)
b
n4
9)
(8,
a
b
$
)
,2
n1
b
(1
a
$
4
c 7
) n0
3
,
b
(2
a
b
b
c
n2
$
b
a
3
b
a
$
$
c
b
2
5
a
b
$
(4,
9)
9)
9)
1
(3 ,
a
c
b
a
b
$
(8,
9)
9)
)
,1
(8,
(4,
(0
(2
)
,3
b
n3
6
r
, 0)
(−1, 0)
)
(8, 9 )
,2
(1
c
9)
9
−
b
(4,
endPoint
k
r
a
a
8
$
babacbab$
8
r
−
$
$
)
(3, 9
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
c
, 0)
(−1
(−1, 0)
b
n4
9)
(8,
a
b
$
)
,2
n1
b
(1
a
$
4
c 7
) n0
3
,
b
(2
a
b
b
c
n2
$
b
a
3
b
a
$
$
c
b
2
5
a
b
$
(4,
9)
9)
9)
1
(3 ,
a
c
b
a
b
$
(8,
9)
9)
)
,1
(8,
(4,
(0
(2
)
,3
b
n3
6
r
, 0)
(−1, 0)
)
(8, 9 )
,2
(1
c
9)
9
−
b
(4,
endPoint
k
r
a
a
8
$
babacbab$
8
−
−
$
$
)
(3, 9
1 def update(s, k, i, T, pos):
2
old_r, n = None, len(T)
3
endPoint, r = test_and_split(s, k, i, T)
4
5
while not endPoint:
6
r.targets[T[i]] = (STNode(pos=pos), i, n)
7
if old_r != None: old_r.s_link = r
8
old_r, pos = r, pos + 1
9
s, k = canonize(s.s_link, k, i - 1, T)
10
endPoint, r = test_and_split(s, k, i, T)
11
12
if old_r != None: old_r.s_link = s
13
s, k = canonize(s, k, i, T)
14
return s, k, pos
T
i
s
old r
t
(−1
Implementierung
0
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
31
Laufzeitanalyse
While-Schleife in canonize:
Zu beginn ist k = 0.
Die While-Bedingung lautet e − b ≤ i + 1 − k.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
32
Laufzeitanalyse
While-Schleife in canonize:
Zu beginn ist k = 0.
Die While-Bedingung lautet e − b ≤ i + 1 − k.
Für alle Intervalle gilt: e − b ≥ 1.
Pro Betreten der While-Schleife wird k um mind. 1 erhöht.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
32
Laufzeitanalyse
While-Schleife in canonize:
Zu beginn ist k = 0.
Die While-Bedingung lautet e − b ≤ i + 1 − k.
Für alle Intervalle gilt: e − b ≥ 1.
Pro Betreten der While-Schleife wird k um mind. 1 erhöht.
Sobald i < k ist, bricht die While-Schleife ab.
Insgesamt kann k max. n mal um 1 erhöht werden. Somit
kann die Schleife auch nur O(n) mal betreten werden.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
32
Laufzeitanalyse
While-schleife in update:
Pro update-Aufruf wird die Stringtiefe der aktuellen Position
um 1 erhöht.
Pro While-Durchlauf wird die Stringtiefe durch das
Beschreiten der Suffixlinks um 1 verringert.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
33
Laufzeitanalyse
While-schleife in update:
Pro update-Aufruf wird die Stringtiefe der aktuellen Position
um 1 erhöht.
Pro While-Durchlauf wird die Stringtiefe durch das
Beschreiten der Suffixlinks um 1 verringert.
Die Stringtiefe kann nicht unter 0 sinken.
Die Stringtiefe wird genau n mal erhöht, also kann sie auch
nur n mal um 1 verringert werden.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
33
Laufzeitanalyse
While-schleife in update:
Pro update-Aufruf wird die Stringtiefe der aktuellen Position
um 1 erhöht.
Pro While-Durchlauf wird die Stringtiefe durch das
Beschreiten der Suffixlinks um 1 verringert.
Die Stringtiefe kann nicht unter 0 sinken.
Die Stringtiefe wird genau n mal erhöht, also kann sie auch
nur n mal um 1 verringert werden.
Der Ukkonen-Algorithmus konstruiert einen Suffix-Tree also
in O(n).
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
33
Suffix-Array aus Suffix-Tree erstellen
Ein Suffix-Array pos gibt die Startpositionen der Suffixe in
lexikographischer Reihenfolge an.
Für T = babacbab$ : pos = [8, 6, 1, 3, 7, 5, 0, 2, 4].
Das Suffix-Array enthält dieselben Informationen wie die
Blätter eines Suffix-Trees.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
34
Suffix-Array aus Suffix-Tree erstellen
Ein Suffix-Array pos gibt die Startpositionen der Suffixe in
lexikographischer Reihenfolge an.
Für T = babacbab$ : pos = [8, 6, 1, 3, 7, 5, 0, 2, 4].
Das Suffix-Array enthält dieselben Informationen wie die
Blätter eines Suffix-Trees.
1
2
3
4
5
6
7
def get_suffixarray(node, pos = None):
if pos == None: pos = []
if len(node.targets):
for c in sorted(node.targets):
get_suffixarray(node.targets[c][0], pos)
else: pos += [node.pos]
return pos
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
34
Mustersuche im Suffix-Tree
Fragestellung: kommt P in T vor?
Für die Mustersuche ist wieder das Tupel (s, k, i) erforderlich:
Die Mustersuche startet mit (root, 0, 0):
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
35
Mustersuche im Suffix-Tree
Fragestellung: kommt P in T vor?
Für die Mustersuche ist wieder das Tupel (s, k, i) erforderlich:
Die Mustersuche startet mit (root, 0, 0):
Drei Möglichkeiten:
Wenn i = |P|: True zurückgeben.
Wenn i < |P| und k == i: Prüfen ob s eine ausgehende Kante
mit P[i] hat.
Wenn i < |P| und k < i: sei s1, b, e = s.targets[P[k]], prüfen
ob P[i] = T [i − k + b].
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
35
Mustersuche im Suffix-Tree
Fragestellung: kommt P in T vor?
Für die Mustersuche ist wieder das Tupel (s, k, i) erforderlich:
Die Mustersuche startet mit (root, 0, 0):
Drei Möglichkeiten:
Wenn i = |P|: True zurückgeben.
Wenn i < |P| und k == i: Prüfen ob s eine ausgehende Kante
mit P[i] hat.
Wenn i < |P| und k < i: sei s1, b, e = s.targets[P[k]], prüfen
ob P[i] = T [i − k + b].
Wenn Fall 2 oder 3 nicht zutrifft: False zurückgeben.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
35
Mustersuche im Suffix-Tree
Fragestellung: kommt P in T vor?
Für die Mustersuche ist wieder das Tupel (s, k, i) erforderlich:
Die Mustersuche startet mit (root, 0, 0):
Drei Möglichkeiten:
Wenn i = |P|: True zurückgeben.
Wenn i < |P| und k == i: Prüfen ob s eine ausgehende Kante
mit P[i] hat.
Wenn i < |P| und k < i: sei s1, b, e = s.targets[P[k]], prüfen
ob P[i] = T [i − k + b].
Wenn Fall 2 oder 3 nicht zutrifft: False zurückgeben.
Überprüfen ob nach gelesenem Zeichen im Tree ein Knoten
kommt und ggf. betreten:
wenn e − b ≤ i + 1 − k : s = s1, k = k + e − b.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
35
Mustersuche im Suffix-Tree
Fragestellung: kommt P in T vor?
Für die Mustersuche ist wieder das Tupel (s, k, i) erforderlich:
Die Mustersuche startet mit (root, 0, 0):
Drei Möglichkeiten:
Wenn i = |P|: True zurückgeben.
Wenn i < |P| und k == i: Prüfen ob s eine ausgehende Kante
mit P[i] hat.
Wenn i < |P| und k < i: sei s1, b, e = s.targets[P[k]], prüfen
ob P[i] = T [i − k + b].
Wenn Fall 2 oder 3 nicht zutrifft: False zurückgeben.
Überprüfen ob nach gelesenem Zeichen im Tree ein Knoten
kommt und ggf. betreten:
wenn e − b ≤ i + 1 − k : s = s1, k = k + e − b.
Suche mit i + 1 wiederholen. Laufzeit insgesamt: O(|P|).
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
35
Mustersuche im Suffix-Tree
Fragestellung: wo kommt P in T vor?
Patternsuche leicht modifizieren.
Wenn i = |P|: überprüfen, ob die aktuelle Position an einem
Knoten ist, wenn k < i : s = s.targets[P[k]][0].
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
36
Mustersuche im Suffix-Tree
Fragestellung: wo kommt P in T vor?
Patternsuche leicht modifizieren.
Wenn i = |P|: überprüfen, ob die aktuelle Position an einem
Knoten ist, wenn k < i : s = s.targets[P[k]][0].
Vom Knoten s alle Blätter besuchen und deren pos-Wert in
einer Liste zurückgeben.
Bei Mismatch leere Liste zurück geben.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
36
Mustersuche im Suffix-Tree
Fragestellung: wo kommt P in T vor?
Patternsuche leicht modifizieren.
Wenn i = |P|: überprüfen, ob die aktuelle Position an einem
Knoten ist, wenn k < i : s = s.targets[P[k]][0].
Vom Knoten s alle Blätter besuchen und deren pos-Wert in
einer Liste zurückgeben.
Bei Mismatch leere Liste zurück geben.
Sei z die Anzahl der Blätter, dann ist die
Gesamtlaufzeit O(|P| + z).
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
36
Mustersuche im Suffix-Tree
1
2
3
def search_pattern(s, T, P, k = 0):
for i, c in enumerate(P):
if k == i and c not in s.targets: return []
4
5
6
s1, b, e = s.targets[P[k]]
if k < i and c != T[i - k + b]: return []
7
8
9
if e - b <= i + 1 - k:
s, k = s1, k + e - b
10
11
12
if k < len(P): s = s.targets[P[k]][0]
return get_suffixarray(s)
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
37
Längster wiederholter Teilstring
Sei s ∗ := arg maxs∈nodes(S) {strdep(s) | s ist innerer Knoten}, dann
ist der längste wiederholte Teilstring (LRS) t = str(s ∗ ).
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
38
Längster wiederholter Teilstring
Sei s ∗ := arg maxs∈nodes(S) {strdep(s) | s ist innerer Knoten}, dann
ist der längste wiederholte Teilstring (LRS) t = str(s ∗ ).
Beispiel: T = ananas$
s$
]
:7
]
[1:3
a [0
:1]
[6
na
$
:7
]
5
[1:
3
na
4
7]
[5:
s$
nas$ [3:7]
s$ [5:7]
]
6
[5
1
3
7]
[5:
s$
nas$ [3:7]
2
0
LRS hier: ana
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
38
Kürzester eindeutiger Teilstring
Sei s ∗ := argmins∈nodes(S) {strdep(s) | s hat Blattkante e, |e| > 1},
dann ist der kürzeste eindeutige Teilstring (SUS) t = str(s ∗ ) ◦ e[0].
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
39
Kürzester eindeutiger Teilstring
Sei s ∗ := argmins∈nodes(S) {strdep(s) | s hat Blattkante e, |e| > 1},
dann ist der kürzeste eindeutige Teilstring (SUS) t = str(s ∗ ) ◦ e[0].
Beispiel: T = baabbaabb$
$
b
a
9
a
$
b
b
b
b
$
5
a
a
b
b
$
$
6
a
a
b
b
$
2
1
b
a
a
b
b
8
$
4
$
7
a
a
b
b
$
SUS hier: bba
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
a
a
b
b
$
3
0
39
Längster gemeinsamer Teilstring
Gegeben seien die Texte T1 und T2 .
Gesucht ist der längste gemeinsame Teilstring von T1 und T2 .
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
40
Längster gemeinsamer Teilstring
Gegeben seien die Texte T1 und T2 .
Gesucht ist der längste gemeinsame Teilstring von T1 und T2 .
Sei dementsprechend der verallgemeinerte Text
T = T1 $1 T2 $2 mit $1 < $2 .
Suffix-Tree auf T aufbauen
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
40
Längster gemeinsamer Teilstring
Gegeben seien die Texte T1 und T2 .
Gesucht ist der längste gemeinsame Teilstring von T1 und T2 .
Sei dementsprechend der verallgemeinerte Text
T = T1 $1 T2 $2 mit $1 < $2 .
Suffix-Tree auf T aufbauen
Alle Blätter mit pos-Wert < |T1 $1 | mit 1 beschriften.
Alle restlichen Blätter mit 2 beschriften.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
40
Längster gemeinsamer Teilstring
Innere Knoten bitweise mit den Labels seiner Kinder verodern. Sei
s ∗ := arg maxs∈nodes(S) {strdep(s) | s ist inn. Knoten, label(s) =
3}, dann ist der längste gemeinsame Teilstring (LCS) t = str(s ∗ ).
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
41
Längster gemeinsamer Teilstring
Innere Knoten bitweise mit den Labels seiner Kinder verodern. Sei
s ∗ := arg maxs∈nodes(S) {strdep(s) | s ist inn. Knoten, label(s) =
3}, dann ist der längste gemeinsame Teilstring (LCS) t = str(s ∗ ).
Beispiel: T = aaab$1 abcc$2
· · · $1
$2
3
a
1
$1
LCS hier: ab
·
·
·
·
01
$1
b
·
$1 b a
·
b
·
·
$1
3
a
· · ·
92
·
41
11
21
c
b
3
c
31
c
$2
3
2
c
c
$2
c
$2
82
$2
72
62
52
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
41
Zusammenfassung
Der Ukkonen-Algorithmus erstellt online einen Suffix-Tree
in O(n).
Verschiedene Fragestellungen können mit dem Suffix-Tree
beantwortet werden:
Kommt P in T vor? Wenn ja, wo?
Welcher ist der längste wiederholte Teilstring im Text T ?
Welcher ist der kürzeste eindeutige Teilstring im Text T ?
Welcher ist der längste gemeinsame Teilstring der beiden Texte
T1 und T2 ?
Leider hohe Konstante beim Speicherverbrauch, bei guten
Implementierungen ca. 20 Bytes pro Zeichen.
D. Kopczynski | Algorithmen auf Sequenzen | SoSe 2015 | Volltext-Indizes
42
Herunterladen