Université de Savoie
Module ETRS711
Travaux pratiques
Compression en codage de Huffman
1. Organisation du projet
1.1. Objectifs
Le but de ce projet est d'écrire un programme permettant de compresser des fichiers textes,
sans perte d'information, afin qu'ils occupent moins d'espace sur un disque. On demande
également d'écrire un compresseur qui devra restaurer le fichier original. Les algorithmes
de compression sont nombreux. Celui proposé ici est l'algorithme de Huffman. Nous nous
proposons de le coder en langage C.
1.2. Notation du projet
La notation sera faite au terme dune présentation de votre travail. La forme de cette
présentation est laissée totalement libre (Power Point, film, exposé oral en français, en
anglais, animation, documents écrits). Un vidéo-projecteur est à votre disposition si besoin.
Le temps de cette présentation est de 5 minutes (démonstrations comprises). Vous devrez être
donc extrêmement concis et préparer toutes vos démonstrations au préalable afin de limiter le
temps de manipulation.
1.3. Organisation dun projet de programmation
Lensemble du projet devra obligatoirement comporter :
· Toutes les versions de votre logiciel en commençant par huff_v0.c. Chaque
amélioration de votre logiciel vous fera passer à la version supérieure et vous
conserverez une sauvegarde de la dernière version qui fonctionne.
· Un fichier « version.txt » dans lequel vous écrirez la description de chacune des
versions de votre logiciel que vous avez écrit.
Il est préférable que vous respectiez les propositions de prototypage des fonctions faites dans
lénoncé afin que le debugage soit plus aisé.
2. Principe de l'algorithme de Huffman
Une idée apparue très tôt en informatique pour compresser les données a été exploitée
indépendamment dans les années 1950 par Shannon et Fano. Elle est basée sur la remarque
suivante : les caractères d'un fichier sont habituellement codés sur un octet, donc tous sur le
même nombre de bits. Il serait plus économique en terme d'espace disque, pour un fichier
donné, de coder ses caractères sur un nombre variable de bits, en utilisant peu de bits pour les
caractères fréquents et plus de bits pour les caractères rares. Le codage choisi dépend donc du
fichier à compresser. Les propriétés d'un tel codage sont les suivantes :
a. Les caractères sont codés sur un nombre différent de bits (pas nécessairement un
multiple de 8) ;
b. Les codes des caractères fréquents sont courts ; ceux des caractères rares sont longs ;
c. Bien que les codes soient de longueur variable, on peut décoder le fichier compressé
de façon unique.
d. La dernière de ces trois propriétés est automatiquement assurée si l'on à la propriété
suivante : Si c1 et c2 codent deux caractères différents, c1 ne commence pas par c2 et
c2 ne commence pas par c1. En effet, si la propriété d est assurée, lorsqu'on décode le
fichier compressé en le lisant liairement, dès que l'on reconnaît le code d'un
caractère, on sait que l'on ne pourra pas le compléter en un autre code.
L'algorithme de Huffman, qui garantit ces propriétés, fonctionne de la façon suivante :
2.1. Calcul des occurrences des caractères
On prend lexemple dun fichier texte dont le contenu est « Une banane ».
· On calcule tout d'abord le nombre doccurrence de chaque caractère dans le fichier à
compresser. Dans lexemple ci-dessous, on a le nombre doccurrence du caractère
espace, U, b, n, a et e.
Figure 1 : Fréquence des caractères
2.2. Création de larbre de Huffman
On prend ensuite les caractères qui possèdent la plus faible occurrence et on ajoute leur
nombre doccurrence pour réaliser un nouveau nœud.
Figure 2 : Création dun nouveau nœud
On fait exactement la même chose en reprenant en compte le nouveau nœud (et non plus les
caractères espace et U). Dans lexemple précédent loccurrence la plus faible est celle de b et
celle du nouveau nœud (on aurait pu prendre aussi a ou e puisque leur valeur est 2 aussi,
cela revient au même à la fin).
Figure 3 : Création dun autre nouveau nœud
IMPORTANT : Dans toute la suite du TP, on appellera « une feuille » de larbre les éléments
qui sont en bout de larbre (les caractères). On appellera un nœud les éléments regroupant
deux feuilles (ou deux nœuds).
Figure 4 : Création complète de l'arbre de Huffman
Avec d'autres choix, on peut obtenir des arbres différents, mais l'algorithme fonctionne avec
tout choix respectant la construction ci-dessus. À partir de l'arbre, on construit le code d'un
caractère en lisant le chemin qui va de la racine au caractère. Un pas à gauche étant lu comme
0 et un pas à droite comme 1.
Figure 5 : Arbre de Huffman avec le codage des caractères
On lit le code des caractères en descendant depuis le haut jusquau caractère.
Figure 6 : Code binaire de chaque caractère
Dans l'exemple précédent, on obtient la suite de bits 0001011100000011001100111 pour le
codage du mot « Une banane ».
On peut voir que ce codage vérifie toujours les propriétés a) à d), et permet donc la
compression et la décompression. Avec cet algorithme, le décompresseur doit connaître les
codes construits par le compresseur.
Lors de la compression, le compresseur écrira donc ces codes en but de fichier compressé,
sous un format à définir, connu du compresseur et du décompresseur. Le fichier compressé
aura donc deux parties disjointes :
· Une première partie permettant au décompresseur de retrouver le code de chaque
caractère;
· Une seconde partie contenant la suite des codes des caractères du fichier à compresser.
Attention, le décompresseur doit toujours pouvoir trouver la séparation entre ces deux parties.
Aussi, vous pouvez toujours vérifier le code générer par votre algorithme en vérifiant que le
code générer pour coder un caractère ne doit pas ressembler au but dun code dun autre
caractère.
3. Travail demandé
3.1. Première partie : Occurrences des caractères
Lobjectif est de travailler avec des fichiers (qui par la suite seront les fichiers à compresser).
Il faut donc que nous maitrisions les fonctions de manipulation de fichier.
Q1. Réaliser un programme qui ouvre un fichier texte et qui affiche une partie du contenu
à lécran. (Utiliser la fonction fread()).
Q2. Réaliser un programme qui ouvre un fichier texte et qui affiche la totalité du contenu
du fichier à lécran. Vous ferez une lecture grâce à la fonction fgetc( ) jusqu'à ce que vous
rencontriez le caractères de fin de fichier (EOF=End Of File).
Nous nous intéressons au comptage des occurrences des caractères présents dans le fichier
texte. Pour cela nous utiliserons un tableau de caractère appelé tab_caractere[256]. Ce tableau
comporte 256 éléments. Dans chaque case de ce tableau, nous rentrerons le nombre
doccurrence du caractère dont le code ASCII est donné par lindex de tab_caractère.
Exemple :
Le code ASCII du a est 97.
tab_caractere[97] comportera donc le nombre doccurrence du caractère a.
Q3. Coder une fonction dont le prototype est [ void occurence(FILE* file, int tab[256]) ].
Cette fonction comptera les occurrences des caractères du fichier file, et stockera les
occurrences dans le tableau tab passé en paramètre. Afficher à lécran une partie du
tableau pour vérifier le fonctionnement.
3.2. Seconde partie : Réalisation de larbre de Huffman
Pour chaque caractère (ou nœud de larbre), nous allons créer une structure commune qui
nous permettra de créer larbre et de créer le code. Nous avons appelé cette structure « nœud »
mais en réalielle sera aussi utilisée pour les feuilles de larbre.
La structure est donc définie comme suit :
1. struct noeud{
2. unsigned char c; /* Caractère initial*/
3. unsigned int occurence; /* Nombre d'occurrences dans le fichier */
4. int code; /* Codage dans l'arbre */
5. int bits; /* Nombre de bits sur lesquels est codée le caractère */
6. struct noeud *gauche, *droite; /* Lien vers les nœuds suivants */
7. };
La seule différence entre un nœud et une feuille, est que pour une feuille, les pointeurs vers
les nœuds suivant sont NULL. Cest de cette façon que nous les distinguerons.
Q4. Réaliser une boucle dans votre programme afin de créer dynamiquement une structure
nœud pour chacun des caractères contenu dans le fichier. Vous testerez votre programme en
affichant le contenu du champ c caractère et occurrence de chacune des structures créées.
Chacune de ces structures seront réservées en mémoire par la fonction malloc(). De plus, afin
de conserver lensemble des structures créées, nous sauvegarderons les pointeurs sur ces
structures nœud (struct nœud*) dans le tableau suivant : [struct noeud*
arbre_huffman[256] ]
Explications complémentaires :
On doit donc créer pour chacun des caractères de notre tableau tab_caractere[256] une
structure nœud comme suit :
struct nœud
c=
Occurrence=1
gauche=NULL
droite=NULL
bits=0
code=0
struct nœud
c=U
Occurrence=1
gauche=NULL
droite=NULL
bits=0
code=0
struct nœud
c=b
Occurrence=1
gauche=NULL
droite=NULL
bits=0
code=0
struct nœud
c=n
Occurrence=3
gauche=NULL
droite=NULL
bits=0
code=0
struct nœud
c=a
Occurrence=2
gauche=NULL
droite=NULL
bits=0
code=0
struct nœud
c=e
Occurrence=2
gauche=NULL
droite=NULL
bits=0
code=0
1 / 10 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !