Chaines de caractères 1. Type abstrait 1. Type abstrait Définition indépendante de la représentation en mémoire. Introduction à la spécification algébrique des types Opérations de comparaison On définit une liste d opérations sur les objets de ce type 2. Algorithmes de recherche de sous-chaînes 3. Implémentation Opérations concaténation élément à la position i sous-chaine de a à b modifier l élément à la position i insérer/retirer à la position i modifier l élément à la position i comparaisons 1 de 43 2 de 43 Spécification algébrique d un type de données Opérations de chaine Une technique de spécification formelle d un type de données Constructeurs --> chaine -- chaine vide Liste des opérations ajout(caractère, chaine) --> chaine constructeurs : produisent un objet de ce type concat(chaine, chaine) --> chaine sélecteurs : donnent une propriété d un objet de ce type Sélecteurs Profil des opérations car_à (entier, chaine ) --> caractère types des paramètres longueur(chaine) --> entier type du résultat sous_chaine(entier, entier, chaine) --> chaine Axiomes définition de la sémantique des opérations Expression logique => Equivalence 3 de 43 4 de 43
Axiomes S : chaine T : chaine C : caractère I : entier longueur(vide) == 0 longueur(ajout(c, S)) == longueur(s) + 1 Axiomes (suite) I = 1 => car_à(i, ajout(c, S)) == C I > 1 => car_à(i, ajout(c, S)) == car_à(i 1, S) longueur(concat(s, T)) == longueur(s) + longueur(t) I longueur(s) => car_à(i, concat(s, T)) == car_à(i, S) I > longueur(s) => car_à(i, concat(s, T)) == car_à(i longueur(s), T) 5 de 43 6 de 43 Utilisation des axiomes Utilisation des axiomes (suite) Calculer la longueur d une chaine longeur(ajout( b, ajout( o, ajout( n, )))) Quel est le deuxième caractère de "bon"? longueur(ajout(c, S)) == longueur(s) + 1 car_à(2, ajout( b, ajout( o, ajout( n, )))) == longeur(ajout( o, ajout( n, ))) + 1 I > 1 => car_à(i, ajout(c, S)) == car_à(i 1, S) == longeur(ajout( n, )) + 1 + 1 == car_à(1, ajout( o, ajout( n, ))) == longueur( ) + 1 + 1 + 1 I = 1 => car_à(i, ajout(c, S)) == C longueur(vide) == 0 == 0 + 1 + 1 + 1 == o 7 de 43 8 de 43
Transformer concat en ajout Définition des comparaisons de chaines Axiomes Opération d égalité stricte concat(ajout(c, S), T) == ajout(c, concat(s, T)) = : chaine, chaine --> booléen concat(vide, S) == S concat(s, vide) == S Axiomes de l égalité stricte = == vrai longueur(s) longueur(t) => S = T == faux Utilisation: "bon"+"jo" C1 = C2 => ajout(c1, S) = ajout(c2, T) == S = T concat(ajout( b, ajout( o, ajout( n, ))), ajout( j, ajout( o, ))) C1 C2 => ajout(c1, S) = ajout(c2, T) == faux == ajout( b, concat(ajout( o, ajout( n, )), ajout( j, ajout( o, )))) == ajout( b, ajout( o, concat(ajout( n, ), ajout( j, ajout( o, ))))) Donc == ajout( b, ajout( o, ajout( n, concat(, ajout( j, ajout( o, )))))) "swing " = "swing" == faux == ajout( b, ajout( o, ajout( n, ajout( j, ajout( o, ))))) "swing" = "swing" == vrai "swing" = "Swing" == faux On peut désormais considérer que les chaines ne sont faites que de ajout "mel" = "mél" == faux 9 de 43 10 de 43 Egalité par degré Comparaison lexicographique On suppose qu il existe des degrés d égalité sur les caractères Il doit exister un ordre ( ) sur les caractères (avec des degrés) = 0 : égalité stricte Axiomes = 1 : des car. différents selon = 0 sont considérés égaux vide S == vr ai "e" = 1 "é" ==> "fréquence" = "frequence" C1 < C2 => ajout(c1, S) ajout(c2, T) == vr ai = 2 : encore plus large C1 = C2 => ajout(c1, S1) ajout(c2, S2) == S1 S2 "e" = 2 "E" ==> "Fréquence" = "frequence" C1 > C2 => ajout(c1, S) ajout(c2, T) == faux etc. Dépend de la langue! (voir: classe java.text.collator) Donc "Zot" "aot" (si "Z" "a") Mêmes axiomes que l égalité stricte mais en remplaçant = par = D "truc" "truc " (mais pas l inverse) "1205" "205" 11 de 43 12 de 43
2. Algorithmes de recherche d une sous-chaîne Recherche directe Problème Chercher si x apparaît dans y On a une chaîne y de taille n. On suppose que les chaînes sont stockées dans des tableaux On cherche une occurence de x (de taille m n) dans y x : tableau de m caractères y : tableau de n caractères Algorithmes Recherche directe Algorithme Automate à états Karp-Rabin (Hachage ) Boyer Moore et beaucoup d autres : http://www-igm.univ-mlv.fr/~lecroq/string tester si x se trouve au début de y : x[0.. m 1] = y[0.. m-1] tester à partir de la position 1 de y : x[0.. m 1] = y[1.. m] tester à partir de la position 2 de y : x[0.. m 1] = y[2.. m+1] tester à partir de la position k de y : x[0.. m 1] = y[k.. k+m 1] 13 de 43 14 de 43 Algorithme Automate à états i := 0; position = -1; pour i := 0 jusqu àn m { j := 0; tant quej < m et ensuite x[j] = y[i+j] { --- ici on sait que x[0.. j] = y[i.. i+j] j := j+1 } si j = m { position = i sortir} ; --- ici on sait que x[0.. m 1] y[u.. u+m 1] --- pour tous les u entre 0 et i } --- si position = -1 on est sûr que x[0.. m 1] y[u.. u+m 1] --- pour tous les u entre 0 et n m, --- donc que x ne se trouve pas dans y. Technique : 1. construire un automate à états qui reconnaît la chaîne cherchée. 2. donner la chaîne à examiner comme entrée de l automate 3. simuler le fonctionnemet de l automate Complexité : O(n x m) 15 de 43 16 de 43
Exemple : chercher "boboa" Construction de l automate Automate : ε pas b b boboa a b b b ni o ni b pas b ni a ni b bobo b o o bo b bob b Chaque état de l automate correspond à un préfixe de la chaîne x à chercher ε, x[0], x[0..1], x[0..2], Il y a une transition q a > qa si qa est un préfixe de x sinon il y a une transition q a > p où p est le plus long suffixe de qa qui est un préfixe de x 17 de 43 18 de 43 Représentation de l automate Une transition q a > r est représentée par A [ nq ] [ na ] = nr nq : numéro d ordre du préfixe q na : code (entier) du caractère a nr : numéro d ordre du préfixe r A [ j ] [ k ] contient l état dans lequel il faut aller quand on rencontre k dans l état j. Exemple A 0: a 1: b... 14: o... 0 : ε 0 1 0 0 0 1 : b 0 1 0 2 0 2 : bo 0 3 0 0 0 3 : bob 0 1 0 4 0 4 : bobo 5 3 0 0 0 5 : boboa 0 1 0 0 0 Exécution de l automate etat 0 ; pour j de 1 à n { etat A[ etat ][ y[j] ]; si etat = FINAL retourner j taille(x) + 1 // début } retourner 1 19 de 43 20 de 43
Karp-Rabin (Hachage) Algorithme Pour accélérer la recherche on teste une signature de la chaîne Si h est une fonction Chaînes --> Entiers Si x = y[j j+m 1] alors h(x) = h(y[j j+m 1]) calculer une fois pour toutes hx = h(x) pour j de 0 à n m + 1 { calculer hy = h(y[j j+m 1]) si hy = hx tester l égalité entre x et y[j j+m 1] } Donc si h(x) h(y[j j+m 1]) alors x y[j j+m 1]. Effectivement plus rapide si le calcul de hy est plus rapide que la comparaison Et si la fonction h est non triviale. 21 de 43 22 de 43 Karp-Rabin (suite) Boyer Moore Astuce : calculer h(y[j+1 j+m]) à partir de h(y[j j+m 1]) On prend comme fonction h h(y[0 m 1] = (y[0]2 m 1 + + y[m 1]2 0 ) mod q (pour q assez grand) Idée: déplacer la "fenêtre" de test de plusieurs cases d un coup quand c est possible. Pour chaque position à laquelle intervient une différence on a un décalage spécifique. Deux cas : bon-suffixe et mauvais-caractère. On commence les comparaisons par la fin de x. On a alors h(y[j+1 j+m]) = y[j+1]2 m 1 + + y[j+m]2 0 mod q = (h(y[j j+m 1]) 2(y[j]2 m 1 ) + y[j+m]) mod q une multiplication par 2 m 1, une multiplication par 2, une soustraction, une addition et un modulo. 23 de 43 24 de 43
Bon suffixe Mauvais caractère : Le caractère b de y ne correspond pas au a de x. On cherche la prochaine sous-chaine u dans x. S il n y en a pas on cherche le plus grand préfixe v de x qui est un suffixe de u. Tableau : caractère --> décalage. Décalage final : MAX (décalage bon suffixe, décalage mauvais car.) Ces tableaux peuvent être calculés en temps O(m + taille alphabet) Etablir un tableau : no. du caractère différent --> décalage. 25 de 43 26 de 43 Données de taille variable 3. Représentation des chaînes Dans les programmes on aimerait pouvoir écrire Solution bornée Réserver l espace nécessaire à la plus grande chaîne que l on va mettre dans X. X : [ taille : Entier, contenu : tableau [1... max] de Caractère ] X "bon"... X "bonjour" Quel espace mémoire réserver pour la variable X? 1. S "abc" 3 S a b c Solutions Chaînes bornées 2. S "hahahabc" S 8 h a h a h a b c Chaînes non bornées Mutabilité et immuabilité 27 de 43 28 de 43
Problèmes comment fixer la taille maximale d une chaîne? gaspillage de place pour la plupart des valeurs exemple : stocker des mot français dans des chaînes Solution non bornée => allocation dynamique de la mémoire et déplacement des données (impossible d agrandir sur-place une zone mémoire) ma chaine taille maximale =~ 26 (anticonstitutionnellement) taille moyenne : probablement inférieure à 7 place inoccupée : env. 70% ma nouvelle chaine mécanisme d allocation tient à jour une carte des zones occupées et libres de la mémoire est capable de trouver (rapidement) une zone libre d une taille donnée => coût 29 de 43 30 de 43 Allocation dynamique de la mémoire et références Structure de données Variable de type référence chaine = [ taille : Entier, contenu : référence à tableau de Caractère ] contient l adress d un objet (entier, réel, tableau, etc.) référence = adresse mémoire d un objet de type tableau de Caractères pointeur qui contient n importe quelle adresse mémoire (év ent. à l intérieur d un objet ou en dehors de tout objet) Procédure d allocation 1. S "abcxx" S 5 a b c x x nouveau T ( new T() en Java) trouve un emplacement libre pour stocker un objet de type T fournit l adresse de cet objet 2. S "wwf" S 3 w w f p.ex. X = nouveau Tableau de 20 caractères X 3. S "hahahabcd" (allocation d un nouveau tableau) S h a h a h a b c d 8 w w f 31 de 43 32 de 43
Propriétés Dans les langages Pas de limitation de taille Bonne utilisation de la mémoire Allocation d un nouvel espace => coût (chercher une place en mémoire) => réduire le nombre de réallocations => allouer un espace n% plus grand que nécessaire En Java String x Toute variable de type String est une référence à un objet mémoire String. En C char* x Les variables de type référence sont indiquée par une * Ce ne sont pas de vraies références à des objets mais des pointeurs -- qui peuvent pointer absolument n importe où en mémoire. 33 de 43 34 de 43 Représentation immuable L objet qui contient la chaîne ne peut changer, chaque fois que l on affecte une nouvelle valeur à une variable chaîne, il faut créer (allouer) un nouvel objet. 1. x "cos" 2. y x 3. x x + "mos" Propriétés Pas besoin de prévoir des chaînes extensibles (non bornées), une fois qu une chaîne a été créée elle ne bouge plus. Deux variables peuvent faire référence à la même chaîne en mémoire si elles on la même valeur pas de problème d alias. x (3) (1) "cosmos" "cos" (2) y Toute opération qui produit un résultat de type chaîne doit créer une nouvelle chaîne pour stocker le résultat => coût. String S = "*"; for (i=1; i<=10000; i++) { S = S + "*" } => 10000 allocations + recopies de nouvelles chaînes 35 de 43 36 de 43
Représentation mutable Un objet chaîne peut changer de valeur. => les opérations ne produisent pas forcément de nouveaux objets de stockage 1. x "hop et boum" 2. y x 3. x "zip" moins de créations d objets Propriétés des objets mutables prévoir une stratégie d extension qui minimise les réallocations, (et reréférences) effets d alias A, B : chaînes mutables x (1) Chaîne (2) "hop et boum" "zip" (3) y A = "encore"; B = A; A = A + " vous"; --- B = "encore vous" 37 de 43 38 de 43 Mutabilité: Stratégies d extension Allouer un nouvel objet uniquement quand c est nécessaire (extension) - allouer plus de place que nécessaire lors de l extension de chaînes - p.ex. allouer toujours k cellules de plus. - p.ex. allouer le double de la taille précédente. [1] s "une chaîne ici" [2] s "plus court" [3] s s +"! " [4] s "de plus en plus long" s "*" pour i de 1 à 10000 { s s + "*" } Mutabilité et Performances si on alloue systématiquement k cellules de plus que nécessaire : 10 000 / k allocations en tout --> voir type StringBuffer en Java s de plus en plus long une chaîne ici plus court (4) (1, 2, 3) 39 de 43 40 de 43
Implémentation des opérations Implémentation Concaténation(s1, s2) chaînes immuables : 1. allouer un objet pour le résultat 2. copier s1 3. copier s2 complexité: allocation( s1 + s2 ) + ( s1 + s2 )copier caractère chaînes mutables si ( s2 > espace libre dans l objet s1) { allouer un objet pour le résultat copier s1 } copier s2 Insertion(s1, s2, position) Chaînes immuables : comme la concaténation Chaînes mutables s il y a réallocation : comme pour les chaînes immuables sinon ( s1 position)copies + s2 copies Conclusion: impossible de traiter de grands textes de manière efficace complexité: pire cas : comme chaînes immuables, meilleur cas : ( s1 ) copier caractèe 41 de 43 42 de 43 Représentation - Résumé Les options de représentation sont : mutable immuable borné constantes non bornée avec référence peu d allocation/déallocation mémoire attention aux alias pas d alias bcp allocations mémoire 43 de 43