Mesures de performance exemple des tris



Documents pareils
Cours de Programmation Impérative: Zones de mémoires et pointeurs

Travaux pratiques. Compression en codage de Huffman Organisation d un projet de programmation

Recherche dans un tableau

PROBLEMES D'ORDONNANCEMENT AVEC RESSOURCES

Généralités sur le Langage Java et éléments syntaxiques.

Chapitre 10. Les interfaces Comparable et Comparator 1

TP n 2 Concepts de la programmation Objets Master 1 mention IL, semestre 2 Le type Abstrait Pile

Chapitre 2. Classes et objets

Java Licence Professionnelle CISII,

I. Introduction aux fonctions : les fonctions standards

Pour signifier qu'une classe fille hérite d'une classe mère, on utilise le mot clé extends class fille extends mère

INF2015 Développement de logiciels dans un environnement Agile. Examen intra 20 février :30 à 20:30

as Architecture des Systèmes d Information

Mesurer les performances (CPU) sous Linux

Seconde et première Exercices de révision sur les probabilités Corrigé

Conventions d écriture et outils de mise au point

Introduction. I Étude rapide du réseau - Apprentissage. II Application à la reconnaissance des notes.

Bases de programmation. Cours 5. Structurer les données

Programme Compte bancaire (code)

Cours intensif Java. 1er cours: de C à Java. Enrica DUCHI LIAFA, Paris 7. Septembre Enrica.Duchi@liafa.jussieu.fr

# let rec concat l1 l2 = match l1 with [] -> l2 x::l 1 -> x::(concat l 1 l2);; val concat : a list -> a list -> a list = <fun>

Le langage C++ est un langage de programmation puissant, polyvalent, on serait presque tenté de dire universel, massivement utilisé dans l'industrie

Seance 2: En respectant la méthode de programmation par contrat, implémentez les autres fonctions de jeu.

Plan du cours. Historique du langage Nouveautés de Java 7

RapidMiner. Data Mining. 1 Introduction. 2 Prise en main. Master Maths Finances 2010/ Présentation. 1.2 Ressources

UEO11 COURS/TD 1. nombres entiers et réels codés en mémoire centrale. Caractères alphabétiques et caractères spéciaux.

Cours 1: Java et les objets

Encapsulation. L'encapsulation consiste à rendre les membres d'un objet plus ou moins visibles pour les autres objets.

Compression de Données - Algorithme de Huffman Document de Conception

INTRODUCTION A JAVA. Fichier en langage machine Exécutable

Langage Java. Classe de première SI

1.6- Génération de nombres aléatoires

Corrigé des exercices sur les références

Langage et Concepts de ProgrammationOrientée-Objet 1 / 40

Lambda! Rémi Forax Univ Paris-Est Marne-la-Vallée

LE PROBLEME DU PLUS COURT CHEMIN

Dossier projet isn 2015 par Victor Gregoire

EPREUVE OPTIONNELLE d INFORMATIQUE CORRIGE

DE L ALGORITHME AU PROGRAMME INTRO AU LANGAGE C 51

Les arbres binaires de recherche

Utilisation d objets : String et ArrayList

Licence Bio Informatique Année Premiers pas. Exercice 1 Hello World parce qu il faut bien commencer par quelque chose...

Programmation Objet Java Correction

Algorithmique I. Algorithmique I p.1/??

1/24. I passer d un problème exprimé en français à la réalisation d un. I expressions arithmétiques. I structures de contrôle (tests, boucles)

Machines Virtuelles. et bazard autour. Rémi Forax

Arbres binaires de recherche

Exceptions. 1 Entrées/sorties. Objectif. Manipuler les exceptions ;

INITIATION AU LANGAGE JAVA

Projet L1, S2, 2015: Simulation de fourmis, Soutenance la semaine du 4 mai.

CH.6 Propriétés des langages non contextuels

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP

Programmation C++ (débutant)/instructions for, while et do...while

Java - la plateforme

MISE A NIVEAU INFORMATIQUE LANGAGE C - EXEMPLES DE PROGRAMMES. Université Paris Dauphine IUP Génie Mathématique et Informatique 2 ème année

Projet ISN - dossier réalisé par Randrianarimanana Stéphanie. Titre du projet : Site de rencontre. le nom de notre site de rencontre : Linkymeet

Structure d un programme et Compilation Notions de classe et d objet Syntaxe

Centre CPGE TSI - Safi 2010/2011. Algorithmique et programmation :

Algorithmique avec Algobox

1. Structure d un programme C. 2. Commentaire: /*..texte */ On utilise aussi le commentaire du C++ qui est valable pour C: 3.

OS Réseaux et Programmation Système - C5

Classe ClInfoCGI. Fonctions membres principales. Gestion des erreurs

Pourquoi l apprentissage?

CORRECTION EXERCICES ALGORITHME 1

TD/TP PAC - Programmation n 3

Cours Programmation Système

Les chaînes de caractères

Annexe : La Programmation Informatique

Initiation à la programmation en Python

Propagation sur réseau statique et dynamique

TP : Shell Scripts. 1 Remarque générale. 2 Mise en jambe. 3 Avec des si. Systèmes et scripts

Complexité. Licence Informatique - Semestre 2 - Algorithmique et Programmation

SHERLOCK 7. Version du 01/09/09 JAVASCRIPT 1.5

Prendre le marteau, le tableau, le mètre, le crayon, la ficelle, le clou, la pointe ;

Rappel. Analyse de Données Structurées - Cours 12. Un langage avec des déclaration locales. Exemple d'un programme

Cours 1 : Introduction. Langages objets. but du module. contrôle des connaissances. Pourquoi Java? présentation du module. Présentation de Java

Cours d initiation à la programmation en C++ Johann Cuenin

Programmer en JAVA. par Tama

Cours de C++ François Laroussinie. 2 novembre Dept. d Informatique, ENS de Cachan

Premiers Pas en Programmation Objet : les Classes et les Objets

Algorithmique, Structures de données et langage C

Chapitre VI- La validation de la composition.

Introduction au langage C

Ebauche Rapport finale

Info0101 Intro. à l'algorithmique et à la programmation. Cours 3. Le langage Java

Probabilités sur un univers fini

Développement d'un projet informatique

TRUECRYPT SUR CLEF USB ( Par Sébastien Maisse 09/12/2007 )

Auto-évaluation Programmation en Java

TD Objets distribués n 3 : Windows XP et Visual Studio.NET. Introduction à.net Remoting

Solutions du chapitre 4

POKER ET PROBABILITÉ

ACTIVITÉ DE PROGRAMMATION

Programmation en Java IUT GEII (MC-II1) 1

Introduction à Java. Matthieu Herrb CNRS-LAAS. Mars

ALGORITHMIQUE ET PROGRAMMATION En C

Introduction à JDBC. Accès aux bases de données en Java

Exercices sur les interfaces

RECOMMANDATION 27 EFFICACITE DE LA COMMUNICATION, ENTRE LES CANAUX DE DISTRIBUTION ET LES ASSUREURS, ET RECIPROQUEMENT.

Algorithmique et Programmation, IMA

Transcription:

IUT De Villetaneuse Dép t informatique Cours d'algorithmique 2 éme Année Cours 7 Mesures de performance exemple des tris Les tris On a un ensemble de données que l'on veut trier. Les données sont dans un tableau de taille n. En pratique, n est de l'ordre des millier, ou même des millions. La plupart des algorithmes s'astreignent donc à ne pas demander d'espace supplémentaire et à procéder par permutation (échange d'éléments) dans le tableau. Deux tris naïfs Exemple1 : tri par recherche du maximum Le principe de l'algorithme est le suivant : on cherche dans le tableau le plus grand élément ; on le met en place (il doit devenir le dernier) en le permutant avec le dernier ; puis on recommence avec le tableau sauf le dernier (le terme technique pour recommencer est : itérer). L'évolution de l'algorithme est plus facile à comprendre si l'on regarde l'état du tableau à la fin de la kieme itération. : les k plus grands éléments sont déjà à leur place définitive. Au début du programme : Tous les éléments en désordre dans le tableau k ième itération entrée 64444447444448 n k +1 éléments en désordre 64447448 k-1 plus grands éléments 1444444244443 sortie n-k éléments en désordre k plus grands éléments La kieme itération se contente de choisir le plus grand élément dans la partie non triée, et de le mettre en place donc la taille de la partie triée augmente de 1. Au bout de n itérations, le tableau est trié. Le temps consommé peut être estimé : - temps pour rechercher le maximum dans un tableau de taille t : - temps pour permuter 2 éléments : - temps pour les n itérations : Donc on a une complexité en O(n 2 ) : si on trie 10 fois plus d'éléments, le temps de calcul est multiplié par environ Si l'on trie 500 éléments en 1s, il faudra pour en trier 50 000 environ Page 1/6

Exemple 2 : tri à bulles Le principe est le suivant : on compare tour à tour chaque élément avec son voisin, et on les échange si ils ne sont pas dans l'ordre. On s'arrête quand il n'y a plus d'échange possible. Cette première idée n'est en fait pas assez précise pour définir un algorithme : après une comparaison (et peut-être un échange) on n'a pas dit quel doit être la suivante. Dans le tri à bulle, on parcourt tout le tableau du début à la fin. Puis on revient au début pour une nouvelle itération, On s'arrête quand une itération n'a donné lieu à aucun échange. Le tri à bulles n'est pas très efficace. Nous ne prendrons pas le temps d'analyser sa complexité, mais elle est en O(n 2 ). Pour en avoir une idée, on peut regarder ce qui se passe quand le tableau de départ est trié à l'envers. Deux améliorations importantes Exemple 3 : tri par tas C'est la même idée que le tri par recherche du maximum : à chaque itération, on trouve le plus grand et on le met à sa place. Mais on réutilise l'idée qui nous a servi dans les files de priorité : si on organise bien les données en arbre, on trouve le plus prioritaire en Log n au lieu de n, y compris la réorganisation de l'arbre il suffit de dire que le plus prioritaire est le plus grand. Prélever les n éléments du tableau l'un après l'autre est de complexité O(n Log n). Il faut aussi compter le temps pour organiser les données, ce qu'on peut faire en créant une file de priorité vide puis en y insérant les données l'une après l'autre. Comme chaque insertion est de complexité O(Log n) (moins en fait, puisque le nombre de nœuds de l'arbre dans lequel on insère n'est pas n), l'ensemble est encore en O(n Log n). Comme les données sont dans un tableau, on réutilisera facilement l'autre idée du cours 5 : implémenter la file de priorité dans un tableau (donc la file de priorité sera un tas). Au départ les données sont comme toujours en désordre dans le tableau. On a 2 phases : i) construire le tas en insérant les nœuds un par un ii) tri par recherche du maximum dans un tas : prélever le plus grand élément et le mettre à la fin, à la place de la feuille qui sert à reconstruire le tas. Phase i : Au début : k ième étape Tous les éléments en désordre dans le tableau entrée 644444474444448 tas de taille k-1 sortie k iéme feuille 1444444424444443 tas de taille k Page 2/6

Phase ii : Au début : k ième étape plus grand élément Tous les éléments du tableau forment un tas entrée 644444474444448 tas de taille n k +1 k-1 plus grands éléments 64447448 1444444244443 sortie tas de taille n-k k plus grands éléments Quand on a implémenté correctement une file de priorité dans un tableau, écrire un tri à bulle ne demande que quelques lignes de code. On a pourtant beaucoup gagné : si l'on multiplie le nombre de données par 100, on multiplie le temps par moins de 100.log 2 (100) 600 (au lieu de 10000 pour le tri par recherche du maximum). Exemple 4 : Tri à bulles à pas variable A chaque échange, le nombre fait un pas vers sa place définitive (ou parfois en sens contraire). Dans le tri à bulles, tous les pas sont de une case. Pour améliorer cela, le tri à bulles à pas variable utilise un principe dichotomique : au début, les pas sont les plus longs possibles. Puis quand une itération ne change plus rien, on divise le pas par deux. On termine avec un pas de 1, mais on a été plus vite. Des optimisations sont possibles : si l'on choisit comme pas initial une puissance de 2, chaque étape avec un pas n/2 se contente d'interclasser n/2 fois deux séries déjà classées. étape de pas n étape de pas n/2 Donc chaque itération range correctement au moins un élément à chaque extrémité de la série, soit n/2 éléments à chaque extrémité pour une itération de pas n/2. On peut réduire le parcours de l'itération de n à chaque fois, et cela limite aussi le nombre d'itérations Mesurer les performances Les calculs de complexité donnent une idée des performances moyennes d'un algorithme. Une technique complémentaire consiste à mesurer les performances d'un programme, dans la réalité, pendant qu'il tourne. C'est un moyen très important de mise au point. Trouver un jeu de tests C'est la première tâche. On ne mesure jamais sur un seul exemple, parce que le résultat peut être du au hasard et n'avoir que très peu de signification. Chaque exemple s'appelle un test, un ensemble d'exemples utilisés ensemble s'appelle un jeu de tests. Il faut choisir des jeux de test représentatifs de la réalité pour que les mesures soient valables. C'est un point délicat (qui se pose aussi dans les tests d'absence de bug). On a deux grandes approches. Page 3/6

Tests sur données réelles On dispose parfois (par exemple dans les archives d'une entreprise) de données tout à fait analogues à celles que l'on aura à traiter. On peut essayer le programme sur ces données anciennes pour voir si on obtient un résultat correct dans un temps acceptable. Jeux de tests aléatoires L'autre solution consiste à fabriquer un ou plusieurs jeux de tests en tirant au sort la valeur des données. Une série de nombres pseudo aléatoire est une série telle qu'un humain ou une machine qui ne connaît pas la fonction qui les engendre peut difficilement prévoir la suite. On dispose maintenant de fonctions bien faites pour générer des séries de nombres pseudo aléatoires. En Java, la fonction Math.random() (renvoie un double entre 0 et 1). La classe Random a des méthodes nextint(), nextfloat(), etc. qui fournissent des séries pseudoaléatoires de tous les types primitifs sauf char et String. Vérifier que les jeux de test aléatoires que l'on va générer sont représentatifs demande une étude précise. Nous nous contenterons pour l'instant de méthodes approchées. Mesurer le temps utilisé par le programme La façon la plus simple de connaître le temps mis par le programme pour s'exécuter, c'est de regarder l'heure au début et à la fin! En Java, la classe System dispose d'une méthode long currenttimemillis() qui donne l'heure au millième de seconde près. C'est une méthode simple, mais rudimentaire : presque toutes nos machines sont multitâches et multiutilisateur. Le temps mesuré a en fait été partagé avec d'autres processus dont on ne sait rien, et on peut obtenir un temps élevé parce qu'un autre utilisateur a lancé un gros calcul! De plus, on ne fait pas la distinction entre le temps de calcul et le temps d'entrée/sortie. En C, on mesure le temps en positionnant un timer qui envoie un signal à intervalle régulier. On dispose de trois timers, selon que l'on veut mesurer le temps réel, le temps de calcul ou le temps de (calcul + Entrées/Sorties). Compter le nombre d'opérations Il faut au départ écrire le code en exécutant les opérations importantes dans des fonctions. Par exemple, au lieu de coder pour un tri (on suppose pour l'exemple qu'on trie des entiers qui sont dans tabint[]) : if (tabint[i] < tabint[j]) { code qu'on risque de retrouver plusieurs fois dans l'algorithme, il vaut mieux écrire : boolean before(int i, int j) { return tabint[i] < tabint[j] ; void swap(int i, int j) { if (before(i,j) swap(i,j) ; C'est plus lisible, on ne réécrira pas plusieurs fois les comparaisons et les affectations, donc on a moins de chance de faire une erreur. De plus, on peut très facilement étudier le comportement du programme en comptant le nombre de comparaisons et de permutations (en général, le nombre d'opérations de chaque sorte). Page 4/6

En Java : Dans la classe qui implante la méthode de tri, ajouter deux variables membres nbcompare et nbpermute de type protected int et initialisées à 0. Modifier le code de before() et de swap() : boolean before(int i, int j) { nbcompare++ ; return tabint[i] < tabint[j] ; void swap(int i, int j) { nbpermute++ ; à la fin du tri, afficher nbcompare et nbpermute En C On utilise des variables statiques de portée locale (elles sont initialisées à 0 et ont une durée de vie permanente, mais ne sont accessibles que dans la fonction) ; boolean before(int i, int j) { static int nbcompare ; nbcompare++ ; return tabint[i] < tabint[j] ; void swap(int i, int j) { static int nbpermute ; nbpermute++ ; Ce code n'est pas tout à fait complet : il faut prévoir un mécanisme pour récupérer les résultats, par exemple un appel de fonction avec un argument spécial [ici, ( 1,-1) convient bien]. Profiler un programme Profiler, c'est utiliser un outil système pour suivre l'exécution du programme et faire des statistiques sur le temps passé dans chaque fonction ou partie de programme. En C, on compile avec l'option pg, par exemple gcc pg headtail.c. Quand on exécute a.out, l'exécution engendre un fichier de trace gmon.out. On peut alors voir des statistiques de comportement des fonctions avec gprof a.out. le tableau qui suit a été obtenu en lançant un tri à bulles sur un tableau de 10000 entiers. (f) veut dire : fonction seule ; (f&d) abrège : fonction et descendants. % temps secondes secondes appels nbre moyen nbre moyen nom [index] (f) cumulées (f & d) seul (f) de ms par appel (f) de ms par appel (f&d) 14,8 10.13 10.13 99150084 0.00 0.00 _greater[4] 5,6 32.63 3.85 1 3850.00 32630.00 _tri[3] 27,3 18.57 18.57 24784824 0.00 0.00 _swap[5] 0.0 35.38 0.01 1 10.00 35380.00 _init[6] 0.0 68.12 0.00 1 0.00 35380.00 _main[1] Page 5/6

On peut ainsi mesurer quelles sont les parties du programme le plus souvent utilisées et celles qui consomment le plus de temps, donc celles qu'il est le plus important d'améliorer. Dans l'exemple, l'arborescence des appels est : main init tri random greater swap Tout le temps consommé par init() l'est en fait par la fonction de bibliothèque random() qui n'est pas tracée. swap() consomme 2 fois plus de temps que greater() qui pourtant est appelé 4 fois plus. À eux deux ils représentent 90% du temps de tri(). A moins d'améliorer leur implémentation (en codant par exemple en assembleur), on ne peut pas gagner grand chose ici sur le codage. Mais le profilage ne montre pas qu'on peut améliorer l'algorithme! En java : le JDK comporte une API de profilage mais pas d'utilitaire pour profiler. Page 6/6