diff --git a/TP1/Java/Analyzer.java b/TP1/Java/Analyzer.java new file mode 100644 index 0000000000000000000000000000000000000000..53cffadb583c29be7d8636f391b402ecd2cb677f --- /dev/null +++ b/TP1/Java/Analyzer.java @@ -0,0 +1,132 @@ +import java.io.*; +import java.util.ArrayList; + +/** + Classe utilisée pour faire des statistiques élémentaires + sur une séquence d'opérations. + */ +public class Analyzer { + + /** + Constructeur de la classe analyse + Complexité en temps/espace, pire et meilleur cas : O(1) + */ + public Analyzer() { + cost = new ArrayList<Double>(); + cumulative_cost = new ArrayList<Double>(); + 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(double x){ + cost.add(x); + cumulative_cost.add( (!cumulative_cost.isEmpty()) ? cumulative_cost.get(cumulative_cost.size()-1)+x : x); + cumulative_square += x*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. + */ + double get_total_cost(){ + return cumulative_cost.get(cumulative_cost.size()-1); + } + + /** + 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. + */ + double get_amortized_cost(int pos){ + return (pos > 0)? cumulative_cost.get(pos)/pos : cumulative_cost.get(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. + */ + double get_average_cost(){ + if(cumulative_cost.isEmpty()) + throw new RuntimeException("List is empty"); + return cumulative_cost.get(cumulative_cost.size()-1)/cumulative_cost.size(); + } + + /** + 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. + */ + double get_variance(){ + double mean, mean_square; + mean = get_average_cost(); + mean_square = mean * mean; + return cumulative_square - mean_square; + } + + /** + 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. + */ + double get_standard_deviation(){ + return Math.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(String path){ + int i; + File file = new File(path); + FileWriter fr = null; + try { + fr = new FileWriter(file); + for (i = 0; i < cost.size(); ++i){ + fr.write(i+" "+cost.get(i)+" "+get_amortized_cost(i)+"\n"); + } + + } catch (IOException e) { + e.printStackTrace(); + }finally{ + //close resources + try { + fr.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + 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(){ + int i; + for (i = 0; i < cost.size(); ++i){ + System.out.println(i+" "+cost.get(i)+" "+get_amortized_cost(i)); + } + } + + + // Coût de chaque opération. Peut représenter du temps ou une autre mesure. + private ArrayList<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. + private ArrayList<Double> cumulative_cost; + // Carré du coût cumulatif. Sert à calculer la variance. On ne garde que la dernière valeur. + private double cumulative_square; + + +} diff --git a/TP1/Java/ArrayListProxy.java b/TP1/Java/ArrayListProxy.java new file mode 100644 index 0000000000000000000000000000000000000000..33a69553e80d945f48de97adba2602e79258ee52 --- /dev/null +++ b/TP1/Java/ArrayListProxy.java @@ -0,0 +1,96 @@ +import java.util.ArrayList; + +/** + Cette classe est un proxy pour les ArrayList, c'est à dire les tableaux dynamiques en Java. + On utilise cette classe afin d'avoir le contrôle sur la gestion de la mémoire. + */ +public class ArrayListProxy<T> { + + /** + Constructeur de la classe des tableaux dynamiques. + Complexité en temps/espace, pire et meilleur cas : O(1) + */ + public ArrayListProxy() { + this.capacity = 4; + this.data = new ArrayList<T>(this.capacity); + } + + /** + 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 + */ + boolean append(T x){ + boolean memory_allocation = false; + if( enlarging_capacity() ){ + memory_allocation = true; + capacity *= 2; + data.ensureCapacity( capacity ); + } + data.add(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 + */ + boolean pop_back(){ + boolean memory_reduction = false; + if(!data.isEmpty()){ + if( reducing_capacity() ){ + memory_reduction = true; + capacity /= 2; + data.ensureCapacity( capacity ); + } + data.remove(data.size()-1); + } + return memory_reduction; + } + + /** + Renvoie la valeur située à la position donnée par l'utilisateur. + Complexité en temps/espace, pire cas : O(1) + @param pos est la l'indice de la case on l'utilisateur veut connaître la valeur. + @returns la valeur située à la position donnée par l'utilisateur. + */ + T get(int pos){ + return data.get(pos); + } + + /** + Renvoie le nombre d'éléments stockés dans le tableau. + Complexité en temps/espace, pire cas : O(1) + @returns le nombre d'éléments stockés dans le tableau. + */ + int get_size(){ + return data.size(); + } + + /** + Cette fonction détermine la règle selon laquelle un espace mémoire plus grand sera alloué ou non. + @returns true si le tableau doit être agrandi, false sinon. + */ + private boolean enlarging_capacity() { + return data.size() >= (capacity * 3)/4; + } + + /** + Cette fonction détermine la règle selon laquelle un espace mémoire plus petit sera alloué ou non. + @returns true si le tableau doit être réduit, false sinon. + */ + private boolean reducing_capacity(){ + return data.size() <= capacity/4 && data.size() >4; + } + + // Tableau dynamique en Java. Sa capacité réelle est masquée, mais on peut avoir un contrôle dessus. + private ArrayList<T> data; + // Capacité réelle du tableau data. + private int capacity; +} \ No newline at end of file diff --git a/TP1/Java/Main.java b/TP1/Java/Main.java new file mode 100644 index 0000000000000000000000000000000000000000..f504dd54684a2253a6fb13be0469b0f230a4da13 --- /dev/null +++ b/TP1/Java/Main.java @@ -0,0 +1,42 @@ +import java.util.Random; + +public class Main { + + public static void main(String[] args) { + int i, time_ind = 0, pop_ind = 0; + // Tableau dynamique. + ArrayListProxy<Integer> a = new ArrayListProxy<Integer>(); + // Analyse du temps pris par les opérations. + Analyzer time_analysis = new Analyzer(); + // Analyse du nombre de copies faites par les opérations. + Analyzer copy_analysis = new Analyzer(); + long before, after; + // Booléen permettant de savoir si une allocation a été effectuée. + boolean memory_allocation; + + + for(i = 0; i < 1000000 ; i++){ + // Ajout d'un élément et mesure du temps pris par l'opération. + before = System.nanoTime(); + memory_allocation = a.append(i); + after = System.nanoTime(); + + // Enregistrement du temps pris par l'opération + time_analysis.append(after - before); + // 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. + copy_analysis.append( (memory_allocation == true)? i: 1); + } + + // Affichage de quelques statistiques sur l'expérience. + System.err.println("Total cost : "+time_analysis.get_total_cost()); + System.err.println("Average cost : "+time_analysis.get_average_cost()); + System.err.println("Variance :"+time_analysis.get_variance()); + System.err.println("Standard deviation :"+time_analysis.get_standard_deviation()); + + // Sauvegarde les données de l'expérience: temps et nombre de copies effectuées par opération. + time_analysis.save_values("../dynamic_array_time_java.plot"); + copy_analysis.save_values("../dynamic_array_copy_java.plot"); + + } +}