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 | ||||
| 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 | ||||
|  |  | |||
|  | @ -1,6 +1,12 @@ | |||
| #ifndef __FREQ_H__ | ||||
| #define __FREQ_H__ | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| #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 | ||||
|  |  | |||
							
								
								
									
										96
									
								
								src/huf.c
								
								
								
								
							
							
						
						
									
										96
									
								
								src/huf.c
								
								
								
								
							|  | @ -1,13 +1,14 @@ | |||
| #include "../include/huf.h" | ||||
| #include <assert.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| 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; | ||||
| } | ||||
|  |  | |||
							
								
								
									
										25
									
								
								src/main.c
								
								
								
								
							
							
						
						
									
										25
									
								
								src/main.c
								
								
								
								
							|  | @ -3,22 +3,39 @@ | |||
| 
 | ||||
| int main(int argc, const char** argv) { | ||||
| 	if (argc != 2) { | ||||
| 		printf("Usage : compress <fichier>\n"); | ||||
| 		printf("Paramètre fichier manquant.\n"); | ||||
| 		fprintf(stderr, "Usage : compress <fichier>\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; | ||||
| } | ||||
|  |  | |||
							
								
								
									
										
											BIN
										
									
								
								src/main.o
								
								
								
								
							
							
						
						
									
										
											BIN
										
									
								
								src/main.o
								
								
								
								
							
										
											Binary file not shown.
										
									
								
							
		Loading…
	
		Reference in New Issue