Implantation de l'algorithme de construction de l'arbre
Ajout d'un programme principal de test
This commit is contained in:
parent
ff88c32573
commit
8ce897ce33
8
Makefile
8
Makefile
|
@ -3,11 +3,11 @@ FLAGS=-Wall -std=c99
|
||||||
SRC=src
|
SRC=src
|
||||||
PROG=compress
|
PROG=compress
|
||||||
|
|
||||||
all: $(SRC)/main.o $(SRC)/huf.o
|
all: main.o huf.o
|
||||||
$(CC) $^ $(FLAGS) -o $(PROG)
|
$(CC) $^ $(FLAGS) -o $(PROG)
|
||||||
|
|
||||||
%.o: %.cpp
|
%.o: src/%.c
|
||||||
$(CC) $(FLAGS) -c $^
|
$(CC) $(FLAGS) -c $^
|
||||||
|
|
||||||
camille:
|
clean:
|
||||||
rm -f $(PROG) **/*.o **/*.gch
|
rm -f $(PROG) *.o
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
#ifndef __FREQ_H__
|
#ifndef __FREQ_H__
|
||||||
#define __FREQ_H__
|
#define __FREQ_H__
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define TRUE 1
|
||||||
|
#define FALSE 0
|
||||||
|
#define NUM_CHARS 256
|
||||||
|
|
||||||
typedef struct Vertex Vertex;
|
typedef struct Vertex Vertex;
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
// le double `freq` indique la fréquence d'apparition de la lettre
|
// 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)
|
// représente (caractère ASCII 0 - 255)
|
||||||
char value;
|
char value;
|
||||||
|
|
||||||
// pointe vers le sommet parent à celui-ci (ou bien vers NULL s'il n'a
|
// les sommets virtuels sont ceux qui ne correspondent pas à une lettre
|
||||||
// pas de parent affecté, comme c'est le cas pour les sommets non-traités
|
// du corpus, mais chapeautent les autres sommets
|
||||||
// et pour la racine)
|
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;
|
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,
|
// calcule un tableau des fréquences des caractères dans le corpus,
|
||||||
// indexé par la valeur numérique ASCII de chaque caractère
|
// indexé par la valeur numérique ASCII de chaque caractère
|
||||||
double* computeFrequencies(const char* filepath);
|
double* computeFrequencies(const char* filepath);
|
||||||
|
|
||||||
// déduit du tableau de fréquences l'arbre de Huffman, représenté
|
// déduit du tableau de fréquences l'arbre de Huffman, représenté
|
||||||
// par une liste de sommets chaînés
|
// par une liste de sommets chaînés
|
||||||
Vertex* buildTree(double* frequencies);
|
Tree buildTree(double* frequencies);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
96
src/huf.c
96
src/huf.c
|
@ -1,13 +1,14 @@
|
||||||
#include "../include/huf.h"
|
#include "../include/huf.h"
|
||||||
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
double* computeFrequencies(const char* filepath) {
|
double* computeFrequencies(const char* filepath) {
|
||||||
double* frequencies = (double*) malloc(256 * sizeof(double));
|
double* frequencies = (double*) malloc(NUM_CHARS * sizeof(double));
|
||||||
int totalChars = 0;
|
int totalChars = 0;
|
||||||
|
|
||||||
// initialisation du tableau à 0
|
// initialisation du tableau à 0
|
||||||
for (int i = 0; i < 256; i++) {
|
for (size_t i = 0; i < NUM_CHARS; i++) {
|
||||||
frequencies[i] = 0;
|
frequencies[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,30 +22,97 @@ double* computeFrequencies(const char* filepath) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// conversion des effectifs en fréquences
|
// 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;
|
frequencies[i] /= totalChars;
|
||||||
}
|
}
|
||||||
|
|
||||||
return frequencies;
|
return frequencies;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vertex* buildTree(double* frequencies) {
|
Tree buildTree(double* frequencies) {
|
||||||
int vertexCount = 0;
|
// 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
|
for (size_t i = 0; i < NUM_CHARS; i++) {
|
||||||
// (uniquement les caractères qui apparaissent au moins une fois)
|
|
||||||
for (int i = 0; i < 256; i++) {
|
|
||||||
if (frequencies[i] > 0) {
|
if (frequencies[i] > 0) {
|
||||||
vertexCount++;
|
vertex_count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// on alloue la place pour 2n + 1 sommets (nombre total
|
// allocation d'un tableau de 2n + 1 sommets, le nombre total de
|
||||||
// de sommets dans l'arbre binaire)
|
// sommets dans l'arbre binaire final
|
||||||
Vertex* tree = (Vertex*) malloc((2 * vertexCount - 1) * sizeof(Vertex));
|
size_t tree_size = 2 * vertex_count - 1;
|
||||||
|
Vertex* vertices = (Vertex*) malloc(tree_size * sizeof(Vertex));
|
||||||
|
|
||||||
// (à faire: algo pour remplir l'arbre)
|
// remplissage initial du tableau avec un sommet pour chaque lettre
|
||||||
// (trier le tableau des fréquences ?)
|
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;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
25
src/main.c
25
src/main.c
|
@ -3,22 +3,39 @@
|
||||||
|
|
||||||
int main(int argc, const char** argv) {
|
int main(int argc, const char** argv) {
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
printf("Usage : compress <fichier>\n");
|
fprintf(stderr, "Usage : compress <fichier>\n");
|
||||||
printf("Paramètre fichier manquant.\n");
|
fprintf(stderr, "Paramètre fichier manquant.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
double* frequencies = computeFrequencies(argv[1]);
|
double* frequencies = computeFrequencies(argv[1]);
|
||||||
double sum = 0;
|
double sum = 0;
|
||||||
|
|
||||||
|
printf("--- 1 : CALCUL DES FRÉQUENCES ---\n\n");
|
||||||
|
|
||||||
for (int i = 0; i < 256; i++) {
|
for (int i = 0; i < 256; i++) {
|
||||||
if (frequencies[i] != 0) {
|
if (frequencies[i] != 0) {
|
||||||
sum += frequencies[i];
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
BIN
src/main.o
BIN
src/main.o
Binary file not shown.
Loading…
Reference in New Issue