Chaînes de caractères (string) CSI2510 Structures de données et algorithmes Exemples de chaînes (ou séquences) de caractères: Programme Java HTML document séquence DNA Image numérique Un alphabet S est l’ensemble des caractères utilisés dans les mots d’un texte; Exemple d’ alphabets: Recherche des motifs ASCII Unicode {0, 1} {A, C, G, T} 1 Recherche de motif 2 CSI2510 - Motifs Recherche de motif : ‘Brute force’ Soit P une séquences de caractères de taille m Une sous- séquence P[i .. j] de P est composée par les caractères entre i et j Un préfixe de P est une sous- séquence de type P[0 .. i] Un suffixe de P est une sous- séquence de type P[i ..m - 1] L’algorithme de recherche de motif “brute force” compare le motif P avec le texte T pour chaque décalage de P relatif à T, jusqu’à ce que: Une correspondance est trouvée ou on a essayé toutes les possibilités Étant donné deux séquences T (texte) et P (motif), le problème de recherche du motif est de trouver une sousséquences de T égale à P a b a c a a c Applications: Éditeurs de texte Moteurs de recherche Recherche biologique c a CSI2510 - Motifs a 3 a c a a a b c a a c a a c a a c a CSI2510 - Motifs c a 4 1 Algorithme exhaustif Force brute Algorithme de Boyer-Moore Algorithm BruteForceMatch(T, P) Input text T of size n and pattern P of size m Output starting index of a substring of T equal to P or −1 if no such substring exists for i ← 0 to n − m { test shift i of the pattern } j←0 while ( j < m && T[i + j] = P[j]) j←j+1 if j = m return i {match at i} return -1 {no match anywhere} Alphabet de taille moyenne et motif long L’algorithme de recherche des motifs de Boyer-Moore est basé sur deux heuristiques: Heuristique Looking-glass: Comparer P avec une sous-séquence de T en commençant par la fin de P (jusqu’au premier caractère) Heuristique character-jump: Quand un “mismatch” arrive àT[i] = c (avec P[j]) Temps d’execution: O(nm) Exemples du pire cas: T = aaa … ah et P = aaah Il pourrait se présenter en images et en séquences ADN Rare dans les langues naturelles CSI2510 - Motifs 5 Algorithme de Boyer-Moore – Si P contient c, décaler P pour aligner la dernière occurrence (la plus à droite) de c en P avec T[i] – Si P ne contient pas c, décaler P complètement après T[i] CSI2510 - Motifs 6 Algorithme de Boyer-Moore Heuristique character-jump: Heuristique looking-glass: 4 3 2 1 a a x x b Si P contient c, décaler P pour aligner la dernière occurrence (la plus à droite) de c en P avec T[i] CSI2510 - Motifs 7 CSI2510 - Motifs 8 2 Algorithme de Boyer-Moore Algorithme de Boyer-Moore Heuristique character-jump: Heuristique character-jump: Si P contient c, shift P pour aligner la dernière occurrence (la plus à droite) de c en P avec T[i] Si P ne contient pas c, décaler P pour aligner P[0] avec T[i + 1] a a a x x b x x x b Si c est à la fin de P (parmi les caractères déjà vérifiés) se déplacer d’une seule unité (voir exemple plus tard) 9 CSI2510 - Motifs 10 CSI2510 - Motifs Algorithme de Boyer-Moore Algorithme de Boyer-Moore Heuristique character-jump : Si P ne contient pas c, décaler P pour aligner P[0] avec T[i + 1] T a p a t r 1 i t h m P x x x b CSI2510 - Motifs a 11 t e r n m a t c h i n g CSI2510 - Motifs a l g o r i t h m 12 3 Algorithme de Boyer-Moore Algorithme de Boyer-Moore T T a p a t P r t e r n m a t c h i n g a l g o r a i t h m p a t 2 i t h m t e r n P r Algorithme de Boyer-Moore a l g o r i t h m 3 i t h m 13 CSI2510 - Motifs m a t c h i n g 14 CSI2510 - Motifs Algorithme de Boyer-Moore T T a p a t t e r n m a t c h i n g P r a l g o r a i t h m p a t t e r n m a t c h i n g P 4 i t h m CSI2510 - Motifs r 15 CSI2510 - Motifs a l g o r i t h m 5 i t h m 16 4 Algorithme de Boyer-Moore Algorithme de Boyer-Moore T T a p a t t e r n m a t c h i n g a l g o r P a i t h m p a t t e r n m a t c h i n g a l g o r 6 i t h m r P i t h m r 7 i t h m 11 10 9 8 17 CSI2510 - Motifs Algorithme de Boyer-Moore Algorithm BMMatch(T, P) Input: Text T with n characters, pattern P with m characters Output: Starting index first substring of T matching P, or indication there is no match // last(c)=-1 si P ne contient pas c i←m−1 j←m−1 repeat if T[i] = P[j] if j = 0 return i {a match ! } else i←i−1 j←j−1 else {mismatch => a jump !} i ← i + m – min(j, 1 + last(T[i])) j←m−1 until i > n − 1 return “There is no match” 18 CSI2510 - Motifs Algorithme de Boyer-Moore . Cas 1: j ≤ 1 + l . . . . . a . i . . . . b a j l m −j . . . . a c a b a c j a b Cas 2: 1 + l ≤ j CSI2510 - Motifs . . . . . . a . l= last . . . a . i . . . . d c a b a c a a a b a a b b b 4 3 c a b 2 13 12 11 10 9 a b a c b a c a 5 a . a b a . b . j m − (1 + l ) a . a 1 b a . b a b a c a b a b a c 8 a b 7 a b 6 a b b . 1+l 19 CSI2510 - Motifs 20 5 Algorithme de Boyer-Moore: Complexité Algorithme de Boyer-Moore: Complexité Garder un tableau de taille |∑|(alphabet). Pour chaque entrée mémoriser la dernière occurrence en P de la lettre correspondante. Construire cette fonction a coûté O(m + |∑|) else 0 2 1 -1 a b c d {a jump !} last(T[i]) i ← i + m – min(j, 1 + last(T[i])) j←m−1 T a P f c a b c e r l m s a c a b b b m mm o r f f h k 1 a c b h m La partie de recherche: O(mn) au pire des cas comme brute-force O(m + |∑|) 21 CSI2510 - Motifs Algorithme de Boyer-Moore: Complexité Le temps d’exec. de l’algorithme Boyer-Moore est O(nm + |∑|) au pires des cas a a 6 5 4 3 2 1 b a a a a a Exemple du pire cas : a a 12 11 10 T = aaa … a P = baaa b Le pire de cas peut arriver dans les images et les séquences ADN; il est rare dans le texte; Boyer- Moore beaucoup plus vite que l’algorithme ‘brute force’ pour les textes CSI2510 - Motifs a a a a a 9 8 7 a a a a a a a a L’algorithme Knuth-Morris-Pratt compare le motif avec le texte de-gauche-a-droite, mais le décalage est choisi de façon plus intelligente que dans l’algorithme ‘brute force’ a Quand il y a un “mismatch” quel est le décalage maximal que l’on puisse faire pour éviter les comparaisons redondantes ? Réponse: Aligner le plus long préfixe de P[0..j] qui est un suffixe de P[1..j] a 24 23 22 21 20 19 b a a a a 22 Algorithme KMP 18 17 16 15 14 13 b CSI2510 - Motifs a 23 CSI2510 - Motifs 24 6 Algorithme KMP Algorithme KMP Le plus long préfixe de P[0..j] qui est un suffixe de P[1..j] a b a a b a . . a b a a b x . . . . . a b a a b a Ex: j=4 ---- > a b Ex: j=5 ---- > a b a a b a a b a Je dois trouver le préfixe (aussi long que possible) a b a a b a qui s’apparie avec un suffixe de la chaine en haut a b a a b a Ex: j=2 ---- > a mais ces deux chaines sont identiques! Ex: j=1 ---- > none 25 CSI2510 - Motifs Algorithme KMP Algorithme KMP Décalage tel que le préfixe coïncide avec le suffixe . . 26 CSI2510 - Motifs a b a a b x . . . . L’algorithme Knuth-Morris-Pratt calcule en avance les préfixes du motif qui coïncident avec ses suffixes . CSI2510 - Motifs j 0 1 2 3 4 P[j] a b a a b a F(j) 0 0 1 1 2 3 5 La “failure function” F(j) est définie comme la taille du plus long préfixe de P[0..j] qui est aussi un suffixe de P[1..j] a b a a b a Pas besoin de répéter ces comparaisons a b a a b a a b a a b a Recommencer à comparer ici j=2 ---- > 27 a a b a a b a j=3 ---- > a CSI2510 - Motifs a b a a b a j=4 ---- > a b a b a a b a j=5 ---- > aba 28 7 Algorithme KMP Algorithme KMP L’algorithme Knuth-Morris-Pratt modifie l’algorithme de ‘brute force’ de manière que si le “mismatch” arrive à (P[j] ≠ T[i]) on échange j par F(j - 1) et i (la position dans T) reste la même (ou si j =0, i est incrémentée de 1) . . j 0 1 2 3 4 P[j] a b a a b a F(j) 0 0 1 1 2 3 a b a a b x . . 5 . . . Donc, il n’y a pas plus que 2n itérations de la boucle while Donc, l’algorithme KMP a un temps optimal de O(m + n) a b a a b a F(j − 1) 29 CSI2510 - Motifs Algorithme KMP Algorithme KMP La “failure function” peut être représentée par un tableau qui peut être calculé en temps O(m) La construction est similaire à celle de l’algorithme KMP A chaque itération de la boucle i augmente de un, OU la quantité de décalage i - j augmente de au moins un (observez que F(j - 1) < j) Donc il n y a pas plus que 2m itérations de la boucle while i j Algorithm failureFunction(P) F[0] ← 0 i←1 j←0 while i < m if P[i] = P[j] {we have matched j + 1 chars} F[i] ← j + 1 i←i+1 j←j+1 else if j > 0 then {use failure function to shift P} j ← F[j − 1] else F[i] ← 0 { no match } i←i+1 CSI2510 - Motifs Algorithm KMPMatch(T, P) F ← failureFunction(P) i←0 j←0 while i < n if T[i] = P[j] if j = m − 1 return i − j { match } else i←i+1 j←j+1 else if j > 0 j ← F[j − 1] else i←i+1 return −1 { no match } i est incrémenté de un, OU La quantité de décalage i - j est incrémentée de au moins un (observez que F(j - 1) < j) a b a a b a j CSI2510 - Motifs La “failure function” peut être représentée par un tableau qui peut être calculé en un temps O(m) A chaque itération de la boucle while : 31 a b a a b a i 0 1 F(i) 0 0 2 3 4 5 30 Algorithm failureFunction(P) F[0] ← 0 i←1 j←0 while i < m if P[i] = P[j] {we have matched j + 1 chars} F[i] ← j + 1 i←i+1 j←j+1 else if j > 0 then {use failure function to shift P} j ← F[j − 1] else F[i] ← 0 { no match } i←i+1 CSI2510 - Motifs 32 8 Algorithme KMP i j a b a a b a i 0 1 2 F(i) 0 0 1 3 4 5 {on a ‘matché’ 1 car.} Algorithm failureFunction(P) F[0] ← 0 i←1 j←0 while i < m if P[i] = P[j] {we have matched j + 1 chars} F[i] ← j + 1 i←i+1 j←j+1 else if j > 0 then {use failure function to shift P} j ← F[j − 1] else F[i] ← 0 { no match } i←i+1 Algorithme KMP i j a b a a b a i 0 1 2 F(i) 0 0 1 3 4 5 Algorithm failureFunction(P) F[0] ← 0 i←1 j←0 while i < m if P[i] = P[j] {we have matched j + 1 chars} F[i] ← j + 1 i←i+1 j←j+1 else if j > 0 then {use failure function to shift P} j ← F[j − 1] else F[i] ← 0 { no match } i←i+1 Il n’y a pas de ‘match’ de 2 car… Il faut verifier s’il y a un ‘match’ avec 1 car. CSI2510 - Motifs Algorithme KMP j i a b a a b a i 0 1 2 F(i) 0 0 1 3 4 5 33 Algorithm failureFunction(P) F[0] ← 0 i←1 j←0 while i < m if P[i] = P[j] {we have matched j + 1 chars} F[i] ← j + 1 i←i+1 j←j+1 else if j > 0 then {use failure function to shift P} j ← F[j − 1] else F[i] ← 0 { no match } i←i+1 CSI2510 - Motifs 35 CSI2510 - Motifs Algorithme KMP j i a b a a b a i 0 1 2 3 F(i) 0 0 1 1 4 5 34 Algorithm failureFunction(P) F[0] ← 0 i←1 j←0 while i < m if P[i] = P[j] {we have matched j + 1 chars} F[i] ← j + 1 i←i+1 j←j+1 else if j > 0 then {use failure function to shift P} j ← F[j − 1] else F[i] ← 0 { no match } i←i+1 CSI2510 - Motifs 36 9 Algorithme KMP i j a b a a b a i 0 1 2 3 4 F(i) 0 0 1 1 2 5 Algorithm failureFunction(P) F[0] ← 0 i←1 j←0 while i < m if P[i] = P[j] {we have matched j + 1 chars} F[i] ← j + 1 i←i+1 j←j+1 else if j > 0 then {use failure function to shift P} j ← F[j − 1] else F[i] ← 0 { no match } i←i+1 On avait un ‘match’ de 1 car., maintenant de 2 ! i j a b a a b a i 0 1 2 3 4 5 F(i) 0 0 1 1 2 3 Algorithm failureFunction(P) F[0] ← 0 i←1 j←0 while i < m if P[i] = P[j] {we have matched j + 1 chars} F[i] ← j + 1 i←i+1 j←j+1 else if j > 0 then {use failure function to shift P} j ← F[j − 1] else F[i] ← 0 { no match } i←i+1 On avait un ‘match’ de 2 car., maintenant de 3 ! 37 CSI2510 - Motifs Algorithme KMP CSI2510 - Motifs 38 Exemple a b a c a a b a c c a b a c a b a a b b 1 2 3 4 5 6 a b a c a b 7 a b a c a b 8 9 10 11 12 a b a c a b 13 j 0 1 2 3 4 5 P[j] a b a c a b F(j) 0 0 1 0 1 2 a b a c a b 14 15 16 17 18 19 a b a c a b CSI2510 - Motifs 39 10