diff --git a/Makefile b/Makefile index efd3ce3..9dd0385 100644 --- a/Makefile +++ b/Makefile @@ -3,11 +3,11 @@ FLAGS=-Wall -std=c99 SRC=src PROG=compress -all: $(SRC)/main.o $(SRC)/huf.o +all: main.o huf.o $(CC) $^ $(FLAGS) -o $(PROG) -%.o: %.cpp +%.o: src/%.c $(CC) $(FLAGS) -c $^ -camille: - rm -f $(PROG) **/*.o **/*.gch +clean: + rm -f $(PROG) *.o diff --git a/compress b/compress deleted file mode 100755 index eccd934..0000000 Binary files a/compress and /dev/null differ diff --git a/include/huf.h b/include/huf.h index 50a1a73..0d596de 100644 --- a/include/huf.h +++ b/include/huf.h @@ -1,6 +1,12 @@ #ifndef __FREQ_H__ #define __FREQ_H__ +#include + +#define TRUE 1 +#define FALSE 0 +#define NUM_CHARS 256 + typedef struct Vertex Vertex; struct Vertex { // le double `freq` indique la fréquence d'apparition de la lettre @@ -11,18 +17,27 @@ struct Vertex { // représente (caractère ASCII 0 - 255) char value; - // pointe vers le sommet parent à celui-ci (ou bien vers NULL s'il n'a - // pas de parent affecté, comme c'est le cas pour les sommets non-traités - // et pour la racine) + // les sommets virtuels sont ceux qui ne correspondent pas à une lettre + // du corpus, mais chapeautent les autres sommets + int is_virtual; + + // pointe vers le sommet parent à celui-ci, ou NULL s'il n'a pas de parent, + // comme par exemple pour la racine et les sommets en cours de traitement Vertex* parent; }; +typedef struct Tree Tree; +struct Tree { + size_t size; + Vertex* vertices; +}; + // calcule un tableau des fréquences des caractères dans le corpus, // indexé par la valeur numérique ASCII de chaque caractère double* computeFrequencies(const char* filepath); // déduit du tableau de fréquences l'arbre de Huffman, représenté // par une liste de sommets chaînés -Vertex* buildTree(double* frequencies); +Tree buildTree(double* frequencies); #endif diff --git a/src/huf.c b/src/huf.c index 635508d..4296dff 100644 --- a/src/huf.c +++ b/src/huf.c @@ -1,13 +1,14 @@ #include "../include/huf.h" +#include #include #include double* computeFrequencies(const char* filepath) { - double* frequencies = (double*) malloc(256 * sizeof(double)); + double* frequencies = (double*) malloc(NUM_CHARS * sizeof(double)); int totalChars = 0; // initialisation du tableau à 0 - for (int i = 0; i < 256; i++) { + for (size_t i = 0; i < NUM_CHARS; i++) { frequencies[i] = 0; } @@ -21,30 +22,97 @@ double* computeFrequencies(const char* filepath) { } // conversion des effectifs en fréquences - for (int i = 0; i < 256; i++) { + for (size_t i = 0; i < NUM_CHARS; i++) { frequencies[i] /= totalChars; } return frequencies; } -Vertex* buildTree(double* frequencies) { - int vertexCount = 0; +Tree buildTree(double* frequencies) { + // comptage du nombre de caractères différents dans le fichier, + // il s'agit du nombre initial de sommets dans l'arbre binaire + size_t vertex_count = 0; - // on compte le nombre de sommets à allouer - // (uniquement les caractères qui apparaissent au moins une fois) - for (int i = 0; i < 256; i++) { + for (size_t i = 0; i < NUM_CHARS; i++) { if (frequencies[i] > 0) { - vertexCount++; + vertex_count++; } } - // on alloue la place pour 2n + 1 sommets (nombre total - // de sommets dans l'arbre binaire) - Vertex* tree = (Vertex*) malloc((2 * vertexCount - 1) * sizeof(Vertex)); + // allocation d'un tableau de 2n + 1 sommets, le nombre total de + // sommets dans l'arbre binaire final + size_t tree_size = 2 * vertex_count - 1; + Vertex* vertices = (Vertex*) malloc(tree_size * sizeof(Vertex)); - // (à faire: algo pour remplir l'arbre) - // (trier le tableau des fréquences ?) + // remplissage initial du tableau avec un sommet pour chaque lettre + size_t next_available = 0; + + for (size_t i = 0; i < NUM_CHARS; i++) { + if (frequencies[i] > 0) { + vertices[next_available].frequency = frequencies[i]; + vertices[next_available].value = (char) i; + vertices[next_available].is_virtual = FALSE; + vertices[next_available].parent = NULL; + next_available++; + } + } + + // remplissage du tableau avec les sommets virtuels + while (next_available < tree_size) { + // détermination des deux sommets de fréquence les plus faibles + // parmi tous les sommets n'ayant pas de parent + size_t i = 0, min_vert, min_vert_sec; + int is_init = FALSE, is_init_sec = FALSE; + double min_freq; + + for (; i < next_available; i++) { + if (vertices[i].parent == NULL) { + if (!is_init) { + // initialisation du premier sommet sans parent + min_vert = i; + min_freq = vertices[i].frequency; + is_init = TRUE; + } else if (!is_init_sec) { + // initialisation du second sommet sans parent, + // en s'assurant qu'ils sont dans le bon ordre + if (vertices[i].frequency < min_freq) { + size_t swap = min_vert; + min_vert = i; + min_vert_sec = swap; + min_freq = vertices[i].frequency; + } else { + min_vert_sec = i; + } + + is_init_sec = TRUE; + } else if (vertices[i].frequency < min_freq) { + // déplacement de l'ancien minimum en second minimum + // et remplacement par le nouveau minimum + min_vert_sec = min_vert; + min_vert = i; + } + } + } + + // création d'un sommet parent à ces deux sommets. Ce sommet est + // créé à la prochaine position disponible dans le tableau + vertices[next_available].frequency = + vertices[min_vert].frequency + vertices[min_vert_sec].frequency; + vertices[next_available].is_virtual = TRUE; + vertices[next_available].parent = NULL; + + // assignation du nouveau parent et des enfants + vertices[min_vert].parent = &vertices[next_available]; + vertices[min_vert_sec].parent = &vertices[next_available]; + + next_available++; + } + + Tree tree = { + .size = tree_size, + .vertices = vertices + }; return tree; } diff --git a/src/huf.o b/src/huf.o deleted file mode 100644 index 0f781c4..0000000 Binary files a/src/huf.o and /dev/null differ diff --git a/src/main.c b/src/main.c index 1e5ae20..08f92e9 100644 --- a/src/main.c +++ b/src/main.c @@ -3,22 +3,39 @@ int main(int argc, const char** argv) { if (argc != 2) { - printf("Usage : compress \n"); - printf("Paramètre fichier manquant.\n"); + fprintf(stderr, "Usage : compress \n"); + fprintf(stderr, "Paramètre fichier manquant.\n"); return 1; } double* frequencies = computeFrequencies(argv[1]); double sum = 0; + printf("--- 1 : CALCUL DES FRÉQUENCES ---\n\n"); + for (int i = 0; i < 256; i++) { if (frequencies[i] != 0) { sum += frequencies[i]; - printf("%c (%d) : %f\n", i, i, frequencies[i]); + printf("%1c (%3d) : %4f\n", i, i, frequencies[i]); } } - printf("Total : %f\n", sum); + printf("Total : %f\n\n", sum); + printf("--- 2 : CONSTRUCTION DE L'ARBRE ---\n\n"); + + Tree tree = buildTree(frequencies); + printf("Arbre à %zu sommets\n\n", tree.size); + + for (int i = 0; i < tree.size; i++) { + Vertex* vertex = &tree.vertices[i]; + + printf( + "[%p] Sommet %c (%4f, %s) : parent %p\n", + (void*) vertex, vertex->value, vertex->frequency, + vertex->is_virtual ? "est virtuel" : "non virtuel", + (void*) vertex->parent + ); + } return 0; } diff --git a/src/main.o b/src/main.o deleted file mode 100644 index 42f2588..0000000 Binary files a/src/main.o and /dev/null differ