8.1 Listes chaînées
Une liste chaînée est constituée de cellules d'un type
struct contenant :
-
un pointeur/l'adresse sur/de la cellule suivante ;
- des champs d'informations.
On peut ainsi définir une cellule par le type suivant :
typedef struct cellule{
struct cellule *suivante ;
type_1 el_1 ;
....
type_n el_n ;
} cellule ;
Ceci fait, il nous reste à définir les manipulations
élémentaires associée à une liste ; il nous faut des fonctions
qui permettent :
-
de créer d'une cellule ;
- d'insérer une cellule dans la liste ;
- de supprimer une cellule de la liste ;
- de détruire d'une cellule ;
Pour créer une cellule, il faut allouer de l'espace mémoire :
cellule * CreerCellule(type_1 data_1, ... type_n data_n){
cellule * cell = (cellule *) malloc(sizeof(cellule)) ;
cell->suivante = NULL ; /* la cellule nouvellement cr\'ee
* ne pointe sur rien */
cell->el_1 = data_1 ;
....
cell->el_n = data_n ;
return cell ;
}
Cette fonction crée (et remplit) une cellule. Remarquez que l'espace
mémoire alloué grâce à la fonction malloc n'est pas
détruit à la fin de la fonction CreerCellule
contrairement à l'ensemble des variables et arguments de cette
fonctions. Pour éviter d'encombrer la mémoire, il nous faut
disposer d'une fonction permettant de détruire une cellule. Pour ce
faire, on utilise la fonction free de la librairie
standrard :
void DetruireCellule( cellule * cell) {
free( (void *) cell) ;
}
Pour insérer une cellule dans une liste chaînée après la
cellule cell_courante, il suffit d'utiliser le code :
void InsererCellule( cellule * cell_a_inserer,
cellule * cell_courante){
cell_a_inserer -> suivante = cell_courante -> suivante ;
cell_courante -> suivante = cell_a_inserer ;
}
De même, pour extraire une cellule après une cellule (ici
qualifiée de mère), on peut utiliser le code :
cellule * ExtraireCellule (cellule * cell_mere){
cellule * tmp ;
tmp = cell_mere->suivante ;
cell_mere -> suivante = tmp -> suivante ;
return tmp ;
}
Exercice 8.0 --- Manipulations élémentaires.
Construire un crible d'Érathostène à l'aide d'une liste
chaînée qui au départ stockera l'ensemble des nombres
inférieurs à un entier saisi au clavier.
Après une étape de construction, il faudra considérer
successivement les éléments de la liste et supprimer les
multiples.
Pour finir, l'ensemble des nombres premiers est afficher à
l'écran.
Impératif :
on prendra soin de détruire les cellules de la liste
chaînée associées à des nombres composés.
Exercice 8.1 --- Distribution de fréquence des lettres d'un texte.
Étant donnée un texte codé suivant un standard ISO (dans la
suite ce sera le standard 8859 cf. man iso_8859_1), on se
propose dans cet exercice de déterminer la fréquences des
caractères le composant.
Par exemple, si l'on saisi au clavier (azerty) la phrase :
Longtemps, je me suis couché de bonne heure.
et qu'on la stocke dans un fichier texte, on obtient le fichier
composé d'entiers codés sur 8 bits :
| 76 |
111 |
110 |
103 |
116 |
101 |
109 |
112 |
115 |
32 |
106 |
| 101 |
32 |
109 |
101 |
32 |
115 |
117 |
105 |
115 |
32 |
99 |
| 111 |
117 |
99 |
104 |
233 |
32 |
100 |
101 |
32 |
98 |
111 |
| 110 |
110 |
101 |
32 |
104 |
101 |
117 |
114 |
101 |
46 |
Pour faire l'analyse de fréquence des lettres de ce texte, on
peut procéder comme suit :
-
construire une liste chaînée dont les cellules
contiennent deux informations : une lettre et sa fréquence ;
- parcourir le texte lettre par lettre et pour chacune ;
-
vérifier si elle se trouve déjà dans la liste ;
- si oui, incrémenter la fréquence.
si non, créer et insérer la nouvelle cellule correspondante ;
- pour finir, on parcours la liste afin de calculer les fréquences.
Construisez un programme prenant en entrée deux noms de fichiers
foo.txt et bar.res ; ce programme calcule la
distribution de fréquence du texte contenu dans foo.txt et
sauve le résultat dans le fichier bar.res.
Indications :
vous pouvez utilisez le manuel unix comme texte (man gcc > foo.txt) ou télécharger un texte depuis la toile.
Exercice 8.2 --- Calcul de l'entropie d'un texte.
Soit un alphabet S munie d'une variable aléatoire X
de probabilité de réalisation P(X=s). Dans notre cas, pour une
lettre s d'un texte, la probabilité P(X=s) n'est que la
fréquence d'apparition de cette lettre. On appelle quantité
d'information du symbole s de S le nombre :
Ainsi, plus l'utilisation d'une lettre est rare, plus la
quantité d'information associée est grande.
Définition 1 [C.E. Shannon 1940] ---
On appelle entropie
de la source S munie d'une
variable aléatoire X et de la probabilité de
réalisation P la quantité moyenne d'information par
symbole :
En utilisant la notion d'entropie de source, on fait l'hypothèse
que toutes les lettres d'un texte sont indépendantes les unes des
autres i.e. il est aussi probable d'avoir un e après un l qu'un z.
Ce n'est généralement pas le cas : l'occurrence une lettre dépend fortement
des lettres voisines. Pour estimer l'entropie dans ce cas, on
utilise la fréquence --- non plus des lettres de S --- mais des
groupes de lettres m1... md avec mi dans S.
Comme une lettres dépend peu des lettres éloignées : la
suite H(m1··· md)/d converge rapidement lorsque d
tends vers l'infini.
Définition 2 --- L'entropie d'un texte est la limite
Questions :
-
Modifier votre programme afin de calculer l'entropie de source
d'un texte (la source étant dans ce cas l'ensemble des lettres
distinctes composant le texte).
- Modifier votre programme afin de calculer l'entropie d'un
texte.
Indications :
On dispose d'une fonction log définie dans math.h.
Pour l'utiliser, il faut indiquer au compilateur la librairie
correspondante par l'instruction gcc foo.c -lm.
Pour calculer l'entropie d'un texte, il est intéressant de
modifier le typage des cellules de notre liste chaînée : on
peut remplacer le caractère par une chaîne de caractères et
profiter de l'ordre lexicographique induit par la commande
stcmp.
Remarque :
L'implantation que nous venons de terminer étant naive, sa
complexité --- i.e. le nombre d'opérations nécessaires --- est
grande : elle est quadratique dans la taille de l'entrée. En
utilisant une table de hachage, on peut effectuer la même tâche
avec une complexité linéaire en la taille de l'entrée.
Pour tout commentaire : Alexandre Sedoglavic.