Chaines de caractères 1. Type abstrait Spécification algébrique d`un
Transcription
Chaines de caractères 1. Type abstrait Spécification algébrique d`un
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 On définit une liste d’opérations sur les objets de ce type – Opérations de comparaison • 2. Algorithmes de recherche de sous-chaînes Opérations • 3. Implémentation 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 G. Falquet, CUI, Université de Genève 1 de 43 G. Falquet, CUI, Université de Genève Spécification algébrique d’un type de données 2 de 43 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 G. Falquet, CUI, Université de Genève 3 de 43 G. Falquet, CUI, Université de Genève 4 de 43 Axiomes Axiomes (suite) ∀S : chaine ∀T : chaine ∀C : caractère ∀I : entier I = 1 => car_à(I, ajout(C, S)) == C longueur(vide) == 0 I > 1 => longueur(ajout(C, S)) == longueur(S) + 1 car_à(I, ajout(C, S)) == car_à(I – 1, S) I ≤ longueur(S) => longueur(concat(S, T)) == longueur(S) + longueur(T) car_à(I, concat(S, T)) == car_à(I, S) I > longueur(S) => car_à(I, concat(S, T)) == car_à(I – longueur(S), T) G. Falquet, CUI, Université de Genève 5 de 43 G. Falquet, CUI, Université de Genève Utilisation des axiomes 6 de 43 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 G. Falquet, CUI, Université de Genève == ’o’ 7 de 43 G. Falquet, CUI, Université de Genève 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 Axiomes de l’égalité stricte concat(S, vide) == S ’’ = ’’ == vrai longueur(S) ≠ longueur(T) => S = T == faux Utilisation: "bon"+"jo" C1 = C2 => ajout(C1, S) = ajout(C2, T) == S = T C1 ≠ C2 => ajout(C1, S) = ajout(C2, T) == faux concat(ajout(’b’, ajout(’o’, ajout(’n’, ’’))), ajout(’j’, ajout(’o’, ’’))) == 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 G. Falquet, CUI, Université de Genève "mel" = "mél" == faux 9 de 43 G. Falquet, CUI, Université de Genève Egalité par degré 10 de 43 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 vide ≤ S == vr ai =1 : des car. différents selon =0 sont considérés égaux C1 < C2 => ajout(C1, S) ≤ ajout(C2, T) == vr ai "e" =1 "é" ==> "fréquence" = "frequence" C1 = C2 => ajout(C1, S1) ≤ ajout(C2, S2) == S1 ≤ S2 =2 : encore plus large C1 > C2 => ajout(C1, S) ≤ ajout(C2, T) == faux "e" =2 "E" ==> "Fréquence" = "frequence" etc. Donc Dépend de la langue ! (voir: classe java.text.Collator) "Zot" ≤ "aot" "truc" ≤ "truc " (mais pas l’inverse) Mêmes axiomes que l’égalité stricte mais en remplaçant = par =D G. Falquet, CUI, Université de Genève (si "Z" ≤ "a") "1205" ≤ "205" 11 de 43 G. Falquet, CUI, Université de Genève 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 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] • Karp-Rabin (Hachage ) tester à partir de la position 2 de y : x[0 .. m–1] = y[2 .. m+1] • Boyer Moore … • et beaucoup d’autres : http://www-igm.univ-mlv.fr/~lecroq/string tester à partir de la position k de y : x[0 .. m–1] = y[k .. k+m–1] … G. Falquet, CUI, Université de Genève 13 de 43 G. Falquet, CUI, Université de Genève Algorithme 14 de 43 Automate à états Technique : 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. 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) G. Falquet, CUI, Université de Genève 15 de 43 G. Falquet, CUI, Université de Genève 16 de 43 Exemple : chercher "boboa" Construction de l’automate Automate : • Chaque état de l’automate correspond à un préfixe de la chaîne x à chercher b ε, x[0], x[0..1], x[0..2], … b ε b o ni o ni b pas b • Il y a une transition q –a–> qa si qa est un préfixe de x bo pas b b b ni a ni b • sinon il y a une transition q –a–> p b b boboa où p est le plus long suffixe de qa qui est un préfixe de x bob a o bobo G. Falquet, CUI, Université de Genève 17 de 43 G. Falquet, CUI, Université de Genève 18 de 43 Représentation de l’automate Exemple 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. 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 jtaille(x) – + 1 // début } retourner –1 G. Falquet, CUI, Université de Genève 19 de 43 G. Falquet, CUI, Université de Genève 20 de 43 Karp-Rabin (Hachage) Algorithme Pour accélérer la recherche on teste une signature de la chaîne 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] } Si h est une fonction Chaînes --> Entiers Si x = y[j…j+m–1] alors h(x) = h(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. G. Falquet, CUI, Université de Genève 21 de 43 G. Falquet, CUI, Université de Genève Karp-Rabin (suite) 22 de 43 Boyer Moore Astuce : calculer h(y[j+1 … j+m]) à partir de h(y[j … j+m–1]) 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. On prend comme fonction h h(y[0 … m–1] = (y[0]2m–1 + … + y[m–1]20) mod q Deux cas : bon-suffixe et mauvais-caractère. (pour q assez grand) On commence les comparaisons par la fin de x. On a alors h(y[j+1 … j+m]) = y[j+1]2m–1 + … + y[j+m]20 mod q = (h(y[j … j+m–1]) – 2(y[j]2m–1) + y[j+m]) mod q une multiplication par 2m–1, une multiplication par 2, une soustraction, une addition et un modulo. G. Falquet, CUI, Université de Genève 23 de 43 G. Falquet, CUI, Université de Genève 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. G. Falquet, CUI, Université de Genève 25 de 43 G. Falquet, CUI, Université de Genève 26 de 43 3. Représentation des chaînes Solution bornée Données de taille variable 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 ] Dans les programmes on aimerait pouvoir écrire X ← "bon" .... X ← "bonjour" 1. S ← "abc" S Quel espace mémoire réserver pour la variable 3 X? abc 2. S ← "hahahabc" S Solutions • Chaînes bornées 8 hahahabc • Chaînes non bornées • Mutabilité et immuabilité G. Falquet, CUI, Université de Genève 27 de 43 G. Falquet, CUI, Université de Genève 28 de 43 Problèmes Solution non bornée – comment fixer la taille maximale d’une chaîne ? => allocation dynamique de la mémoire et déplacement des données – gaspillage de place pour la plupart des valeurs (impossible d’agrandir sur-place une zone mémoire) exemple : ma chaine stocker des mot français dans des chaînes • taille maximale =~ 26 (anticonstitutionnellement) • taille moyenne : probablement inférieure à 7 ma nouvelle chaine • place inoccupée : env. 70% 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 G. Falquet, CUI, Université de Genève 29 de 43 G. Falquet, CUI, Université de Genève Allocation dynamique de la mémoire et références 30 de 43 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) 1. S ← "abcxx" S 5 Procédure d’allocation nouveau T ( new T() en Java) 2. S ← "wwf" trouve un emplacement libre pour stocker un objet de type T abcxx S 3 wwf fournit l’adresse de cet objet 3. S ← "hahahabcd" (allocation d’un nouveau tableau) S p.ex. X = nouveau Tableau de 20 caractères X G. Falquet, CUI, Université de Genève hahahabcd 31 de 43 G. Falquet, CUI, Université de Genève 8 wwf 32 de 43 Propriétés Dans les langages Pas de limitation de taille En Java String x Bonne utilisation de la mémoire Toute variable de type String est une référence à un objet mémoire String. Allocation d’un nouvel espace => coût (chercher une place en mémoire) => réduire le nombre de réallocations En C => allouer un espace n% plus grand que nécessaire 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. G. Falquet, CUI, Université de Genève 33 de 43 G. Falquet, CUI, Université de Genève Représentation immuable 34 de 43 Propriétés L’objet qui contient la chaîne ne peut changer, Pas besoin de prévoir des chaînes extensibles (non bornées), chaque fois que l’on affecte une nouvelle valeur à une variable chaîne, il faut créer (allouer) un nouvel objet. • 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 1. x ← "cos" 2. y ← x • pas de problème d’alias. 3. x ← x + "mos" (1) x "cos" (3) 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. y (2) String S = "*"; for (i=1; i< =10000; i++) { S = S + "*" } "cosmos" => 10000 allocations + recopies de nouvelles chaînes G. Falquet, CUI, Université de Genève 35 de 43 G. Falquet, CUI, Université de Genève 36 de 43 Représentation mutable Propriétés des objets mutables Un objet chaîne peut changer de valeur. => les opérations ne produisent pas forcément de nouveaux objets de stockage • moins de créations d’objets • prévoir une stratégie d’extension qui minimise les réallocations, (et re- références) 1. x ← "hop et boum" • effets d’alias 2. y ← x 3. x ← "zip" A, B : chaînes mutables (1) x Chaîne "hop et boum" "zip" (3) (2) A = "encore"; B = A; A = A + " vous"; y --- B = "encore vous" G. Falquet, CUI, Université de Genève 37 de 43 G. Falquet, CUI, Université de Genève Mutabilité: Stratégies d’extension 38 de 43 Mutabilité et Performances s ← "*" pour i de 1 à 10000 { s ← s + "*" } 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" si on alloue systématiquement k cellules de plus que nécessaire : [2] s ← "plus court" 10 000 / k allocations en tout [3] s ← s +" ! " [4] s ← "de plus en plus long" --> voir type StringBuffer en Java s une chaîne ici plus court de plus en plus long (4) (1, 2, 3) G. Falquet, CUI, Université de Genève 39 de 43 G. Falquet, CUI, Université de Genève 40 de 43 Implémentation des opérations Implémentation Concaténation(s1, s2) Insertion(s1, s2, position) chaînes immuables : Chaînes immuables : comme la concaténation 1. allouer un objet pour le résultat 2. copier s1 Chaînes mutables 3. copier s2 s’il y a réallocation : comme pour les chaînes immuables complexité: allocation(|s1|+|s2|) + (|s1| + |s2|)copier caractère sinon chaînes mutables (|s1| – position)copies + |s2| copies si (|s2| > espace libre dans l’objet s1) { allouer un objet pour le résultat copier s1 } copier s2 Conclusion: impossible de traiter de grands textes de manière efficace complexité: pire cas : comme chaînes immuables, meilleur cas : (|s1|) copier caractèe G. Falquet, CUI, Université de Genève 41 de 43 Représentation - Résumé Les options de représentation sont : mutable borné non bornée avec référence G. Falquet, CUI, Université de Genève immuable constantes peu d’allocation/déallocation mémoire attention aux alias pas d’alias bcp allocations mémoire 43 de 43 G. Falquet, CUI, Université de Genève 42 de 43