TP 4 : TRI PAR TAS INSA 2e année MIC Algorithmique & Programmation (semestre 4) 5 avril 2015 Les objectifs de ce TP sont les suivants : à manipuler le type abstrait TAS ; des algorithmes de tri (basés sur un tas, sur un arbre binaire de recherche, etc.) ; comparer ces algorithmes avec les algorithmes de tri classiques et mener une analyse critique des résultats obtenus. apprendre concevoir et développer Remarques créer un nouveau répertoire pour ce sujet de TP, les noms des chiers ne doivent pas comporter de majuscules, Ce sujet dure au maximum 2 séances de TP. Contexte On souhaite développer des algorithmes de tri en utilisant une structure de données appelée TAS. Pour cela, on va créer un paquetage générique de TAS que l'on testera avec des nombres entiers. Une fois testé le bon fonctionnement du paquetage TAS, on utilisera cette structure pour trier (ordonner de manière croissante ou décroissante) un ensemble des nombres entiers stockés dans un chier texte. Avec le même jeux des données, il faudra construire un arbre binaire que l'on utilisera, comme dans le cas du TAS, pour trier l'ensemble des nombres. Enn vous choisirez un algorithme de tri classique (BubbleSort, pour eectuer à nouveau le tri des données. SelectionSort, QuickSort, etc.) Une fois que le fonctionnement de ces trois méthodes de tri a été vérié par des tests de validité, on comparera leur ecacité respective par des tests de performance. 1 1 Paquetage générique de Tas Le tas (le de priorité) est une structure de données qui peut-être représentée par un arbre complet à gauche et qui vérie la condition d'ordre suivante : la clé d'un n÷ud est supérieur ou égale à la clé de chacun de ses ls. [votre support de cours, wikipedia.fr] La structure de ce paquetage, tas_gen, vous est fourni. Il exporte : un type Un_Tas limité privé deux exceptions : Tas_Vide, Tas_Plein les primitives : Liberer(T) : libérer la mémoire utilisée pour T. Est_Vide(T) : renvoie vrai si T est vide. Cardinal(T) : retourne le nombre courant d'éléments de T ; Enlever_Racine(T, E) : retire l'élément racine de T et la retourne ; Ajouter(E, T) : ajoute un nouvel élément E dans le TAS ; Tas_To_String(T) : convertit les éléments de T en chaine de caractères ; Le paquetage est générique sur : le type Element : c'est l'information contenue dans un n÷ud ; le type Key : le type de la clé des éléments (chaque élément a une clé unique) ; < : fonction de comparaison de deux valeurs de type Key ; Liberer_Element : procedure permettant de libérer la mémoire associée à un élément ; Element_to_string : réprésente un élément sous forme de chaîne de caractères. Travail à réaliser X Développer le corps du paquetage tas_gen (en respectant la spécication). X Tester les fonctionnalités du paquetage développé en instanciant un tas de nombres entiers ; écrivant une procédure de test de validation. 2 2 Le tri L'objectif est de comparer plusieurs méthodes de tri (tri utilisant un tas, tri utilisant un arbre binaire de recherche et tri basé sur un tableau). Le schéma ci-dessous résume le travail à réaliser : 1 TAS 6 79 56 input.txt tri 2 23 10 1,2,6,10,23,56,79,120 120 56 79 1 10 23 2 79 6 ABR 120 23 10 120 56 tri 1,2,6,10,23,56,79,120 6 algorithme de tri 2 1 1,2,6,10,23,56,79,120 Figure 1: Schéma conceptuel 2.1 Le tri par tas On va réaliser un algorithme de tri (croissant ou décroissant) de nombres entiers qui utilise un TAS préalablement créé à partir des données contenues dans un chier texte. Travail à réaliser X Créer un tas de nombres entiers à partir du chier texte data.txt donné (avant tout, vérier la structure du chier) ; X Développer un algorithme de tri par tas qui produira un tableau comme résultat du tri ; X Mémoriser le résultat du tri dans un deuxième chier text appelé output_tri_TAS.txt (voir Annexe 4.1 pour écrire dans un chier). Idées : Écrire à la n du chier le nombre d'opérations élémentaires nécessaires pour réaliser ce tri (nombres de comparaison, nombre de permutations, etc.). Écrire également à la n du chier le temps d'exécution qui a été nécessaire pour eectuer le tri. Cette information sera utile pour l'analyse comparative (voir Annexe 4.2). 2.2 Tri par arbre binaire de recherche On va réaliser un algorithme de tri (croissant ou décroissant) de nombres entiers qui utilise un ABR préalablement créé à partir de données contenues dans un chier texte. Travail à réaliser X Récupérer le paquetage arbre_bin_recherche_cle_g (développé lors des TPs précédents) et instancier un ABR pour des nombres entiers ; 3 X Créer un ABR contenant les nombres entiers lus à partir du chier texte data.txt donné ; X Développer un algorithme de tri par ABR qui produira un tableau comme résultat du tri ; X Mémoriser le résultat du tri dans un deuxième chier texte appelé output_tri_ABR.txt. Mêmes idées : Écrire à la n du chier le nombre d'opérations élémentaires nécessaires pour réaliser ce tri (nombres de comparaison, nombre de permutations, etc.). Écrire également à la n du chier le temps d'exécution qui a été nécessaire pour le tri. Cette information sera utile pour l'analyse comparative. 2.3 Algorithmes classiques de tri On va implémenter un programme contenant un algorithme de tri classique (basé sur des tableaux). Cet algorithme doit permettre de trier des nombres entiers lus dans un chier text. Rappel Un algorithme de tri (sorting algorithm ) est un algorithme qui permet d'organiser une collection d'objets selon un ordre déterminé [wiki fr]. Le tableau suivant résume les performances des principaux algorithme de tri : Nom Meilleur Cas Cas Moyenn Pire Cas O(n) O(n2 ) O(n log n) O(n) O(n log n) O(n2 ) O(n2 ) O(n log n) O(n2 ) O(n log n) O(n2 ) O(n2 ) O(n2 ) O(n2 ) O(n log n) Bubble Sort Selection Sort QuickSort Insertion Sort Merge Sort Travail à réaliser X Développer un algorithme de tri choisi parmi les classiques. Cet algorithme produira un tableau comme résultat du tri de l'ensemble des nombres entiers contenu dans data.txt ; X Mémoriser le résultat du tri dans un deuxième chier texte appelé output_tri_CL.txt. Toujours les mêmes idées : Écrire à la n du chier le nombre d'opérations élémentaires nécessaires pour réaliser ce tri (nombres de comparaison, nombre de permutation, etc.). Écrire également à la n du chier le temps d'exécution qui a été nécessaire pour le tri. Cette information sera utile pour l'analyse comparative. 3 Analyse comparative des performances L'objectif est analyser et de comparer les résultats des algorithmes développés en termes de performances. Travail à réaliser X Calculer théoriquement la complexité des trois algorithmes de tri ; X Comparer le calcul théorique avec la mesure pratique eectuée ; 4 4 Annexe 4.1 Ecriture de données dans un chier texte Pour écrire des données dans un chier texte, nous proposons d'appliquer la méthode suivante : ouvrir un chier (open) en mode lecture (out_file). écrire les valeurs, ligne apès ligne (put_line ou put suivi de new_line pour revenir à la ligne) fermer le chier (close). Pour gérer les chiers, le langage Ada propose un type prédéni appelé file_type. En supposant que le chier où l'on souhaite écrire s'appelle resu.txt, le principe général d'écriture est fourni dans le listing ci-dessous. 1 2 3 4 5 6 7 8 9 10 11 F : File_Type ; −− T e s t un t a b l e a u t r i e d ' e n t i e r s begin −− l e c t u r e Open (F , Out_File , " r e s u . t x t " ) ; Put (F , T' l e n g t h ) ; l e nombre d ' e l e m e n t s t r i e s For i in T' range loop Put (F , T( I ) ) ; New_Line (F) ; end loop ; C l o s e (F) ; end ; −− l e c t u r e Listing 1: Ecriture d'un tableau d'entiers dans un chier 4.2 Mesure du temps d'exécution Pour mesurer le temps de calcul d'un algorithme, nous proposons d'utiliser un paquetage Ada appelé Ada.Calendar. Grâce à ce paquetage, il va être possible de connaitre l'horaire de début et l'horaire de n d'un programme et donc d'en calculer sa durée. Pour plus de renseignements, consulter la documentation Ada en ligne. Le listing ci-après donne un exemple d'utilisation du paquetage Ada.Calendar. Note : cette mesure de durée n'est pas la valeur exacte de la durée mise par le programme, si votre ordinateur eectue d'autres activités en tâches de fond, cela peut fausser la mesure eectuée. Néanmoins, on se contentera de cette mesure de temps pour ce TP. 5 1 2 3 4 5 6 procedure 8 9 11 12 13 begin −− l i r e l ' h e u r e de debut Time_And_Date := Clock ; S p l i t ( Time_And_Date , Year , Month , Day , S t a r t ) ; −− a f f i c h e r l ' h e u r e de debut Put ( " Date de debut : " ) ; Put ( S t a r t , 8 , 3 , 0 ) ; New_Line ; 18 19 20 21 22 23 −− r e a l i s e r un t r a i t e m e n t for I in 0 . . 1 _000_000_000 Cpt := Cpt + 1 ; end loop ; 24 25 26 27 28 30 31 32 33 34 36 37 38 39 loop −− l i r e l ' h e u r e de f i n Time_And_Date := Clock ; S p l i t ( Time_And_Date , Year , Month , Day , Seconds ) ; −− a f f i c h e r l ' h e u r e de f i n Put ( " Date de f i n : " ) ; Put ( Seconds , 8 , 3 , 0 ) ; New_Line ; 29 35 Ada . Text_IO . Fixed_IO (DAY_DURATION) ; Cpt : I n t e g e r := 0 ; 14 17 is Year , Month , Day : INTEGER; S t a r t , Seconds : DAY_DURATION; Time_And_Date : TIME ; 10 16 Temps package Fix_IO is new use Fix_IO ; 7 15 with Ada . Text_IO , Ada . Integer_Text_IO ; use Ada . Text_IO , Ada . Integer_Text_IO ; with Ada . Calendar ; use Ada . Calendar ; −− a f f i c h e r l a d u r e e du t r a i t e m e n t Put ( " Duree de l a t a c h e : " ) ; Put ( Seconds − S t a r t , 8 , 3 , 0 ) ; New_Line ; end Temps ; 6