107 lines
4.8 KiB
C
107 lines
4.8 KiB
C
#include "arbre.h"
|
|
|
|
int listeVersArbre(Liste *liste) {
|
|
Cellule *curseur = *liste;
|
|
int nombreLettresDansFichier = 0;
|
|
while (curseur != NULL) { // parcours de la liste
|
|
if (curseur->lettre != '\0') nombreLettresDansFichier++; // +1 au compteur si c'est bien une lettre
|
|
if (curseur->suivant != NULL) { // on créer un mini-arbre qu'on colle au reste de l'arbre seulement si le suivant existe
|
|
Cellule *nouvelleCellule;
|
|
if ((nouvelleCellule = (Cellule*)malloc(sizeof(Cellule))) == NULL) { // on alloue de la mémoire pour notre nouvelle cellule (mini-racine)
|
|
printf("Impossible d'allouer de la mémoire supplémentaire (listeVersArbre).\n"); // gestion de l'erreur
|
|
exit(1);
|
|
}
|
|
|
|
nouvelleCellule->gauche = curseur; // membre gauche = curseur
|
|
nouvelleCellule->droite = curseur->suivant; // membre droit = élément suivant dans la liste
|
|
nouvelleCellule->lettre = '\0';
|
|
nouvelleCellule->frequence = nouvelleCellule->gauche->frequence + nouvelleCellule->droite->frequence;
|
|
|
|
if (curseur->suivant->lettre != '\0') nombreLettresDansFichier++; // +1 si le suivant est aussi une lettre (membre droit)
|
|
|
|
curseur = curseur->suivant->suivant; // on va au suivant 2x car on a déjà ajouté le suivant en tant que membre droit
|
|
|
|
*liste = curseur; // on change le point de départ de notre liste pour ne pas traiter en boucle les anciennes cellules
|
|
ajouterRangee(liste, nouvelleCellule); // on ajoute à la liste notre nouvelle cellule
|
|
curseur = *liste; // on met à jour le curseur
|
|
} else { // cas du dernier élément
|
|
*liste = curseur;
|
|
curseur = curseur->suivant;
|
|
}
|
|
}
|
|
|
|
return nombreLettresDansFichier;
|
|
}
|
|
|
|
void assignationCode(Arbre arbre, int codeActuel, int longueur, Entete *enteteListe, int *i, int *longueurTotale) {
|
|
if (arbre->lettre != '\0') { // si c'est une lettre qu'on regarde
|
|
enteteListe[*i].lettre = arbre->lettre; // ajout de la lettre
|
|
enteteListe[*i].code = codeActuel; // assignation de son code
|
|
enteteListe[*i].longueur = longueur; // longueur du code (ex: 1001 est de taille 4)
|
|
|
|
*i += 1; // on incrémente de 1
|
|
*longueurTotale += longueur * arbre->frequence; // incrémente la taille du code à la taille totale finale
|
|
} else { // si c'est une "mini-racine"
|
|
longueur++;
|
|
codeActuel <<= 1; // décalage de bit vers la gauche
|
|
assignationCode(arbre->gauche, codeActuel, longueur, enteteListe, i, longueurTotale); // appel récursif arbre de gauche
|
|
codeActuel |= 1; // copie de bit si nécessaire (porte ou)
|
|
assignationCode(arbre->droite, codeActuel, longueur, enteteListe, i, longueurTotale); // appel récursif arbre de droite
|
|
}
|
|
}
|
|
|
|
// Libère en mémoire un Arbre
|
|
void freeArbre(Arbre arbre) {
|
|
if (arbre->lettre == '\0') { // free aussi les mini-racines
|
|
freeArbre(arbre->gauche);
|
|
freeArbre(arbre->droite);
|
|
}
|
|
|
|
free(arbre); // free du noeud courant
|
|
}
|
|
|
|
Entete *arbreVersListe(Arbre arbre, int taille, int *tailleTotale) {
|
|
Entete *enteteListe;
|
|
if ((enteteListe = (Entete*)malloc(taille * sizeof(Entete))) == NULL) { // on alloue la liste qui va contenir nos caractères
|
|
printf("Impossible d'allouer de la mémoire supplémentaire (arbreVersListe).\n"); // gestion de l'erreur
|
|
exit(1);
|
|
}
|
|
int i = 0; // initialisation de `i` au début car `assignationCode` est récursif
|
|
assignationCode(arbre, '\0', 0, enteteListe, &i, tailleTotale); // on commence avec une racine nulle et une taille de 0
|
|
freeArbre(arbre);
|
|
|
|
return enteteListe;
|
|
}
|
|
|
|
Entete *fichierVersListe(FILE *fichier, int *nombreLettresDansFichier, int *tailleTotale) {
|
|
char lettre = 'a';
|
|
Liste liste = NULL;
|
|
while (lettre != EOF) {
|
|
lettre = fgetc(fichier);
|
|
ajouterLettre(&liste, lettre);
|
|
}
|
|
rewind(fichier);
|
|
|
|
trierListe(&liste);
|
|
*nombreLettresDansFichier = listeVersArbre(&liste);
|
|
|
|
return arbreVersListe(liste, *nombreLettresDansFichier, tailleTotale);
|
|
}
|
|
|
|
void compression(FILE *entree, FILE *sortie) {
|
|
int nombreLettresDansFichier; // initialisé par `listeVersArbre`
|
|
int tailleTotale = 0; // taille totale en en bit du fichier en sortie
|
|
Entete *enteteListe = fichierVersListe(entree, &nombreLettresDansFichier, &tailleTotale);
|
|
|
|
// On écrit l'entête du fichier avec la table complète des correspondances
|
|
enteteVersFichier(enteteListe, nombreLettresDansFichier, tailleTotale, sortie);
|
|
|
|
// On écrit les données huffman-isée dans le fichier
|
|
huffmanVersFichier(entree, sortie, enteteListe, nombreLettresDansFichier);
|
|
}
|
|
|
|
void decompression(FILE *entree, FILE *sortie) {
|
|
/* fclose temporaire pour supprimer les warnings */
|
|
fclose(entree);
|
|
fclose(sortie);
|
|
}
|