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