Commit b21b5f66 authored by Abdessamade BENYAHYA's avatar Abdessamade BENYAHYA
Browse files

tp4

parent 5c2b975a
Pipeline #4680 passed with stage
in 7 seconds
CAROUNANIDY Sylvin 11504985
BENYAHYA Abdessamade 11503336
CC= gcc
CXXFLAGS= -Wall -ansi --pedantic -O3
CPP_O_FILE = arraylist.o analyzer.o main.o
CPP_O_FILE = analyzer.o arraylist.o tas.o main.o
LIB = -lm
......
#include<stdio.h>
#include <time.h>
#include<stdlib.h>
#include "arraylist.h"
//#include "arraylist.h"
#include "tas.h"
#include "analyzer.h"
int main(int argc, char ** argv){
int i;
// Tableau dynamique.
arraylist_t * a = arraylist_create();
// Analyse du temps pris par les opérations.
analyzer_t * time_analysis = analyzer_create();
// Analyse du nombre de copies faites par les opérations.
analyzer_t * copy_analysis = analyzer_create();
// Analyse de l'espace mémoire inutilisé.
analyzer_t * memory_analysis = analyzer_create();
// Mesure de la durée d'une opération.
struct timespec before, after;
clockid_t clk_id = CLOCK_REALTIME;
// utilisé comme booléen pour savoir si une allocation a été effectuée.
char memory_allocation;
for(i = 0; i < 1000000 ; i++){
// Ajout d'un élément et mesure du temps pris par l'opération.
clock_gettime(clk_id, &before);
memory_allocation = arraylist_append(a, i);
clock_gettime(clk_id, &after);
// Enregistrement du temps pris par l'opération
analyzer_append(time_analysis, after.tv_nsec - before.tv_nsec);
// Enregistrement du nombre de copies efféctuées par l'opération.
// S'il y a eu réallocation de mémoire, il a fallu recopier tout le tableau.
analyzer_append(copy_analysis, (memory_allocation)? i:1 );
// Enregistrement de l'espace mémoire non-utilisé.
analyzer_append(memory_analysis,arraylist_capacity(a)-arraylist_size(a));
}
// Affichage de quelques statistiques sur l'expérience.
fprintf(stderr, "Total cost: %Lf\n", get_total_cost(time_analysis));
fprintf(stderr, "Average cost: %Lf\n", get_average_cost(time_analysis));
fprintf(stderr, "Variance: %Lf\n", get_variance(time_analysis));
fprintf(stderr, "Standard deviation: %Lf\n", get_standard_deviation(time_analysis));
// Sauvegarde les données de l'expérience.
save_values(time_analysis, "../plots/dynamic_array_time_c.plot");
save_values(copy_analysis, "../plots/dynamic_array_copy_c.plot");
save_values(memory_analysis, "../plots/dynamic_array_memory_c.plot");
// Nettoyage de la mémoire avant la sortie du programme
arraylist_destroy(a);
analyzer_destroy(time_analysis);
analyzer_destroy(copy_analysis);
analyzer_destroy(memory_analysis);
return EXIT_SUCCESS;
int comparer_entiers(int a, int b)
{
return b - a;
}
int main(int argc, char** argv) {
srand(time(NULL));
int i;
tas t;
// Tas
construire_tas(&t, comparer_entiers);
// Analyse du temps pris par les opérations.
analyzer_t* time_analysis = analyzer_create();
// Analyse du nombre de copies faites par les opérations.
analyzer_t* copy_analysis = analyzer_create();
// Analyse de l'espace mémoire inutilisé.
analyzer_t* memory_analysis = analyzer_create();
// Mesure de la durée d'une opération.
struct timespec before, after;
clockid_t clk_id = CLOCK_REALTIME;
// utilisé comme booléen pour savoir si une allocation a été effectuée.
char memory_allocation;
unsigned int swaps;
for (i = 0; i < 1000000u; i++) {
// Ajout d'un élément et mesure du temps pris par l'opération.
int j = rand();
clock_gettime(clk_id, &before);
swaps = arraylist_size(t.Tableau) == 0 || j > 0.75 * RAND_MAX ? inserer_element(&t, j) : retirer_element(&t, &j);
clock_gettime(clk_id, &after);
// Enregistrement du temps pris par l'opération
analyzer_append(time_analysis, after.tv_nsec - before.tv_nsec);
// Enregistrement du nombre de copies efféctuées par l'opération.
// S'il y a eu réallocation de mémoire, il a fallu recopier tout le tableau.
analyzer_append(copy_analysis, swaps);
// Enregistrement de l'espace mémoire non-utilisé.
analyzer_append(memory_analysis, t.Tableau->capacity - t.Tableau->size);
}
// Affichage de quelques statistiques sur l'expérience.
fprintf(stderr, "Total cost: %Lf\n", get_total_cost(time_analysis));
fprintf(stderr, "Average cost: %Lf\n", get_average_cost(time_analysis));
fprintf(stderr, "Variance: %Lf\n", get_variance(time_analysis));
fprintf(stderr, "Standard deviation: %Lf\n", get_standard_deviation(time_analysis));
// Sauvegarde les données de l'expérience.
save_values(time_analysis, "../plots/dynamic_binary_heap_time_0.75_c.plot");
save_values(copy_analysis, "../plots/dynamic_binary_heap_copy_0.75_c.plot");
save_values(memory_analysis, "../plots/dynamic_binary_heap_memory_0.75_c.plot");
// Nettoyage de la mémoire avant la sortie du programme
detruire_tas(&t);
analyzer_destroy(time_analysis);
analyzer_destroy(copy_analysis);
analyzer_destroy(memory_analysis);
return EXIT_SUCCESS;
}
#include<stdio.h>
#include <time.h>
#include<stdlib.h>
//#include "arraylist.h"
#include "tas.h"
#include "analyzer.h"
int comparer_entiers(void* a, void* b)
{
return *((int*)b) - *((int*)a);
}
//croiss i -> rand
//decroissant rand -> i + sign
int main(int argc, char** argv) {
srand( time( NULL ) );
int i;
tas t;
// Tas
construire_tas(&t, 1000000u, comparer_entiers);
// Analyse du temps pris par les opérations.
analyzer_t* time_analysis = analyzer_create();
// Analyse du nombre de copies faites par les opérations.
analyzer_t* copy_analysis = analyzer_create();
// Analyse de l'espace mémoire inutilisé.
analyzer_t* memory_analysis = analyzer_create();
// Mesure de la durée d'une opération.
struct timespec before, after;
clockid_t clk_id = CLOCK_REALTIME;
// utilisé comme booléen pour savoir si une allocation a été effectuée.
char memory_allocation;
unsigned int swaps;
float p = 0.75;
for (i = 0; i < t.Taille; i++)
{
// Ajout d'un élément et mesure du temps pris par l'opération.
int* j = malloc(sizeof(int));
// *j = rand();
*j = i;
clock_gettime(clk_id, &before);
// swaps = (rand() > p*RAND_MAX) ? inserer_element(&t, j) : retirer_element(&t, (void**)&j);
if ( rand() > p*(RAND_MAX))
{
swaps = inserer_element(&t, j);
}
else
{
swaps = retirer_element(&t, (void**)&j);
}
clock_gettime(clk_id, &after);
// Enregistrement du temps pris par l'opération
analyzer_append(time_analysis, after.tv_nsec - before.tv_nsec);
// Enregistrement du nombre de copies efféctuées par l'opération.
// S'il y a eu réallocation de mémoire, il a fallu recopier tout le tableau.
analyzer_append(copy_analysis, swaps);
// Enregistrement de l'espace mémoire non-utilisé.
analyzer_append(memory_analysis, t.Taille - t.Nombre);
}
// Affichage de quelques statistiques sur l'expérience.
fprintf(stderr, "Total cost: %Lf\n", get_total_cost(time_analysis));
fprintf(stderr, "Average cost: %Lf\n", get_average_cost(time_analysis));
fprintf(stderr, "Variance: %Lf\n", get_variance(time_analysis));
fprintf(stderr, "Standard deviation: %Lf\n", get_standard_deviation(time_analysis));
// Sauvegarde les données de l'expérience.
save_values(time_analysis, "../plots/fbin_heap_time_c-75.plot");
save_values(copy_analysis, "../plots/fbin_heap_copy_c-75.plot");
save_values(memory_analysis, "../plots/fbin_heap_memory_c-75.plot");
// Nettoyage de la mémoire avant la sortie du programme
detruire_tas(&t);
analyzer_destroy(time_analysis);
analyzer_destroy(copy_analysis);
analyzer_destroy(memory_analysis);
return EXIT_SUCCESS;
}
#include <stdlib.h>
#include "tas.h"
int construire_tas(tas * Tas, int (*Ordre)(int, int))
{
if ((Tas->Tableau = arraylist_create()) == NULL)
{
Tas->Ordre = NULL;
return 1;
}
else
{
Tas->Ordre = Ordre;
return 0;
}
}
void detruire_tas(tas * Tas)
{
arraylist_destroy(Tas->Tableau);
Tas->Ordre = NULL;
}
unsigned int tester_tas(const tas * Tas)
{
if (Tas->Tableau->size == 0)
{
return 1;
}
else
{
return 0;
}
}
unsigned int obtenir_pere(const tas * Tas, unsigned int Fils, unsigned int * Pere)
{
if (Fils > 0)
{
*Pere = 0.5 * (Fils - 1);
return 1;
}
else
{
return 0;
}
}
unsigned int obtenir_fils_gauche(const tas * Tas, unsigned int Pere, unsigned int * Fils)
{
if (2 * Pere + 1 < Tas->Tableau->size)
{
*Fils = 2 * Pere + 1;
return 1;
}
else
{
return 0;
}
}
unsigned int obtenir_fils_droit(const tas * Tas, unsigned int Pere, unsigned int * Fils)
{
if (2 * Pere + 2 < Tas->Tableau->size)
{
*Fils = 2 * Pere + 2;
return 1;
}
else
{
return 0;
}
}
unsigned int inserer_element(tas* Tas, int Element)
{
if (arraylist_do_we_need_to_enlarge_capacity(Tas->Tableau))
{
arraylist_enlarge_capacity(Tas->Tableau);
}
unsigned int Swaps = 0;
unsigned int Fils = Tas->Tableau->size, Pere;
Tas->Tableau->data[Fils] = Element;
while (obtenir_pere(Tas, Fils, &Pere) && Tas->Ordre(Tas->Tableau->data[Pere], Element) < 0)
{
int NouvelElement = Tas->Tableau->data[Fils];
Tas->Tableau->data[Fils] = Tas->Tableau->data[Pere];
Tas->Tableau->data[Pere] = NouvelElement;
Fils = Pere;
++Swaps;
}
Tas->Tableau->size++;
return Swaps;
}
unsigned int retirer_element(tas * Tas, int * Element)
{
if (Tas->Tableau->size > 0)
{
unsigned int Swaps = 0;
unsigned int Fils, FilsGauche, FilsDroit, Pere = 0;
*Element = Tas->Tableau->data[0];
Tas->Tableau->data[0] = Tas->Tableau->data[--Tas->Tableau->size];
while (obtenir_fils_gauche(Tas, Pere, &FilsGauche))
{
if (obtenir_fils_droit(Tas, Pere, &FilsDroit) && Tas->Ordre(Tas->Tableau->data[FilsGauche], Tas->Tableau->data[FilsDroit]) < 0)
{
Fils = FilsDroit;
}
else
{
Fils = FilsGauche;
}
if (Tas->Ordre(Tas->Tableau->data[Pere], Tas->Tableau->data[Fils]) < 0)
{
int NouvelElement = Tas->Tableau->data[Fils];
Tas->Tableau->data[Fils] = Tas->Tableau->data[Pere];
Tas->Tableau->data[Pere] = NouvelElement;
Pere = Fils;
++Swaps;
}
else
{
break;
}
}
if (arraylist_do_we_need_to_reduce_capacity(Tas->Tableau))
{
arraylist_reduce_capacity(Tas->Tableau);
}
return Swaps;
}
else
{
return -1;
}
}
#include "arraylist.h"
// Informations sur la gestion du tas.
typedef struct tas_s
{
arraylist_t* Tableau;
// Adresse de la fonction qui détermine une relation d'ordre entre les éléments du tas.
int (*Ordre)(int, int);
} tas;
// Construit un tas.
// Reçoit l'adresse du tas, la taille max du tas et un pointeur sur la fonction qui devra retourner Gauche - Droite.
// si aucune erreur n'est survenue alors retourne 0.
int construire_tas(tas *, int (*)(int, int));
// libère un tas avec l'adresse du tas en paramètre.
void detruire_tas(tas *);
// Test sur le tas et retourne 0 s'il n'est pas vide. Recois l'adresse du tas à tester
unsigned int tester_tas(const tas *);
// Permet d'avoir la position du père d'un élément dans le tas.
// Reçoit l'adresse du tas, la position de l'élément et l'adresse où sera stockée la position du père.
// si l'élément a un père retourne 1, 0 sinon.
unsigned int obtenir_pere(const tas *, unsigned int, unsigned int *);
// Permet d'avoir la position du fils gauche d'un élément dans le tas.
// Reçoit l'adresse du tas, la position de l'élément et l'adresse où sera stockée la position du fils gauche.
// si l'élément a un fils gauche retourne 1, 0 sinon.
unsigned int obtenir_fils_gauche(const tas *, unsigned int, unsigned int *);
// Permet d'avoir la position du fils droit d'un élément dans le tas.
// Reçoit l'adresse du tas, la position de l'élément et l'adresse où sera stockée la position du fils droit.
// si l'élément a un fils droit retourne 1, 0 sinon.
unsigned int obtenir_fils_droit(const tas *, unsigned int, unsigned int *);
// Insère un élément dans le tas.
// Reçoit l'adresse du tas et l'adresse de l'élément qui sera inséré.
// Retourne le tas final après insertion.
unsigned int inserer_element(tas *, int);
// Retire l'élément du tas.
// Reçoit l'adresse du tas et l'adresse où sera stockée l'adresse de l'élément retiré.
// si aucune erreur n'est survenue retourne 0.
unsigned int retirer_element(tas *, int*);
\ No newline at end of file
CC= g++
CXXFLAGS= -Wall -ansi --pedantic -g
CPP_O_FILE = analyzer.o main.o
all: $(CPP_O_FILE)
$(CC) $(CXXFLAGS) -o arraylist_analysis $(CPP_O_FILE)
clean:
rm -rf *.o
rm -rf *~
rm -rf arraylist_analysis
%.o: %.cpp
$(CC) $(CPPFLAGS) -c $< -o $@
#include "analyzer.hpp"
#include <fstream>
void Analyzer::append(const double & x){
cost.push_back(x);
cumulative_cost.push_back( (cumulative_cost.size()) ? cumulative_cost.back()+x : x);
cumulative_square += x*x;
}
long double Analyzer::get_average_cost(){
if(cumulative_cost.empty())
throw std::runtime_error("List is empty");
return cumulative_cost.back()/cumulative_cost.size();
}
long double Analyzer::get_variance(){
long double mean, mean_square;
mean = get_average_cost();
mean_square = mean * mean;
return cumulative_square - mean_square;
}
void Analyzer::save_values(const std::string & path){
std::ofstream f;
size_t i;
f.open(path.c_str());
for (i = 0; i < cost.size(); ++i)
f<<i<<" "<<cost.at(i)<<" "<<get_amortized_cost(i)<<std::endl;
f.close();
}
void Analyzer::plot_values(){
size_t i;
for (i = 0; i < cost.size(); ++i)
std::cout<<i<<" "<<cost.at(i)<<" "<<get_amortized_cost(i)<<std::endl;
}
#ifndef __ANALYZER_HPP__
#define __ANALYZER_HPP__
#include<cmath>
#include <vector>
#include <iostream>
/**
Classe utilisée pour faire des statistiques élémentaires
sur une séquence d'opérations.
*/
class Analyzer{
public:
/**
Constructeur de la classe analyse
Complexité en temps/espace, pire et meilleur cas : O(1)
*/
Analyzer():cumulative_square(0){}
/**
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 x est la valeur que l'on souhaite ajouter à l'analyse.
*/
void append(const double & x);
/**
Renvoie la somme des coûts enregistrés dans cette analyse.
Complexité en temps/espace, meilleur cas : O(1)
@returns la somme des coûts enregistrés dans cette analyse.
*/
long double get_total_cost(){
return cumulative_cost.back();
}
/**
Renvoie le coût amorti d'une opération.
Complexité en temps/espace, meilleur cas : O(1)
@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(size_t pos){
return (pos)? cumulative_cost.at(pos)/pos : cumulative_cost.at(pos);
}
/**
Renvoie la moyenne des coûts de toutes les opérations enregistrées dans l'analyse.
Complexité en temps/espace, meilleur cas : O(1)
@returns la moyenne des coûts de toutes les opérations enregistrées dans l'analyse.
*/
long double get_average_cost();
/**
Renvoie la variance des coûts de toutes les opérations enregistrées dans l'analyse.
Complexité en temps/espace, meilleur cas : O(1)
@returns la variance des coûts de toutes les opérations enregistrées dans l'analyse.
*/
long double get_variance();
/**
Renvoie l'écart-type des coûts de toutes les opérations enregistrées dans l'analyse.
Complexité en temps/espace, meilleur cas : O(1)
@returns l'écart-type des coûts de toutes les opérations enregistrées dans l'analyse.
*/
long double get_standard_deviation(){
return std::sqrt(get_variance());
}
/**
Sauvegarde la liste des coûts et des coûts amortis dans un fichier.
Complexité en temps, meilleur/pire cas : O(size)
@param path est le chemin du fichier dans lequel la sauvegarde est faite.
*/
void save_values(const std::string & path);
/**
Affiche la liste des coûts et des coûts amortis sur la sortie standard.
Complexité en temps, meilleur/pire cas : O(size)
*/
void plot_values();
private:
// Coût de chaque opération. Peut représenter du temps ou une autre mesure.
std::vector<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.
std::vector<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;
};
#endif
#ifndef __ARRAYLIST_HPP
#define __ARRAYLIST_HPP
#include<iostream>
#include<vector>
/**
Cette classe est un proxy pour les vecteurs, c'est à dire les tableaux dynamiques en C++.
On utilise cette classe afin d'avoir le contrôle sur la gestion de la mémoire.
*/
template <typename P>
class ArrayList{
public:
/**
Constructeur de la classe des tableaux dynamiques.
Complexité en temps/espace, pire et meilleur cas : O(1)
*/
ArrayList(){
data.reserve(4);
}
/**
Ajoute une valeur dans le tableau.
Complexité en temps/espace, pire cas : O(size)
Complexité en temps/espace, meilleur cas : O(1)
Complexité amortie : O(1)
@param x est la valeur que l'on souhaite ajouter.
@returns true si le tableau a été agrandit, false sinon
*/
bool append(P x){
bool memory_allocation = false;
if( do_we_need_to_enlarge_capacity() ){
memory_allocation = true;
enlarge_capacity();
}
data.push_back(x);
return memory_allocation;
}
/**
Supprime la dernière valeur du tableau.
Complexité en temps, pire cas : O(size)
Complexité en temps, meilleur cas : O(1)
Complexité amortie : O(1)
@returns true si le tableau a été réduit, false sinon
*/
bool pop_back(){
bool memory_reduction = false;
if(!data.empty()){
if( do_we_need_to_reduce_capacity() ){
memory_reduction = true;
reduce_capacity();
}
data.pop_back();