Referat zum Bau von Suffix Baeumen Autoren: Hanna Kraeusel Axel Block Magnus Brockschmidt Prozeduraler Algorithmus Konstruiere T1; for (i=1; i<m; i++) { /*Beginn von Phase i+1 */ Prozeduraler Algorithmus Konstruiere T1; for (i=1; i<m; i++) { /*Beginn von Phase i+1 */ for (j=1; j<=j+1;j++) { /*Beginn von der j-ten Erweiterung*/ Prozeduraler Algorithmus Konstruiere T1; for (i=1; i<m; i++) { /*Beginn von Phase i+1 */ for (j=1; j<=i+1;j++) { /*Beginn von der j-ten Erweiterung*/ Finde das Ende des Pfades mit Label S[j..i]; Falls noetig, erweitere den Pfad durch S[i+1]; } } Erweiterungsregeln 1. ß endet in einem Blatt. Dann füge [i+1] zum Kantenlabel hinzu. Erweiterungsregeln 1. 2. ß endet in einem Blatt. Dann füge [i+1] zum Kantenlabel hinzu. Es gibt keinen Pfad am Ende von ß, der mit S[i+1] weitergeht, aber mindestens ein anderer Pfad geht weiter. Dann füge eine neue Kante mit Label S[i+1] ein. Dazu muß ein neuer Knoten erzeugt werden, wenn ß mitten in einer Kante endet. Gib dem neuen Blatt Nummer j. Erweiterungsregeln 1. 2. 3. ß endet in einem Blatt. Dann füge [i+1] zum Kantenlabel hinzu. Es gibt keinen Pfad am Ende von ß, der mit S[i+1] weitergeht, aber mindestens ein anderer Pfad geht weiter. Dann füge eine neue Kante mit Label S[i+1] ein. Dazu muß ein neuer Knoten erzeugt werden, wenn ß mitten in einer Kante endet. Gib dem neuen Blatt Nummer j. Es gibt einen Pfad am Ende von ß, der mit S[i+1] weitergeht. In diesem Fall ist ßS[i+1] schon im Baum und wir tun nichts. Beispiel: Wir wollen den Suffix Baum des Strings abcabcabacdba erzeugen. Um den Baum zu bilden, muss in der Phase i der Baum Bi in den Baum Bi+1 umgewandelt werden. Wir beschreiben jede Phase und zeichnen den Baum immer, wenn die Phase beendet ist. Einfügen von a Gesamter String: a a Es ist nur a Einzufügen! (Regel 2) Einfügen von b Gesamter String: ab a b In der ersten Erweiterung fügen wir ein b an das vorhandene Blatt an. (Regel 1) Einfügen von b Gesamter String: ab a b b In der ersten Erweiterung fügen wir ein b an das vorhandene Blatt an. (Regel 1) Die zweite Erweiterung konstruiert einen neuen Ast mit der Bezeichnung b. (Regel 2) Einfügen von b Gesamter String: ab a b b In der ersten Erweiterung fügen wir ein b an das vorhandene Blatt an. (Regel 1) Die zweite Erweiterung konstruiert einen neuen Ast mit der Bezeichnung b. (Regel 2) Jetzt stehen alle Suffixe des Strings ab im Baum. Einfügen von c Gesamter String: abc a b c b c c In den ersten beiden Erweiterungen fügen wir ein c an die vorhandenen Blätter an. Die dritte Erweiterung konstruiert einen neuen Ast mit der Bezeichnung c. Jetzt sind alle Suffixe von abc im Baum enthalten. Einfügen von a Gesamter String: abca a b c a b c a c a In den ersten drei Erweiterungen fügen wir ein a an die vorhandenen Blätter an. Die vierte Erweiterung muss keinen neuen Ast kreieren, da a bereits Als Präfix von abca vorhanden ist. (Regel 3) Jetzt sind alle Suffixe von abca im Baum enthalten. Einfügen von b Gesamter String: abcab a b c a b b c a b c a b Diese Phase ist synchron zur vorherigen Phase. Einfügen von c Gesamter String: abcabc a b c a b c b c a b c c a b c Auch hier ist nichts anderes zu tun. Man erkennt, dass der Suffix Baum keine weiteren Äste hinzufügt, wenn die neuen Character nur Teilstrings des gesamten Strings bilden. Einfügen von a Gesamter String: abcabca a b c a b c a b c a b c a c a b c a Nur anhängen von a an die vorhandenen Äste nötig! Einfügen von b Gesamter String: abcabcab a b c a b c a b b c a b c a b c a b c a b Jetzt wird noch b an die vorhandenen Äste angefügt! Einfügen von a Gesamter String: abcabcaba a b c a b c a b a b c a b c a b a c a b c a b a Erweiterung 1 bis 3: Wie zuvor auch fuegen wir ein a an alle Aeste an. Einfügen von a Gesamter String: abcabcaba a b c a b c a b a a b c a b c a b a c a b c a b a Erweiterung 4: Jetzt muss der String abcaba gefunden werden. Von der Wurzel laufen wir abcab runter und fuegen ein a an. Einfügen von a Gesamter String: abcabcaba a b c a b c a b a a b c a b c a b a c a b c a b a Erweiterung 4: Jetzt muss der String abcaba gefunden werden. Von der Wurzel laufen wir abcab runter und fuegen ein a an. Einfügen von a Gesamter String: abcabcaba a b c a b c a b a a a b c a b c a b a a a c a b c a b a a Einfügen von c Gesamter String: abcabcabac a b c a b c a b a c a c a c b c c a b c a b a c a c a c c a b c a b a c a c Einfügen von d Gesamter String: abcabcabacd a b c a b c a b a c d a c d a c d c d b c a b c a b a c d a c d a c d c a b c a b a c d d d a c d Einfügen von b Gesamter String: abcabcabacdb a b c a b c a b a c d b a c d b a c d b c d b b c a b c a b a c d b a c d b a c d b c a b c a b a c d b d b a c d b d b Einfügen von a Gesamter String: abcabcabacdba a b c a b c a b a c d b a a c d b a c a d c b d a b a b c a b c a b a c d b a a c d b a a c d b a c a b c a b a c d b a a c d b a d b a d b a Definition von Suffix Links • Knoten v hat die Beschriftung x (wobei x ein einzelner Character sei). ist möglicherweise leer. Definition von Suffix Links • Knoten v hat die Beschriftung x (wobei x ein einzelner Character sei). ist möglicherweise leer. • Knoten s(v) hat die Beschriftung Definition von Suffix Links • Knoten v hat die Beschriftung x (wobei x ein einzelner Character sei). ist möglicherweise leer. • Knoten s(v) hat die Beschriftung • Jetzt heißt die Kante v s(v) ein Suffix-Link. Gibt es für jeden Knoten v ein Suffix Link zu s(v)? Beobachtung Wenn der Knoten v als neuer innerer Knoten während der Verarbeitung von Erweiterung j in Phase i durch den bisherigen Algorithmus eingesetzt wird, und wenn v die Markierung x trägt, dann gilt eine der beiden Aussagen: 1. 2. Der Weg mit Beschriftung endet in einem bereits vorhandenen inneren Knoten w = s(v). Ein neuer Knoten s(v) wird bei der Verarbeitung von Extension j+1 in Phase i angelegt und s(v) hat als Beschriftung. Beweis • Das Hinzufügen eines Knoten v kann nur in der Erweiterungsregel 2 passiert sein. • Dann gibt es, neben der Verbindung zum neuen Blatt, auch einen weiteren von v ausgehenden Weg, der den Buchstaben y als ersten besitzen möge. Es treten zwei Fälle auf Fall1:Der gegenwärtige Baum besitzt neben xy einen weiteren Weg von • • der Wurzel beginnend mit der Beschriftung xz, wobei z ein beliebiger String aus dem Suffix sei, und z y. Jetzt gibt es Suffixe mit den Präfixen xy und xz, also auch mit y und z. Deswegen besitzt der Baum einen Knoten s(v) mit der Beschriftung . Fall2: Der gegenwärtige Baum besitzt keinen weiteren Weg wie in Fall1, dann wird in der Verarbeitung von S(j+1..i) ein neuer innerer Knoten s(v) angelegt, der die Beschriftung hat, weil es Suffixe mit den Präfixen y und S(i+1) gibt. Lemma • Bei Ukkonens Algorithmus hat jeder implizite Suffix Baum für jeden neuen inneren Knoten einen Suffix Link nach dem Ende der nächsten Erweiterung. Beweis • Der Beweis dieses Lemmas ist induktiv. • Sie ist wahr für B1, weil B1 noch keine Knoten besitzt. • Da in der letzten Erweiterung einer Phase keine neuen Knoten eingefügt werden, denn in dieser Phase ist der zu behandelnde String nur ein einzelner Character, sind am Ende der Phase i alle Knoten mit Suffix Links belegt und zu Beginn der Phase i+1 gilt ebenfalls die Aussage. Single extension algorithm (SEA) Begin • Finde Knoten v über dem Ende von S[j-1..i]. Laufe eine Kante vom Ende von S[j-1..i] hoch. Sei nun y der String zwischen dem Ende von S[j-1..i] und v. Single extension algorithm (SEA) Begin • Finde Knoten v über dem Ende von S[j-1..i]. Laufe eine Kante vom Ende von S[j-1..i] hoch. Sei nun y der String zwischen dem Ende von S[j-1..i] und v. • Wenn v nicht die Wurzel ist, gehe den Suffix Link entlang nach s(v). Klettere den Baum herunter an dem Ast des Strings y. Wenn v die Wurzel ist, folge S[j..i] von der Wurzel. Single extension algorithm (SEA) Begin • Finde Knoten v über dem Ende von S[j-1..i]. Laufe eine Kante vom Ende von S[j-1..i] hoch. Sei nun y der String zwischen dem Ende von S[j-1..i] und v. • Wenn v nicht die Wurzel ist, gehe den Suffix Link entlang nach s(v). Klettere den Baum herunter an dem Ast des Strings y. Wenn v die Wurzel ist, folge S[j..i] von der Wurzel. • Sorge gemäss den Erweiterungsregeln dafür, dass der String S[j..i]S(i+1) im Baum enthalten ist. Single extension algorithm (SEA) Begin • Finde Knoten v über dem Ende von S[j-1..i]. Laufe eine Kante vom Ende von S[j-1..i] hoch. Sei nun y der String zwischen dem Ende von S[j-1..i] und v. • Wenn v nicht die Wurzel ist, gehe den Suffix Link entlang nach s(v). Klettere den Baum herunter an dem Ast des Strings y. Wenn v die Wurzel ist, folge S[j..i] von der Wurzel. • Sorge gemäss den Erweiterungsregeln dafür, dass der String S[j..i]S(i+1) im Baum enthalten ist. • Wenn in Erweiterung j-1 ( nach Erweiterungsregel 2) ein Knoten w erzeugt wurde, dann muss der String das Ende des Suffix Links s(w) sein. Erzeuge einen Link (w,s(w)) von w nach s(w). End. Beispiel: Wir wollen den Suffix Baum des Strings abcabcabacdb mit Hilfe von Suffixlinks erzeugen. Um den Baum zu bilden, muss in der Phase i der Baum Bi in den Baum Bi+1 umgewandelt werden. Einfügen von a Gesamter String: a Es ist nur a Einzufügen! a In den ersten Phasen sind die Suffix Links noch nicht wichtig, da noch keine Knoten vorhanden Sind. Einfügen von b Gesamter String: ab a b In der ersten Erweiterung fügen wir ein b an das vorhandene Blatt an. Einfügen von b Gesamter String: ab a b b In der ersten Erweiterung fügen wir ein b an das vorhandene Blatt an. Die zweite Erweiterung konstruiert einen neuen Ast mit der Bezeichnung b. Einfügen von b Gesamter String: ab a b b In der ersten Erweiterung fügen wir ein b an das vorhandene Blatt an. Die zweite Erweiterung konstruiert einen neuen Ast mit der Bezeichnung b. Jetzt stehen alle Suffixe des Strings ab im Baum. Einfügen von c Gesamter String: abc a b c b c c In den ersten beiden Erweiterungen fügen wir ein c an die vorhandenen Blätter an. Die dritte Erweiterung konstruiert einen neuen Ast mit der Bezeichnung c. Jetzt sind alle Suffixe von abc im Baum enthalten. Einfügen von a Gesamter String: abca a b c a b c a c a In den ersten drei Erweiterungen fügen wir ein a an die vorhandenen Blätter an. Die vierte Erweiterung muss keinen neuen Ast kreieren, da a bereits Als Präfix von abca vorhanden ist. Jetzt sind alle Suffixe von abca im Baum enthalten. Einfügen von b Gesamter String: abcab a b c a b b c a b c a b Diese Phase ist synchron zur vorherigen Phase. Einfügen von c Gesamter String: abcabc a b c a b c b c a b c c a b c Auch hier ist nichts anderes zu tun. Man erkennt, dass der Suffix Baum keine weiteren Äste hinzufügt, wenn die neuen Character nur Teilstrings des gesamten Strings bilden. Einfügen von a Gesamter String: abcabca a b c a b c a b c a b c a c a b c a Nur anhängen von a an die vorhandenen Äste nötig! Einfügen von b Gesamter String: abcabcab a b c a b c a b b c a b c a b c a b c a b Jetzt wird noch b an die vorhandenen Äste angefügt! Einfügen von a Gesamter String: abcabcaba a b c a b c a b a b c a b c a b a c a b c a b a In dieser Phase kommen die Suffix Links erst richtig ins Spiel. Erweiterung 1 bis 3: Wie zuvor auch fuegen wir ein a an alle Aeste an. Einfügen von a Gesamter String: abcabcaba a b c a b c a b a a b c a b c a b a c a b c a b a Diese Erweiterung erzeugt einen Knoten, der noch keinen Suffix Link hat, aber wir wissen, dass dieser in der naechsten Erweiterung hinzugefuegt wird. Erweiterung 4: Jetzt muss der String abcaba eingefuegt werden. Von der Wurzel laufen wir abcab runter und fuegen ein a an. Einfügen von a Gesamter String: abcabcaba a b c a b c a b a a b c a b c a b a a c a b c a b a Diese Erweiterung erzeugt einen Suffix Link. Der neue Knoten ist allerdings noch nicht weiterverlinkt, was wieder in der naechsten Erweiterung passieren wird. Erweiterung 5: Jetzt muss der String bcaba eingefuegt werden. Von der Wurzel laufen wir bcab runter und fuegen ein a an. Einfügen von a Gesamter String: abcabcaba a b c a b c a b a a b c a b c a b a a c a b c a b a Diese Erweiterung erzeugt wie zuvor einen Suffix Link. a Erweiterung 6: Jetzt muss der String caba eingefuegt werden. Von der Wurzel laufen wir cab runter und fuegen ein a an. Einfügen von a Gesamter String: abcabcaba a b c a b c a b a a a b c a b c a b a a c a b c a b a Diese Erweiterung erzeugt wie zuvor einen Suffix Link. a Erweiterung 7: Jetzt muss der String aba eingefuegt werden. Von der Wurzel laufen wir ab runter und fuegen ein a an. Einfügen von a Gesamter String: abcabcaba a b c a b c a b a a a b c a b c a b a a a c a b c a b a Diese Erweiterung erzeugt wie zuvor einen Suffix Link. a Der Suffix Link des neuen Knotens fuehrt zur Wurzel, da b nur noch ein einzelner Character ist und α ist in diesem Fall ein leerer String. Erweiterung 8: Jetzt muss der String ba eingefuegt werden. Von der Wurzel laufen wir b runter und fuegen ein a an. Einfügen von a Gesamter String: abcabcaba a b c a b c a b a a a b c a b c a b a a a c a b c a b a a Erweiterung 9: Jetzt muss lediglich noch der Character a eingefuegt werden. Dieser ist allerdings schon vorhanden. Einfügen von a Gesamter String: abcabcaba a b c a b c a b a a a b c a b c a b a a a c a b c a b a a Unser Baum ist jetzt vollstaendig verlinkt und die Phase ist beendet. Einfügen von c Gesamter String: abcabcabac Wir wissen, dass abcabcaba der laengste String im Baum ist. Wir laufen diesen runter und fuegen dort ein c an. a b c b c a a c a a b a b c a b c a a c a a b a b a b a a c Erweiterung 1: Die erste Erweiterung ist immer speziell. Wir muessen den String abcabcabac einfuegen. Einfügen von c Gesamter String: abcabcabac Wir wissen, dass der erste Knoten ueber dem laengsten String im Baum ein Suffix link hat. Wir laufen vom laengsten Blatt hoch bis zum besagten Suffix Link. Von da gehen wir a die gleiche Bezeichnug wieder runter und fuegen dort ein c an. a b c b c a a c a a b a b c b c a a c a a b a b a b a a c c Erweiterung 2:Wir muessen den String bcabcabac einfuegen. Wir nutzen den Suffix Link. Einfügen von c Gesamter String: abcabcabac Wir laufen von der Position, wo wir in Erweiterung 2 das c eingefuegt haben, hoch bis zu dem Suffix link. Von da gehen wir die gleiche Bezeichnug wieder runter, die a wir hochgegangen sind, und fuegen dort ein c an. a b c b c a a c a a b a b c b c a a c a a b a b a b a c a c c Erweiterung 3:Wir muessen den String cabcabac einfuegen. Wir nutzen wieder den Suffix Link. Einfügen von c Gesamter String: abcabcabac Wir laufen von der Position, wo wir in Erweiterung 3 das c eingefuegt haben, hoch bis zu dem Suffix link. Von da gehen wir die gleiche Bezeichnug wieder runter, die a wir hochgegangen sind, und fuegen dort ein c an. a b c b c a a c a a b a b c b c a a c a a b a c b a b a c a c c Erweiterung 4:Wir muessen den String abcabac einfuegen. Wir nutzen den zustaendigen Suffix Link. Einfügen von c Gesamter String: abcabcabac Wir laufen von der Position, wo wir in Erweiterung 4 das c eingefuegt haben, hoch bis zu dem ersten Suffix link. Von da gehen wir das a runter, das wir auch hochgegangen a sind, und fuegen dort ein c an. a b c b c a a c a a b a b c b c a a c a a c b a c b a b a c a c c Erweiterung 5: Wir muessen den String bcabac einfuegen. Jetzt nehmen wir den ersten Suffix Link. Einfügen von c Gesamter String: abcabcabac Wir laufen von der Position, wo wir in Erweiterung 5 das c eingefuegt haben, hoch bis zu dem ersten Suffix link. Von da gehen wir das a runter, das wir auch hochgegangen a sind, und fuegen c dort ein c an. a b c b c a a c a a b a b c b c a a c a a c b a c b a b a c a c c Erweiterung 6: Wir muessen den String cabac einfuegen. Dies passiert wie in Erweiterung 5. Einfügen von c Gesamter String: abcabcabac Wir laufen von der Position, wo wir in der vorherigen Erweiterung das c eingefuegt haben, hoch bis zu dem ersten Suffix link. Von da gehen wir das a runter, a das wir c auch hochgegangen sind, und fuegen dort ein c an. a b c b c a a c a a c b a c b c b c a a c a a c b a c b a b a c a c c Erweiterung 7 und 8: Wir muessen den String abac und bac einfuegen. Diese Vorgaenge sind ebenfalls wie in Erweiterung 5. Einfügen von c Gesamter String: abcabcabac Wir laufen von der Position, wo wir in der vorherigen Erweiterung das c eingefuegt haben, hoch bis zu dem ersten Suffix link, hier die Wurzel. Von da gehen wir das a runter, a das wir c auch hochgegangen sind, und fuegen dort einen neuen Ast fuer das c an. Es entsteht ein neuer Suffix Link zur Wurzel. a b c b c c a a c a a c b a c b c b c a a c a a c b a c b a b a c a c c Erweiterung 9: Wir muessen den String ac einfuegen. Einfügen von c Gesamter String: abcabcabac a b c b c c a a c a a c b a c b c a b c a a c c a a c b a c b a b a c a c c Erweiterung 10: Wir muessen den String c einfuegen. Dieser existiert allerdings bereits als Praefix im Baum. Einfügen von c Gesamter String: abcabcabac a b c b c c a a c a a c b a c b c a b c a a c c a a c b a c b a b a c a c c Phase ist beendet und der Baum ist vollstaendig verlinket. Einfügen von d Gesamter String: abcabcabacd a b c a b c a b a c d c a c a c b c a b c a b a c a c a c c a b c a b a c Der gesuchte String ist der Laengste. Wir fuegen d ein und merken uns die Position. a c Erweiterung 1: abcabcabacd muss eingefuegt werden. Es geht ebenso wie in der Phase zuvor! Einfügen von d Gesamter String: abcabcabacd a b c a b c a b a c d Von der gemerkten Position gehen wir bis zum Suffix Link hoch, diesen entlang und an der Stelle die gleiche Bezeichnung wieder herunter! b c c c a a a a c b c b c a c a a c a a c b c b a a c c d Erweiterung 2: bcabcabacd muss eingefuegt werden. Es geht ebenso wie in der Phase zuvor! Einfügen von d Gesamter String: abcabcabacd a b c a b c a b a c d Von der gemerkten Position gehen wir jeweils bis zum Suffix Link hoch, diesen entlang und an der Stelle die gleiche Bezeichnung herunter! a wieder Wir nutzen fuer c diese drei Schritte die markierten Links und fuegen die gelben d’s ein. b c c c a a a a c b c b c c a a a a c b c b d a d a c c d d Erweiterung 3-5: cabcabacd, abcabacd, bcabacd mussen eingefuegt werden. Einfügen von d Gesamter String: abcabcabacd a b c a b c a b a c d Von der gemerkten Position gehen wir jeweils bis zum Suffix Link hoch, diesen entlang und an der Stelle die gleiche Bezeichnung herunter! a wieder Wir nutzen fuer c diese drei Schritte markierten Links d die und fuegen die gelben d’s ein. b c c c a a a d a c b c b d c d c a a a a c b c b d a d a c c d d Erweiterung 6-9: cabacd, abacd, bacd, acd mussen eingefuegt werden. Einfügen von d Gesamter String: abcabcabacd a b c a b c a b a c d c a d c d a c d b c a b c a b a c d a c d a c d c a b c a b a c d d a c d Jetzt gehen wir ueber den Suffixlink zur Wurzel, laufen ein c wieder runter, weil wir das auch hochgelaufen sind, und fuegen einen neuen Ast fuer das d ein. Es entsteht ein neuer Suffix Link zur Wurzel. Erweiterung 9: cd muss eingefuegt werden. Einfügen von d Gesamter String: abcabcabacd a b c a b c a b a c d c a d c d a c d b c a b c a b a c d a c d a c d c a b c a b a c d d d a c d Jetzt gehen wir ueber Den neuen Suffixlink zur Wurzel, laufen ein c wieder runter, weil wir das auch hochgelaufen sind, und fuegen einen neuen Ast fuer das d ein. Erweiterung 11:d muss eingefuegt werden. Einfügen von d Gesamter String: abcabcabacd a b c a b c a b a c d c a d c d a c d b c a b c a b a c d a c d a c d c a b c a b a c d d d a c d Die Phase ist beendet und der Baum vollstaendig verlinkt. Einfügen von b Gesamter String: abcabcabacdb a b c a b c a b a c d b b c c c a a d a d a c b b c b b d c a d c a b a c a b a c b d c b d a b d a b c b c d d b b Nach der letzten Phase erhalten wir diesen Baum. d b Trick Nr. 1 Skip/Count Trick Sinn: In Phase zwei vom Knoten s(v) dem Label y folgen erfordert eine Zeit t ~ Laenge von y |y|. Der Skip/Count Trick reduziert t auf t ~ Anzahl der Knoten in y. Wir befinden uns an einem Knoten v, und das nun zu erweiternde Suffix hat ein Praefix, welches auf abcdefgh endet. Trick 1 • • • Der Trick ist sehr simpel: Wenn am Knoten s(v) angekommen, suche den Weg aus dem Knoten, welcher mit dem Anfangsbuchstaben von y beginnt. Wenn y länger ist als der String an dieser Kante bis zum nächsten Knoten, so springe zum nächsten Knoten. Setze einen Index auf den |String| + 1. Nun schaue, welche Kante aus diesem Knoten mit dem |String| + 1 Buchstaben aus y beginnt und springe zum nächsten Knoten usw. Dieses "Springen" endet, wenn der String an der folgenden Kante länger oder gleich der Länge von y ist. Dann ist nämlich das Ende von y erreicht und nun wird die entsprechende Extension Rule angewendet. Also: Man guckt einfach nach dem Weg, zählt und springt einen Knoten weiter oder zum Ende. Aber was ist mit dem Worst Case? Dem Suffix Link von v nach s(v) folgen, dann soll es den String y = abcdefgh heruntergehen, um an dessen Ende ein Zeichen anzuhaengen. Der naïve Algorithmus wuerde Zeichen fuer Zeichen ablaufen. G ist hier die Laenge des restlichen abzulaufenden Teils von y, I der Index des naechsten Zeichens. v Suffix Link S(v) a b c d String y e G = |y| = 8, f I = 1, g h i j Wir suchen den Buchstaben an diesem Knoten, mit dem y beginnt, also a, gucken, ob an dieser Kante mehr Buchstaben stehen als y lang ist, hier abcd, also kuerzer, somit springen wir zum naechsten Knoten. Wenn y kuerzer ist als der String an dieser Kante, waere das Ende von y erreicht, und wir koennten anfuegen. x v Suffix Link S(v) a b Aktuelle Position z g c d String y e G = |y| = 8, f I = 1, g h i j Nun springen wir direkt zu diesem Knoten Nun sind wir an dem Knoten. Wir haben 4 Zeichen uebersprungen, also wird G auf G-4 gesetzt und I auf 1+4. Dann gehts weiter, nach der Kante mit dem 5ten Zeichen von y suchen und zum naechsten Knoten springen. x v Suffix Link S(v) a b z g c d Aktuelle Position String y e G = G-4 = 4, f I = I+4 = 5, g h i j Nun springen wir weiter zu diesem Knoten Die Laenge des Strings an der naechsten Kante, die mit dem 7ten Zeichen von y beginnt ist groesser als die Laenge des Restes von y. Das Ende von y liegt also an dieser Kante. x v Suffix Link S(v) a b z g c d String y e G = G-2 = 2, f I = I+2 = 7 g h Aktuelle Position. i j Ende von y Wir haben nun das Ende von y gefunden und koennen das Zeichen, z.B. ein w einfuegen. x v Suffix Link S(v) a b z g c d String y e f g h i j Hier findet sich das Ende von y, und das Zeichen kann eingefuegt werden. W eingefuegt, es geht weiter mit der naechsten Extension. x v Suffix Link S(v) a b z g c d String y e f g h i j w Hier findet sich nun ein neuer Knoten und ein Ast mit Label w. Definition Die Tiefe (Knotentiefe) eines Knotens ist die Anzahl der Knoten auf dem Pfad von der Wurzel bis zu diesem Knoten. Lemma Es sei (v, s(v)) irgendein Suffix Link. Dann ist die Knotentiefe von v hoechstens um 1 groesser als die von s(v). Beweis • • • • • • Jeder interne Vorfahr von v mit Label xbeta hat einen Link zu einem Knoten mit Label beta. xbeta ist ein Präfix des Pfades zu v, so ist beta ein Präfix des Pfades zu s(v) --> Jeder Link von einem internen Vorfahr von v geht zu einem internen Vorfahr von s(v). Und wenn beta nicht leer ist, so ist der Knoten mit dem Label beta ein interner Knoten. Da die Tiefen zweier Vorfahren von v verschieden sein muessen, hat jeder Vorfahr von v einen Link zu einem anderen Vorfahren von s(v). -->Die Tiefe von s(v) ist mindestens 1 (Wurzel) + die Anzahl interner Vorfahren von v mit längerer Bezeichnung als einem Zeichen. Den einzigen Vorfahren ohne Gegenstück, den v haben kann, ist der mit nur einem Zeichen, und nur dann ist die Tiefe von v auch nur 1 groesser als die von s(v). Ausschnitt aus dem Suffixbaum fuer den String ALDACFALBALDACTALDACFALBN, ohne Links. L D A C F A L B A L D A C T A L D A C F A L B N N A D A C F A L B A L D A C T D A C F A L D A C N C F A L B A L D A C T A L A L B N N L D A C F A L B A L N D A C T A L D A C F A L B N F A L B N Bei diesen Links ist die Tiefe von v um 1 groesser als die Tiefe von s(v). S(v) L D S(v) A S(v) C F A L B A L D A C T A L D A C F A L B N N A D A C F A L B A L D A C T D A C F A L D A C N C F A L B A L D A C T A L A L B N N L v D A C F A v L B A L v N D A C T A L D A C F A L B N F A L B N Bei diesen Links ist die Tiefe von v um 1 kleiner als die Tiefe von s(v). L D A C F A L B A L D A C T A L D A C F A L B N N A D A C F A L v C F A L S(v) B A L D B A v A C T L D A C T D A C F A L D A C N A L A L B N S(v) N L D A C F A L B A L N D A C T A L D A C F A L B N F A L B N Definition • Die aktuelle Knotentiefe ist die des zuletzt besuchten Knotens. Behauptung Mit diesem Trick dauert jede Phase des Algorithmus O(m). Beweis • • Es gibt höchstens m Extensions in einer Phase. In einer davon es geht höchstens einen Knoten hoch zum nächsten Link, den Link entlang, die Knoten herunter und die Regeln ausführen, evtl auch Link setzen. Wir wissen, daß alles ausser dem Knoten abwärts gehen konstante Zeit benoetigt. Dieses untersuchen wir anhand der Tiefeveränderung in einer Phase. Einen hoch, der Suffix Link erhöht höchstens weiter um einen, es geht also höchstens zwei rauf, also insgesamt höchstens 2m rauf. Da der Baum aber höchstens m Knoten haben kann, geht es auf die Phase gesehen höchstens 3m herunter. Es gibt also höchstens 3m downwalks, --> O(m) Corollar Es gibt m Phasen mit O(m), also insgesamt O(m*m). Das ist sehr grob gerechnet und sieht schlecht aus, aber mit ein paar kleinen weiteren Details erreichen wir O(m). Ersetzen der Zeichen durch Indices Durch die Zeichen an den Kanten nimmt der Baum sehr viel Platz weg. Diese werden nun durch Indices ersetzt, die Anfang und Ende des Teilstrings im Gesamtstring markieren. Der Auschnitt aus dem Baum, dieses mal mit Indices. A L D A C F A L B A L D A C T A L D A C F A L B N 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 2-2 3-5 6 - 10 11 - 25 25 - 25 6 - 10 1 1 11 - 25 - 25 3-3 2 2 6 - 10 11 - 25 25 - 25 3-5 6 - 10 11 25 - 25 - 25 25 Single Phase Algorithm (SPA) 1. Setze e auf i+1. 2. Führe mit Hilfe vonSuffix-Links Erweiterungen durch, bis in Erweiterung j* Regel 3 angewandt wird. 3. Setze ji+1 auf j*-1 und gehe zur nächsten Phase.