TU München Hauptseminar: WS 2002 / 2003 Einführung in Suffix - Bäume Bearbeiterin: Shasha Meng Betreuerin: Barbara König Inhalt 1. Einleitung 1.1 Motivation 1.2 Eine kurze Geschichte 2. Tries 2.1 Basisdefinition 2.2 Suffix-Tries 3. Suffix-Baum 3.1 Basisdefintion 3.2 Ein paar Definitionen 3.3 Ein naiver Algorithmus zur Konstruktion eines Suffix-Baumes 3.4 Suchen im Suffix-Baum 4. Generalisierter Suffix-Baum 4.1 Konstruktiom 4.2 Eine Anwendung von GSB – Längste gemeinsame Zeichenkette 1. Einleitung 1.1 Motivation Der Suffixbaum ist eine Datenstruktur und kann benutzt werden, um das exakt-matching-Problem in der linearen Zeit zu lösen.Aber der Hauptvorteil ist, dass sie viele String-Probleme in der linearen Zeit lösen können, die viel komplizierter als das exakt-matching-Problem sind. Suffixbäume können auch als eine Brücke zwischen exakt-matching-Problemen und inexakt-matching-Problemen angesehen. Die klassische Anwendung für Suffixbäume ist das exakt-matching-Problem. Ein Text T der Länge m und ein String S (Pattern) der Länge n sind gegeben.Man soll alles Auftreten vom String S in Text T finden. Der Suffixbaum für den Text T wird in der linearen Zeit O(m) in der Vorverarbeitungsphase hergestellt. Danach wenn ein String S der Länge n eingegeben wird,wird entweder in der linearen Zeit O(n) ein Auftreten von S in T gefunden oder es kann festgestellt werden, daß S nicht in T enthalten ist. Häufig ist der Text eine Menge von Strings und die Aufgabe ist festzustellen,ob S ein Teilstring von irgendeinem in dieser Stringmenge. Das ist sog. Teilstring-Problem. Mit Suffixbäumen kann dieses Problem auch sehr gut gelöst werden. 1.2 Eine kurze Geschichte Der erste Algorithmus für die Konstruktion der Suffixbäume in der linearen Zeit wurde von Weiner 1973 gegeben, obwohl er seinen Baum einen Positionsbaum nannte. Der andere Algorithmus für die Konstruktion, der wenige Speicherplätze in der Implementierung braucht, wurde von McCreight einige Jahre später gegeben.Vor kurzem entwickelte Ukkonen einen begrifflich anderen Algorithmus für Suffixbäume, der alle Vorteile vom Algorithmus von McCreight hat, aber erlaubt eine viel einfachere Erklärung. 2. Tries 2.1 Basisdefinition Um die Konstruktion von Suffix-Bäumen zu verstehen,betrachten wir zunächst eine verwandte Art von Bäumen,sog. Tries. Tries ( von engl. retrieval ) sind Suchbäume und repräsentieren eine Menge von M Schlüsseln. Ein Schlüssel wird als eine Zeichenkette über einem endlichen Alphabet ∑ aufgefasst. Jede Kante eines Tries T ist mit einem Zeichen aus ∑ beschriftet und benachbarte Kanten aus einem Knoten müssen mit verschiedenen Zeichen beschriftet werden. Damit ist der maximale Grad eines Knotens in T gleich |∑|.Ferner kann jedem einfachen Weg von der Wurzel zu einem Knoten v in T eine Zeichenkette durch Konkatenation der Beschriftungen der zu dem Weg gehörenden Kanten zugeordnet werden. Da ein einfacher Weg von der Wurzel zu einem Knoten v in T eindeutig bestimmt ist, repräsentiert jeder Knoten in T eine Zeichenkette.Diese Zuordnung ist eindeutig, da benachbarte Kanten von einem Knoten verschiedene Beschriftungen haben. Um zu testen,ob ein String S in M enthalten ist, stellt man fest,ob es einen Weg von der Wurzel r von T zu einem Blatt l gibt,dessen Beschriftung gleich S ist. 2.2 Suffix-Tries Suffix-Tries ( auch Position-Trees ) sind Tries, die alle Suffixe einer Zeichenkette S repräsentieren. Leider kann die Anzahl der inneren Knoten von Suffix-Tries bis zu O(n2) betragen. 3. Suffix-Baum 3.1 Basisdefinition Die Anzahl der Knoten eines Suffix-Tries kann man dadurch reduzieren, dass man alle Wege,die nur aus unären Knoten bestehen, zu einer Kante zusammenzieht. Damit erhält man einen Suffix-Baum. Definition: Sei S ein String der Länge m über einem endlichen Alphabet ∑. Ein Suffix-Baum für S ist ein gerichteter Baum mit m Blättern,die mit 1 bis m nummeriert sind und der Baum hat folgende Eigenschaften: 1) Innere Knoten (außer der Wurzel) haben min. 2 Söhne. 2) Kanten sind mit Teilzeichenketten aus String S beschriftet. 3) Die Beschriftungen der ausgehenden Kanten eines Knotens beginnen mit unterschiedlichen Zeichen. 4) Die Beschriftungen entlang des Pfades von der Wurzel zu Blatt i ergeben S [ i..m]. Der Platzbedarf ist O ( m ). Es gibt nach obiger Definition nicht für jeden String einen Suffix-Baum, nämlich dann nicht, wenn ein Suffix S1 ein Präfix eines anderen Suffixes S2 ist (z.B. S=xabxa).Das Suffix S4 ( xa ) ist ein Präfix von einem anderen Suffix S1 ( xabxa ). In diesem Fall gibt es keinen Pfad von der Wurzel zu einem Blatt mit der Beschriftung S4. Deswegen gibt es keinen Suffixbaum für diesen String S= xabxa. Mit diesem Problem kann man leicht umgehen, indem man an S ein Sonderzeichen $ anhängt, welches erzwingt, daß kein Suffix ein Präfix eines anderen Suffixes ist. 3.2 Ein paar Definitionen Definitionen: Die Beschriftung eines Pfades von der Wurzel zu einem inneren Knoten v ist die Konkatenation der Strings, welche den Pfad beschriften. Die Beschriftung eines Knotens ist die Beschriftung des Pfades von der Wurzel zu dem Knoten. Partieller Weg: Eine zusammenhängende,von der Wurzel beginnende Folge von Kanten. Weg: Ein partieller Weg,der bei einem Blatt endet. Ort einer Zeichenkette S: Der Knoten am Ende des mit S bezeichneten Weges (falls er existiert). Erweiterung einer Zeichenkette S: Jede Zeichenkette,die S als Präfix hat. Erweiterter Ort einer Zeichenkette S: Ort der kürzesten Erweiterung von S,deren Ort definiert ist. String-Tiefe eines Knotens ist die Anzahl der Buchstaben in seinem Label. Knoten-Tiefe eines Knotens ist die Anzahl der Knoten auf dem Pfad von der Wurzel zu dem Knoten. 3.3 Ein naiver Algorithmus zur Konstruktion eines Suffix-Baumes Das naive Verfahren zur Konstruktion des Suffix-Baumes verläuft so, dass beginnend mit dem leeren Baum T0 der Baum Ti+1 aus Ti dadurch entsteht,dass man in Ti das Suffix sufx+1 einfügt. sufx : an Position i beginnendes Suffix von S, also z. B. suf1 = S. Algorithmus: Suffix-Baum Eingabe: Eine Zeichenkette S der Länge m Ausgabe: Der Suffix-Baum T von S begin T0:=leerer Baum for i:=0 to n-1 do füge sufi+1 in Ti ein; end for end; headi = längstes Präfix von sufi,dessen erweiterter Ort in Ti-1 existiert. taili = sufi– headi Ti+1 kann aus Ti wie folgt konstruiert werden kann: 1. Man bestimme den erweiterten Ort von headi+1 in Ti und teile die letzte zu diesem Ort führende Kante in zwei neue Kanten auf durch Einfügen eines neuen Knotens. 2. Man schaffe ein neues Blatt als Ort für sufi+1. Die Zeitkomplexität von diesem Algorithmus ist O ( m2 ). 3.4 Suchen im Suffix-Baum Ein Sting P (Pattern) der Länge n und ein Text X der Länge m sind gegeben, und alles Auftreten von P in Text T soll gefunden werden. Zuerst wird ein Suffixbaum T für den Text X in der O(m) Zeit konstruiert.Dann sucht man einfach ab der Wurzel von T Zeichen für Zeichen nach P, bis die Suche entweder steckenbleibt ( dann ist P nicht in X enthalten) oder bis P erschöpft ist (dann ist P in X enthalten). Wir nehmen an, dass u der Knoten in T ist, bei dem P erschöpft ist und dieser Knoten u kann in der linearen Zeit O(n) gefunden werden. Falls u ein Blatt ist, kommt P genau einmal in X vor. Falls u ein innerer Knoten von T ist, dann kommt P mehrmals in X vor, und zwar an allen Positionen i, so dass leaf[i] ein Blatt im Unterbaum vom Knoten u ist. Alles Auftreten von P in X kann in der Zeit O(n+m )gefunden werden. Wenn nur ein einzelnes Auftreten von P benötigt wird und die Vorverarbeitung ein bisschen erweitert wird, dann kann die Suchzeit von O(n+k) auf O(n) reduziert werden. Man speichert an jedem inneren Knoten irgendeine Nummer von einem Blatt im Unterbaum des Knotens u. Diese können direkt nach der Konstruktion des Suffixbaums mittels einer einfachen Tiefensuche in der linearen Zeit O ( m ) berechnet werden. In der Suchphase gibt die Nummer im entsprechenden Knoten eine Anfangspostion von P in X. 4. Generalisierter Suffix-Baum 4.1 Konstruktion Ein generalisierter Suffix-Baum ist ein Suffix-Baum, der die Suffixe von einer Menge von Strings { S1, S2, ..... , Sk } repräsentieren. Es gibt zwei Verfahren zur Konstruktion eines generaliserten Suffix-Baumes für eine gegebene Menge von Strings. Verfahren 1 1) Erstelle einen Suffix-Baum für den String S1$1...Sk$k. ( $i ≠ $j ,i ≠j) 2) Jedes Blatt entspricht einem Suffix von einem String Si. 3) Jedes Blatt ist mit (String,Suffix) beschriftet. Ein Nachteil mit diesem Verfahren für die Konstruktion eines generalisierten Suffixbaums ist, daß der Baum keine echte Suffixe vom einzelnen String darstellt, sondern die Zeichenkette „ein Suffx von Sj+ Sj+1+...+Sk“ darstellt.Diese aus mehreren Strings zusammengesetzte Zeichenketten sind nicht im Allgemeinen vom Interesse.Deswegen wird im Beispiel (siehe Folien ) das Sonderzeichen &1 eingeführt, um alle unerwünschten zusammengesetzten Zeichenketten Sj+1+...+Sk zu entfernen. Verfahren 2: 1) Erstelle einen Suffix-Baum für S1. 2) Beginnend von der Wurzel des Baums match S2 gegen einen Pfad bis kein Match möglich ist. 3) Füge die restlichen Zeichen des Suffixes von S2 in Suffix-Baum hinzu. 4) und so weiter bis fertig 4.2 Eine Anwendung von GSB - Längste gemeinsame Zeichenkette Zwei Zeichenketten S1,S2 sind gegeben und die längste gemeinsame Zeichenkette ist die längste Zeichenkette, die sowohl in S1 als auch in S2 vorkommt. Verfahren: 1. Konstruiere einen generalisierten Suffixbaum für { S1, S2}. 2. Markiere das innere Knoten mit 1 (2),falls ein Blatt im Unterbaum dieses Knotens mit dem Suffix von Sting 1 (2) beschriftet ist. 3. Die Beschriftung von der Wurzel r bis zu einem Knoten, der mit 1 und 2 markiert ist und die größte Zeichentiefe hat, entspricht der längsten gemeinsamen Zeichenkette.