Commit 47d80cb3 authored by MARRAKCHI Ghassen's avatar MARRAKCHI Ghassen
Browse files

Première version du rapport

parent 3ac4f361
Pipeline #4665 failed with stage
in 9 seconds
#include"analyzer.h"
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
analyzer_t * analyzer_create(){
analyzer_t * res = (analyzer_t *) malloc( sizeof(analyzer_t) );
res->capacity = 4;
res->cost = (double *) malloc( sizeof(double) * res->capacity );
res->cumulative_cost = (long double *) malloc( sizeof(long double) * res->capacity );
res->cumulative_square = 0.;
res->size = 0;
return res;
}
void analyzer_destroy(analyzer_t * a){
if( a != NULL ){
free( a->cost );
free( a->cumulative_cost );
free( a );
}
}
void analyzer_append(analyzer_t * a, double x){
if( a!=NULL ){
if( a->size >= (a->capacity * 3)/4 ){
a->capacity *= 2;
a->cost = (double *) realloc(a->cost, sizeof(double) * a->capacity*2);
a->cumulative_cost = (long double *) realloc(a->cumulative_cost, sizeof(long double) * a->capacity*2);
}
a->cost[a->size] = x;
a->cumulative_cost[a->size] = (a->size) ? a->cumulative_cost[a->size-1]+x : x;
a->cumulative_square += x*x;
a->size++;
}
}
long double get_total_cost(analyzer_t * a){
return (a->size) ? a->cumulative_cost[a->size-1] : -1;
}
long double get_amortized_cost(analyzer_t * a, size_t pos){
if(pos >= 0 && pos < a->size)
return (pos)? a->cumulative_cost[pos]/pos : a->cumulative_cost[pos];
return -1;
}
long double get_average_cost(analyzer_t * a){
if(a->size)
return a->cumulative_cost[a->size - 1]/a->size;
return -1;
}
long double get_variance(analyzer_t * a){
long double mean, mean_square;
if(a->size){
mean = get_average_cost(a);
mean_square = mean * mean;
return a->cumulative_square - mean_square;
}
return -1;
}
long double get_standard_deviation(analyzer_t * a){
if(a->size)
return sqrt(get_variance(a));
return -1;
}
void save_values(analyzer_t * a, char * path){
FILE * f;
int i;
if( (f = fopen(path, "w")) != NULL ){
for (i = 0; i < a->size; ++i){
fprintf(f,"%d %lf %Lf\n", i, a->cost[i], get_amortized_cost(a, i));
}
}else{
fprintf(stderr, "Could not save values in file %s", path);
}
}
void plot_values(analyzer_t * a){
int i;
for (i = 0; i < a->size; ++i){
printf("%d %lf %Lf\n", i, a->cost[i], get_amortized_cost(a, i));
}
}
#ifndef __ANALYZER_H__
#define __ANALYZER_H__
#include <stddef.h>
/**
Structure utilisée pour faire des statistiques élémentaires
sur une séquence d'opérations.
*/
typedef struct analyzer_s{
// Coût de chaque opération. Peut représenter du temps ou une autre mesure.
double * cost;
// Coût cumulatif. La case i contient la somme des coûts des i premières opérations.
// Permet de calculer le coût amorti d'une opération.
long double * cumulative_cost;
// Carré du coût cumulatif. Sert à calculer la variance. On ne garde que la dernière valeur.
long double cumulative_square;
// Capacité de stockage des tableaux
size_t capacity;
// Nombre d'éléments dans chaque tableaux.
size_t size;
} analyzer_t;
/**
Fonction d'initialisation d'une analyse.
Complexité en temps/espace, pire et meilleur cas : O(1)
@return Un pointeur sur une structure analyzer_t nouvellement allouée.
*/
analyzer_t * analyzer_create();
/**
Fonction de libération de la mémoire occupée par une analyse.
Complexité en temps/espace, pire et meilleur cas : O(1)
@param a est un pointeur vers l'espace mémoire que la fonction va libérer.
*/
void analyzer_destroy(analyzer_t * a);
/**
Ajoute un coût, une valeur à l'analyse.
Complexité en temps/espace, pire cas : O(size)
Complexité en temps/espace, meilleur cas : O(1)
Complexité amortie : O(1)
@param a est l'analyse à laquelle on souhaite ajouter une valeur.
@param cost est la valeur que l'on souhaite ajouter.
*/
void analyzer_append(analyzer_t * a, double cost);
/**
Renvoie la somme des coûts enregistrés dans cette analyse.
Complexité en temps/espace, pire cas : O(1)
@param a est une analyse.
@returns la somme des coûts enregistrés dans cette analyse.
*/
long double get_total_cost(analyzer_t * a);
/**
Renvoie le coût amorti d'une opération.
Complexité en temps/espace, pire cas : O(1)
@param a est une analyse.
@param pos est l'indice de l'opération pour laquelle on veut connaître le coût amorti.
@returns le coût amorti d'une opération.
*/
long double get_amortized_cost(analyzer_t * a, size_t pos);
/**
Renvoie la moyenne des coûts de toutes les opérations enregistrées dans l'analyse.
Complexité en temps/espace, pire cas : O(1)
@param a est une analyse.
@returns la moyenne des coûts de toutes les opérations enregistrées dans l'analyse.
*/
long double get_average_cost(analyzer_t * a);
/**
Renvoie la variance des coûts de toutes les opérations enregistrées dans l'analyse.
Complexité en temps/espace, pire cas : O(1)
@param a est une analyse.
@returns la variance des coûts de toutes les opérations enregistrées dans l'analyse.
*/
long double get_variance(analyzer_t * a);
/**
Renvoie l'écart-type des coûts de toutes les opérations enregistrées dans l'analyse.
Complexité en temps/espace, pire cas : O(1)
@param a est une analyse.
@returns l'écart-type des coûts de toutes les opérations enregistrées dans l'analyse.
*/
long double get_standard_deviation(analyzer_t * a);
/**
Sauvegarde la liste des coûts et des coûts amortis dans un fichier.
Complexité en temps, meilleur/pire cas : O(size)
@param a est l'analyse que l'on souhaite sauvegarder.
@param path est le chemin du fichier dans lequel la sauvegarde est faite.
*/
void save_values(analyzer_t * a, char * path);
/**
Affiche la liste des coûts et des coûts amortis sur la sortie standard.
Complexité en temps, meilleur/pire cas : O(size)
@param a est l'analyse que l'on souhaite sauvegarder.
*/
void plot_values(analyzer_t * a);
#endif
<hr>
<div style="display:flex;align-items:center;flex-direction:column;">
<img src="./institut-Galilee.png"/>
<img src="./Institut-Galilee.png"/>
<h1 style="text-align:center;color:#5b84b3">Structure de Données Avancée</h1>
<span style="color:#c4c1d9"><i>Ghassen <strong>MARRAKCHI</strong></i></span>
</div>
<hr>
<h2 style="text-align:center;color:#7494c4">TP 3</h1>
<h2 style="text-align:center;color:#7494c4">TP 5 : Tas Binomial</h1>
<hr>
<h3 style="color:##7C7C7C"> I- Présentation brève de la structure de données utilisée</h3>
<h3 style="color:##7C7C7C"> I- Choix du langage</h3>
<p>
Un tas binaire est un tableau qui peut être vu comme un arbre binaire comme le montre les images ci-dessous :
</p>
<div style="display:flex;align-items:center;flex-direction:row;">
<img src="./tas-binaire-format-tableau.png" style="width:50px"/>
<img src="./tas-binaire-format-arbre.png" style="width:50px"/>
</div>
<p>
Un tas est caractérisé par sa longueur qui représente sa capacité (le nombre maximal d'élements qu'il peut contenir) et sa taille qui représente le nombre d'élement du tas. Il est dit borné si sa capacité est fixe comme dans notre cas.
En plus de la rapidité accrue, le langage C permet une meilleure gestion de la mémoire.
</p>
<h3 style="color:##7C7C7C"> II- Représentation de la structure de donnée</h3>
<h4 style="color:##7C7C7C"> 1- Noeud du tas</h4>
<p>
Un tas en général vérifie un certain nombre de caractéristques:
On a créé le noeud comme étant une structure "<i>struct node_s</i>" qui contient :
<ul>
<li>longueur du tas >= taille du tas</li>
<li>parent de l'élement numéro i est à la i/2 ème position</li>
<li>parent de l'élement numéro i est à la 2i ème position</li>
<li>parent de l'élement numéro i est à la 2i + 1 ème position</li>
<li>la clé du noeud</li>
<li>le degré du noeud</li>
<li>un pointeur sur le parent</li>
<li>un pointeur sur le frère à gauche</li>
<li>un pointeur sur le fils le plus à droite</li>
</ul>
</p>
<p>
Il faut noter qu'il existe deux type de tas, selon la proprieté fondamentale qu'il vérifie :
<ul>
<li>si parent de l'élement numéro i est inférieur au i ème élement, alors le tas est dit minimal.</li>
<li>si parent de l'élement numéro i est supérieur au i ème élement, alors le tas est dit maximal.</li>
</ul>
On a ensuite créé le type comme étant la structure du noeud "<i>node_t</i>".
</p>
<h3 style="color:##7C7C7C"> II- Expériences effectuées</h3>
<h4 style="color:##7C7C7C"> 2- le Tas</h4>
<p>
Nous avons implémenter un benchmark qui effectue trois expériences différents sur les deux types de tas en même temps :
On a créé le tas comme étant une structure "<i>struct binomial_heap_s</i>" qui contient :
<ul>
<li>Ajout croissant : on ajoute n élements ordonnés dans l'ordre croissant allant de 1 jusqu'à n.</li>
<li>Ajout décroissant : on ajoute n élements ordonnés dans l'ordre décroissant allant de n jusqu'à 1.</li>
<li>Ajout aléatoire : on ajoute n élements NON-ordonnés compris entre 1 et n.</li>
<li>un pointeur vers le premier noeud du tas</li>
</ul>
</p>
<h3 style="color:##7C7C7C"> III- Analyse des résultats des experiences</h3>
<h4 style="color:##7C7C7C"> 1- Courbes de temps amorti</h4>
<p>
D'abord, on remarque l'analogie entre les courbes d'ajout croissant et décroissant. Analysons l'exemple des ajouts croissant :<br>
On remarque que le temps amorti pour les ajouts croissants dans un tas minimal est plus grand que celui du tas maximal. Ceci est dù au nombre de swap (permutations) dont la courbe sera analysée dans ce qui suit.
De plus on remarque un caractère asymptotique qui nous rappelle de la complexité temporelle devant être théoriquement O(log n) au pire et au meilleur des cas.
On a ensuite créé le type comme étant la structure du tas "<i>binomial_heap_t</i>".
</p>
<p>
Pour le cas d'ajout aléatoire on remarque une NON-régularité dans le tracé de la courbe ce qui est expliquable par les données de permutation. Cependant, on note une corrélation entre les courbes des tas minimal et maximal.
Il faut noter qu'on peut aussi utiliser le type "<i>node_t</i>" pour toutes les opérations puisque le tas n'est rien d'autre qu'une liste chainée des noeuds racines des arbres binomiaux.<br>
Cependant, on a préféré créer le type du tas afin de pouvoir différencier les appels des pointeurs dans le code.
</p>
<h4 style="color:##7C7C7C"> 2- Courbes de mémoire gaspillée</h4>
<h3 style="color:##7C7C7C"> III- Fonctions</h3>
<p>
Comme expliqué ci-dessus, dans notre cas nous avons implémenté un tas binaire borné. Ainsi, si on ajoute à chaque itération un élement, l'espace de mémoire libre décroit linéairement comme le mettent en évidence toutes les courbes.
Hormis le fait qu'on nous ait demandé d'implémenter les trois opérations de bases (fusion de tas, ajout de noeud et extraction du min), plusieurs autres fonctions sont créées afin de faciliter la lecture du code et son maintenance.
</p>
<h4 style="color:##7C7C7C"> 3- Courbes de permutations (SWAP)</h4>
<h4 style="color:##7C7C7C"> 1- Noeud du tas</h4>
<p>
Pour la courbe d'ajout croissant, on remarque que le nombre de swap est croissant pour le tas minimal et totalement absent pour le tas maximal (Aucune permutation n'est effectuée).
Cela est expliquable par le fait que l'ajout croissant vérifie la condition du tas max tel que le i ème élement est supérieur au i+1 ème élement.
Ainsi, chaque élement ajouté à la fin du tableau vérifie la proprieté de tas maximal (le i ème élement est supérieur au parent de celui-ci) à savoir qu'il est supérieur à son parent ce qui ne nécessite aucune permutation.<br>
Pour la courbe d'ajout décroissant, les mêmes caractéristiques sont remarquées avec un raisonnement inversé à savoir que le tas max est celui qui effectue le plus de permutation d'élements.<br>
De plus, on peut remarquer une caractéristique intéressante dans les deux cas à savoir que le nombre de permutations se stabilise pour 2<sup>k</sup> élements ajoutés (2, 4, 8, 16 ..).
Les fonctions suivantes agissent sur les noeuds ou sur des listes chainées (les arbres binomiaux) :
</p>
<p>
Pour la courbe aléatoire, la non régularité de la courbe est le resultat attendu. En effet, chaque fois que l'on ajoute un élement, on ne peut pas prédire le nombre de permutation à effectuer.
Cela est du à la dépendance de ce dernier de la position de l'element à ajouter.<br>
De plus, on peut dire que les deux types de tas possèdent le même comportement.
<ul>
<li> Fonction d'initialisation d'un noeud.
</li>
<li> Relie deux arbres binomiaux de même ordre (k-1).
</li>
<li>
Inverse la liste des enfants d'une racine.
</li>
<li>
Fonction de libération de la mémoire occupée par un noeud.
</li>
</ul>
</p>
<h4 style="color:##7C7C7C"> 2- le Tas</h4>
<p>
Les fonctions suivantes agissent sur les tas :
</p>
<p>
<ul>
<li> Fonction d'initialisation d'un tas binomial (ne contenant aucun noeud).
</li>
<li> Fonction de libération de la mémoire occupée par un tas binomial.
</li>
<li>
Renvoie un poitnteur sur le noeud dont la clé est minimale.
</li>
<li>
Unir deux tas binomiaux.
</li>
<li>
Renvoie un poitnteur sur le noeud dont la clé est minimale et définit le pointeur du noeud qui le précède.
</li>
<li>
Insère un noeud dans le tas.
</li>
<li>
Extrait la noeud dont la clé est minimale du tas.
</li>
<li>
Fusionner les deux listes de racines (les tas h1 et h2)
</li>
<li>
Affiche le tas.
</li>
</ul>
</p>
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment