Notes de cours. Introduction

Documents pareils
1 de 46. Algorithmique. Trouver et Trier. Florent Hivert. Mél : Florent.Hivert@lri.fr Page personnelle : hivert

Les arbres binaires de recherche

Chapitre 7. Récurrences

Initiation à l algorithmique

Quelques Algorithmes simples

# 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>

Résolution de systèmes linéaires par des méthodes directes

Les structures de données. Rajae El Ouazzani

Grandes lignes ASTRÉE. Logiciels critiques. Outils de certification classiques. Inspection manuelle. Definition. Test

Introduction à MATLAB R

03/04/2007. Tâche 1 Tâche 2 Tâche 3. Système Unix. Time sharing

Exo7. Calculs de déterminants. Fiche corrigée par Arnaud Bodin. Exercice 1 Calculer les déterminants des matrices suivantes : Exercice 2.

Algorithmique I. Algorithmique I p.1/??

Algorithmique et structures de données I

Architecture des Systèmes d Information Architecture des Systèmes d Information

Quelques algorithmes simples dont l analyse n est pas si simple

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP

Exclusion Mutuelle. Arnaud Labourel Courriel : arnaud.labourel@lif.univ-mrs.fr. Université de Provence. 9 février 2011


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

ARBRES BINAIRES DE RECHERCHE

Programmer en JAVA. par Tama

Java Licence Professionnelle CISII,

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

Projet de programmation (IK3) : TP n 1 Correction

TD3: tableaux avancées, première classe et chaînes

Initiation à la programmation en Python

Algorithmes récursifs

Les algorithmes de base du graphisme

Conventions d écriture et outils de mise au point

ARDUINO DOSSIER RESSOURCE POUR LA CLASSE

1 Recherche en table par balayage

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)

Programme Compte bancaire (code)

Introduction à Java. Matthieu Herrb CNRS-LAAS. Mars

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

INTRODUCTION AUX SYSTEMES D EXPLOITATION. TD2 Exclusion mutuelle / Sémaphores

Logiciel Libre Cours 3 Fondements: Génie Logiciel

Organigramme / Algorigramme Dossier élève 1 SI

4. Groupement d objets

2. Comprendre les définitions de classes

Résolution d équations non linéaires

Programmes des classes préparatoires aux Grandes Ecoles

Corrigé des TD 1 à 5

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

Qualité du logiciel: Méthodes de test

Premiers Pas en Programmation Objet : les Classes et les Objets

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

Prénom : Matricule : Sigle et titre du cours Groupe Trimestre INF1101 Algorithmes et structures de données Tous H2004. Loc Jeudi 29/4/2004

Algorithmique et Programmation, IMA

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

ALGORITHMIQUE II NOTION DE COMPLEXITE. SMI AlgoII

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

EPREUVE OPTIONNELLE d INFORMATIQUE CORRIGE

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

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

CHAPITRE V. Recherche et tri

Recherche dans un tableau

TP, première séquence d exercices.

L exclusion mutuelle distribuée

Cours d Algorithmique-Programmation 2 e partie (IAP2): programmation 24 octobre 2007impérative 1 / 44 et. structures de données simples

INTRODUCTION A JAVA. Fichier en langage machine Exécutable

CCP PSI Mathématiques 1 : un corrigé

Cours d algorithmique pour la classe de 2nde

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

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

Souad EL Bernoussi. Groupe d Analyse Numérique et Optimisation Rabat http ://

TP1 : Initiation à Java et Eclipse

introduction Chapitre 5 Récursivité Exemples mathématiques Fonction factorielle ø est un arbre (vide) Images récursives

as Architecture des Systèmes d Information

Objets et Programmation. origine des langages orientés-objet

Algorithmique et Programmation

Utilisation d objets : String et ArrayList

Cryptologie et physique quantique : Espoirs et menaces. Objectifs 2. distribué sous licence creative common détails sur

SNT4U16 - Initiation à la programmation TD - Dynamique de POP III - Fichiers sources

SUPPORT DE COURS. Dr. Omari Mohammed Maître de Conférences Classe A Université d Adrar Courriel : omarinmt@gmail.com

Examen Médian - 1 heure 30

Algorithmique, Structures de données et langage C

Découverte de Python

Gestion mémoire et Représentation intermédiaire

Cours de Systèmes d Exploitation

LES DECIMALES DE π BERNARD EGGER

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

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

Licence Sciences et Technologies Examen janvier 2010

Problèmes liés à la concurrence

Corrigé des exercices sur les références

Ordonnancement temps réel

Temps Réel. Jérôme Pouiller Septembre 2011

IN Cours 1. 1 Informatique, calculateurs. 2 Un premier programme en C

Exercices types Algorithmique et simulation numérique Oral Mathématiques et algorithmique Banque PT

Chap 4: Analyse syntaxique. Prof. M.D. RAHMANI Compilation SMI- S5 2013/14 1

Traitement des données avec Microsoft EXCEL 2010

LMI 2. Programmation Orientée Objet POO - Cours 9. Said Jabbour. jabbour@cril.univ-artois.fr

Le Langage C Version 1.2 c 2002 Florence HENRY Observatoire de Paris Université de Versailles florence.henry@obspm.fr

#include <stdio.h> #include <stdlib.h> struct cell { int clef; struct cell *suiv; };

Initiation à LabView : Les exemples d applications :

UE C avancé cours 1: introduction et révisions

Cours d Algorithmique et de Langage C v 3.0

Transcription:

Notes de cours GEI 44 : STRUCTURES DE DONNÉES ET ALGORITHMES Chapitre 3 Algorithmes de tri 1 Introduction Tri = application fondamentale en informatique Pour effectuer un traitement donné sur des données, il existe généralement des algorithmes plus performants lorsque ces données sont triées Nous nous intéressons au tri d un tableau d éléments Nous présenterons différents algorithmes de tri Nous considérons uniquement les algorithmes s exécutant entièrement en mémoire centrale. Cela implique que le nombre d éléments à trier est relativement faible ( < quelques millions )

Importance du tri Traitement d un tableau trié est beaucoup plus facile que traitement d un tableau non trié Les résultats d un programme qui ont une taille importante sont généralement triés pour faciliter des traitements ultérieurs sur ces résultats Exemples : - Recherche dans un annuaire téléphonique - chercher numéro à partir d un nom : facile car noms triés - l inverse est pratiquement impossible car numéros non triés - Recherche dans un dictionnaire - chercher signification d un mot : facile car mots triés - l inverse est pratiquement impossible car significations non triées - Liste de fichiers dans un répertoire - Organisation des livres dans une bibliothèque 3 Contraintes imposées par algorithmes présentés Les éléments d un tableau à trier doivent être des objets qui implantent l interface Comparable ([1], page 91) qui contient deux opérations Les objets à trier doivent donc implanter les deux méthodes : lessthan et compares Soient a et b deux objets d une classe K qui implante l interface Comparable Supposons qu une relation d ordre a été définie et implantée dans K a.lessthan( b ) retourne : true si a est inférieur à b false si a est supérieur ou égal à b a.compares( b ) retourne : une valeur > 0 si a est supérieur à b une valeur = 0 si a est égal à b une valeur < 0 si a est inférieur à b 4

Tri par insertion : algorithme ([1], Sect. 4.3.1, Fig. 8.) public static void insertionsort( Comparable [ ] a ) { for( int p = 1; p < a.length; p++ ) { Comparable tmp = a[ p ]; int j = p; for( ; j > 0 && tmp.lessthan( a[ j - 1 ] ); j-- ) a[ j ] = a[ j - 1 ]; a[ j ] = tmp; Deux boucles imbriquées : - Boucle externe : au début de l itération p, les éléments dans les positions 0 à p-1 ont déjà été triés. Le but est alors : - d intégrer l élément en position p au tableau trié de taille p - d obtenir un tableau trié de taille p+1 Cette tâche est effectuée par la boucle interne - Boucle interne : Compare l élément en position p aux éléments en positions p-1, p-,, jusqu à ce que cet élément soit inséré 5 Tri par insertion : temps d exécution Soit N la taille du tableau à trier Cas général : O(N ) Si tableau initialement en ordre inverse : ( p + 1) = 1+ +... + ( N 1) = θ(n ) p 1 car à l itération p de la boucle externe, le test de la boucle interne est effectué p+1 fois Si tableau déjà trié : O(N) car à chaque itération de la boucle externe, le test de la boucle interne est effectué une seule fois Temps d exécution moyen : θ(n ) N 1 = 6

Tri par insertion : inversion Inversion : paire d éléments ( A i, A j ) d un tableau telle que : i < j et A i > A j Exemple : Le tableau { 8, 5, 9,, 6, 3 contient les dix inversions suivantes : ( 8,5 ), ( 8, ), ( 8,6 ), ( 8,3 ), ( 5, ), ( 5,3 ), ( 9, ), ( 9,6 ), ( 9,3 ), ( 6,3 ) Nombre d inversions : nombre de fois où boucle interne est effectuée Si un tableau contient O(N) inversions : alors temps d exécution de l algorithme de tri est O(N) N(N 1) Nombre moyen d inversions dans un tableau de taille N : ([1], page 6) 4 Ce qui implique que le temps moyen du tri par insertion est θ(n ) 7 Tri par permutation d éléments adjacents Tout algorithme qui effectue un tri en permutant des éléments adjacents est en moyenne Ω(N ) ([1], page 7) L algorithme de tri par insertion en est un exemple : - la permutation est effectuée implicitement - comme il est Ο(N ) et Ω(N ), alors il est θ(n ) 8

- Proposé par Donald Shell en 1959 ShellSort - Plus rapide que tri par insertion - Parmi les algorithmes plus rapides que tri par insertion : - ShellSort est le plus simple : un petit peu plus long (en code) que tri par insertion - ShellSort n est pas le plus rapide - Idée est de trier : - d abord éléments lointains - ensuite éléments moins lointains - enfin éléments adjacents (tri par insertion) - Avantage : tri d éléments lointains donne la possibilité de supprimer plusieurs inversions en une seule permutation Exemple : { 8, 5, 9,, 6, 3 Permutation entre et 8 : - supprime les inversions (8,), (9,), (5,) - ajoute inversion (9,8) 9 ShellSort : principe - Utilise une séquence h 1, h,, h t appelée séquence d incréments - Toute séquence est valide à condition que h 1 = 1 - h k -tri consiste à effectuer un tri : - en comparant chaque paire d éléments distants de h k, et - en permutant les éléments si nécessaire Donc h 1 -tri est équivalent au tri par insertion - Effectue la séquence de tri : h t -tri, h t-1 -tri, h 1 -tri - Propriété : Un tableau h k -trié qui est ensuite h k-1 -trié reste toujours h k -trié - Si h 1 1, alors il existe au moins un tableau sur lequel le ShellSort n est pas applicable - Performance de ShellSort dépend beaucoup du choix de la séquence d insertion h 1, h,, h t 10

ShellSort : exemple ([1], Fig. 8.3) ([1], Fig. 8.3) 11 ShellSort : algorithme ([1], Fig. 8.4) public static void shellsort( Comparable [ ] a ) { for( int gap = a.length / ; gap > 0; gap = gap ==? 1 : (int) ( gap /. ) ) for( int i = gap; i < a.length; i++ ) { Comparable tmp = a[ i ]; int j = i; Algorithme ressemble au tri par insertion Lignes 9-19 : Application de h k -tri, avec h k = gap Analogue au tri par insertion lorsque gap = 1 Lignes 7-8 : Boucle pour appliquer la séquence h t -tri, h t-1 -tri, h 1 -tri hi 1 si h i-1 = N avec h t = h i = h 1 = 1 hi 1 sinon. for( ; j >= gap && tmp.lessthan( a[ j - gap ] ); j -= gap ) a[ j ] = a[ j - gap ]; a[ j ] = tmp; 1

ShellSort : performance N hi h Séquence d incréments : h t =, h i-1 =... h 1 = = 1 Pire cas : O(N ) se produit si : - N= u - tous les grands éléments en positions paires - tous les petits éléments en positions impaires Chaque h k -tri consiste à trier h k ensembles de Donc complexité de h k -tri est O( h k ( ) ) = O( ) D où complexité de ShellSort est O( ) = O(N ) En moyenne : O(N 3/ ) N hk N h 1 k N hk éléments chacun N h k 13 ShellSort : performance (suite) Première amélioration : h t toujours impair h i-1 = hi hi + 1 si si hi hi impair pair Pire cas : O(N 3/ ) Amélioration due au fait que : i < t : h i et h i+1 n ont aucun facteur en commun En moyenne : O(N 5/4 ) - non démontré - basé sur des simulations 14

ShellSort : performance (suite) Seconde amélioration : h i-1 = hi. 1 si h i si h i = Temps moyen < O(N 5/4 ) et peut-être < O(N 7/6 ) - aucune base théorique - améliore performance de 5 à 35 % pour N = 10 5 à 10 6 15 ShellSort : temps d exécution ([1], Fig. 8.5) ([1], Fig. 8.5) Ce tableau confirme que : - ShellSort est plus performant que InsertionSort - Performance de ShellSort dépend de la séquence d incréments 16

Tri par fusion (MergeSort( MergeSort) Idée : - diviser pour mieux maîtriser - ensuite faire une fusion Trois étapes : 1) si nombre d items à trier est 0 ou 1, alors terminé ) trier séparément et récursivement les première et deuxième moitiés 3) fusionner les deux moitiés 17 Tri par fusion : temps d exécution Tri d un tableau de taille N se fait en un temps égal à Tt 0 Tri d un tableau de taille N/ se fait en un temps égal à Tt 1 Tri d un tableau de taille N/( k ) se fait en un temps égal à Tt k Fusionner deux tableaux triés de taille N/ se fait en un temps égal à Tf 1 Fusionner deux tableaux triés de taille N/( k ) se fait en un temps égal à Tf k On a Tt k = Tt k+1 + Tf k+1 pour k = 0, 1, D où Tt 0 = k Tt k + Tf 1 + Tf + + k Tf k avec : k N car on divise N par jusqu à ce qu on arrive à 1 Tt k est le temps pour trier un tableau de un élément (Donc Tt k 0) 18

Tri par fusion : la fusion Estimation de Tf i : temps pour fusionner deux tableaux triés de taille N/( i ) Exemple : ( [1], Sect. 8.5.1 ) soient les tableaux A et B triés suivants 1 13 4 6 A ref 15 7 38 B ref C ref Étape 1 : 1 13 4 6 15 7 38 1 A ref Étape : 1 13 4 6 B ref 15 7 38 C ref 1 A ref Étape 3 : 1 13 4 6 B ref 15 7 38 C ref 1 13 A ref B ref C ref 19 Tri par fusion : la fusion (suite) Étape 4 : 1 13 4 6 15 7 38 1 13 15 A ref Étape 5 : 1 13 4 6 B ref 15 7 38 C ref 1 13 15 4 A ref Étape 6 : 1 13 4 6 B ref 15 7 38 C ref 1 13 15 4 6 A ref B ref C ref Ensuite le reste du tableau est copié et on obtient : 1 13 15 4 6 7 38 C ref 0

Tri par fusion : temps d exécution Fusion de deux tableaux triés est donc linéaire car : - comparer deux valeurs de A et B - copier dans C une valeur de A ou B effectués : - avancer un pointeur - en temps borné par une constante - u fois, avec u = taille de chacun des deux tableaux D où : Tf i = O( N/( i ) ) i Tf i = O( N ) k i Tf i i= 1 = O( N k ) = O( N logn ) k Tf i Et alors Tt = k i Tt k + = O( N logn ) i= 1 Pire cas = cas moyen = O( N logn ) 1 Tri par fusion : algorithme de tri ([1], Fig. 8.6) public static void mergesort( Comparable [ ] a ) { Comparable [ ] tmparray = new Comparable[ a.length ]; mergesort( a, tmparray, 0, a.length - 1 ); private static void mergesort( Comparable [ ] a, Comparable [ ] tmparray, int left, int right ) { if( left < right ) { int center = ( left + right ) / ; mergesort( a, tmparray, left, center ); mergesort( a, tmparray, center + 1, right ); merge( a, tmparray, left, center + 1, right );

Tri par fusion : algorithme de fusion ([1], Fig. 8.7) Fusion de deux tableaux triés private static void merge( Comparable [ ] a, Comparable [ ] tmparray, int leftpos, int rightpos, int rightend ) { int leftend = rightpos - 1; int tmppos = leftpos; int numelements = rightend - leftpos + 1; // Main loop while( leftpos <= leftend && rightpos <= rightend ) if( a[ leftpos ].lessthan( a[ rightpos ] ) ) tmparray[ tmppos++ ] = a[ leftpos++ ]; else tmparray[ tmppos++ ] = a[ rightpos++ ]; while( leftpos <= leftend ) // Copy rest of first half tmparray[ tmppos++ ] = a[ leftpos++ ]; while( rightpos <= rightend ) // Copy rest of right half tmparray[ tmppos++ ] = a[ rightpos++ ]; // Copy TmpArray back for( int i = 0; i < numelements; i++, rightend-- ) a[ rightend ] = tmparray[ rightend ]; 3 Tri par fusion : inconvénients - Nécessite l utilisation d un tableau temporaire de taille N (tableau C) C est un problème lorsque N est grand - Temps passé dans copie entre tableau principal et tableau temporaire 4

Tri rapide (QuickSort( QuickSort) Algorithme le plus rapide parmi les algorithmes connus Temps moyen : O( N logn ) Pire cas : O( N ) peut être facilement rendu très peu probable Basé sur récursivité : ce qui le rend facile : - à comprendre - à prouver qu il est correct Petits changement dans le code peuvent grandement modifier le temps d exécution 5 Soit S le tableau à trier QuickSort L algorithme QuickSort( S ) est constitué des quatre étapes suivantes : 1) Si nombre d items à trier est 0 ou 1, alors : terminé ) Prendre n importe quel élément v de S Cet élément est appelé pivot 3) Faire la partition suivante : L = { x S { v x v L contient les éléments plus petits que le pivot R = { x S v x R contient les éléments plus grands que le pivot { v 4) Retourner : - résultat de QuickSort( L ) - v - résultat de QuickSort( R ) Tout élément peut être choisi comme pivot, mais nous verrons que certains choix sont meilleurs que d autres Si S contient v en plusieurs exemplaires, l algorithme permet de mettre ces exemplaires aussi bien dans L que dans R. Nous reviendrons sur ce point. 6

QuickSort : exemple ( [1], Fig. 8.8 ) 13 81 9 43 31 57 75 65 6 0 Choisir le pivot 13 13 0 6 43 81 31 43 75 9 57 6 0 65 Partition 57 65 31 9 QuickSort sur QuickSort sur petits éléments grands éléments 65 0 13 6 31 43 57 75 81 9 75 81 0 13 6 31 43 57 65 75 81 9 7 QuickSort : par rapport à MergeSort Ressemblances avec MergeSort - Diviser pour mieux maîtriser - Récursif Différences : - Les deux sous-problèmes : - sont de même taille avec MergeSort - ne sont pas forcément de même taille avec QuickSort Ceci est un inconvénient pour QuickSort - Étape de partition de QuickSort peut être améliorée beaucoup plus que l étape de fusion de MergeSort Cet avantage dépasse l inconvénient dû à l inégalité des tailles des deux sous-problèmes 8

Analyse de QuickSort Meilleur cas : - pivot partitionne S en deux sous-problèmes de même taille, et ceci à chaque étape de la récursivité - Temps d exécution = O( N logn ) Pire cas : - un des deux ensembles L ou R est vide, et ceci à chaque étape de la récursivité - Temps d exécution : - Soit T( N ) temps de trier S de N éléments - Hypothèse : temps pour partitionner un ensemble de N éléments N - T( i ) = T( i-1 ) + i, pour i=1,, N On obtient alors : T( N ) = N (N + 1)/ = O(N ) 9 Analyse de QuickSort : cas moyen (voir [1], pages 39-40) T(0) +... + T(N 1) T( L ) = T( R ) = N T( N ) = T( L ) + T( R ) + N À partir de ces deux équations, on peut montrer que : T(N) T(N 1) = + N + 1 N N + 1 T(N) 1 1 1 5 On peut ensuite montrer que: = (1 + + +... + ) = O( logn ) N + 1 3 N + 1 Donc le temps d exécution est O( N logn) 30

QuickSort : choix du pivot À ne pas faire : pivot est le premier ou dernier élément du tableau Si éléments initialement : - disposés aléatoirement : choix est correct - triés ou inversement triés : choix est mauvais, et temps d exécution = O(N ) Choix sécuritaire : pivot au milieu Lorsque éléments déjà triés : pivot parfait à toutes les étapes de la récursivité Choix Median-of-three : On considère les trois éléments premier, milieu et dernier du tableau On prend le median, càd celui qui n est ni le plus petit ni le plus grand des trois Par rapport au choix sécuritaire, cela apporte une légère amélioration sur le temps d exécution Lorsque la taille du tableau est paire = k, alors le milieu est le k ième élément 31 QuickSort : partition Hypothèse : aucun élément n est dupliqué Principe : consiste à mettre : - les petits éléments (< pivot) à gauche - les grands éléments (> pivot) à droite dans le tableau Utilise deux indices : i pour rechercher les grands éléments de gauche à droite j pour rechercher les petits éléments de droite à gauche Algorithme de partition : Étapes 0) Initialisations : i initialisé à la première position du tableau j initialisé à l avant dernière position du tableau 1) Échange pivot et dernier élément du tableau ) i est déplacé vers la droite jusqu à ce qu il rencontre un grand élément j est déplacé vers la gauche jusqu à ce qu il rencontre un petit élément Si i et j ne se sont pas croisés, alors inverser les items et reprendre l étape Sinon aller à l étape 3 3) Échanger l élément en position i avec le pivot 3

QuickSort : exemple de partition ([1], Fig. 8.9 à 8.15) Soit l entrée : 8 1 4 9 6 3 5 7 0 Initialement : i = 0 et j = 8 Étape 1 : ([1], Fig. 8.9) 8 1 4 9 0 3 5 7 6 Étape : i = 0 rencontre grand élément 8 j = 7 rencontre petit élément ([1], Fig. 8.10) 8 1 4 9 0 3 5 7 6 8 et sont échangés ([1], Fig. 8.11) 1 4 9 0 3 5 8 7 6 i = 3 rencontre grand élément 9 j = 6 rencontre petit élément 5 ([1], Fig. 8.1) 1 4 9 0 3 5 8 7 6 9 et 5 sont échangés ([1], Fig. 8.13) 1 4 5 0 3 9 8 7 6 33 QuickSort : exemple de partition (suite) Étape (suite) i = 6 rencontre grand élément 9 j = 5 rencontre petit élément 3 ([1], Fig. 8.14) 1 4 5 0 3 9 8 7 6 Comme i et j se sont croisés, alors on termine l étape Étape 3 On échange le pivot 6 (en position 9) avec l élément 9 (en position i=6) ([1], Fig. 8.15) 1 4 5 0 3 6 8 7 9 34

QuickSort : partition lorsque pivot en plusieurs exemplaires L étape de l algorithme devient : i est déplacé vers la droite jusqu à ce qu il rencontre un grand élément ou un élément égal au pivot j est déplacé vers la gauche jusqu à ce qu il rencontre un petit élément ou un élément égal au pivot Si i et j ne se sont pas croisés, alors inverser les items et reprendre l étape Sinon aller à l étape 3 Si on n effectue pas cette modification, on obtient un temps d exécution quadratique lorsque le pivot est en plusieurs exemplaires 35 QuickSort : partition Median-of- -of-three Voici une amélioration de la partition proposée Soient les trois éléments median-of-three (voir page 31) 1) On place : - le plus petit élément au début du tableau - le plus grand élément à la fin du tableau - le median au milieu du tableau ) On échange le pivot avec l avant dernier élément du tableau (au lieu du dernier) 3) i initialisé à la seconde position du tableau (au lieu de la première) j initialisé à l avant avant dernière position du tableau (au lieu de l avant dernière) Avantages : - i s arrêtera à coup sûr car, dans le pire cas le pivot l arrêtera - j s arrêtera à coup sûr car, dans le pire cas le premier élément l arrêtera - code simplifié - temps d exécution légèrement amélioré 36

QuickSort : tableaux de petite taille Le tri par insertion est en général plus rapide 37 QuickSort : implantation ([1], Fig. 8.19) public static void quicksort( Comparable [ ] a ) { quicksort( a, 0, a.length - 1 ); private static final int CUTOFF = 10; public static void swapreferences( Object [ ] a, int index1, int index ) { Object tmp = a[ index1 ]; a[ index1 ] = a[ index ]; a[ index ] = tmp; private static void quicksort( Comparable [ ] a, int low, int high ) { if( low + CUTOFF > high ) insertionsort( a, low, high ); else { // Sort low, middle, high int middle = ( low + high ) / ; if( a[ middle ].lessthan( a[ low ] ) ) swapreferences( a, low, middle ); if( a[ high ].lessthan( a[ low ] ) ) swapreferences( a, low, high ); if( a[ high ].lessthan( a[ middle ] ) ) swapreferences( a, middle, high ); // Place pivot at position high - 1 swapreferences( a, middle, high - 1 ); Comparable pivot = a[ high - 1 ]; // Begin partitioning int i, j; for( i = low, j = high - 1; ; ) { while( a[ ++i ].lessthan( pivot ) ) ; while( pivot.lessthan( a[ --j ] ) ) ; if( i < j ) swapreferences( a, i, j ); else break; // Restore pivot swapreferences( a, i, high - 1 ); quicksort( a, low, i - 1 ); // Sort small elements quicksort( a, i + 1, high ); // Sort large elements 38

QuickSelect But : sélectionner k ième plus petit élément d un tableau Une approche intuitive mais non performante consiste à : - trier le tableau - rechercher le k ième élément du tableau trié Le temps d exécution avec une telle approche est donc du même ordre que le temps pour trier le tableau Algorithme performant : QuickSelect - plus performant qu un algorithme de tri - Pire cas : O(N ) - Cas moyen : O(N) 39 QuickSelect : algorithme Soit : - S le tableau - k tel que on veut rechercher le k ième plus petit élément de S Algorithme QuickSelect( S, k ) : 1) Si S contient un élément alors : - k doit être égal à 1 - retour de l unique élément de S ) Prendre n importe quel élément v de S Cet élément est appelé pivot 3) Faire la partition suivante : L = { x S { v x v L contient les éléments plus petits que le pivot R = { x S { v x v R contient les éléments plus grands que le pivot 4) Si k L (ce qui implique que l élément recherché est dans L) alors on effectue un appel récursif à QuikSelect( L, k ) Sinon si k = 1+ L : alors l élément recherché est le pivot Sinon on effectue un appel récursif à QuikSelect( R, k - L - 1 ) 40

QuickSelect : implantation ([1], Fig. 8.0) public static void quickselect( Comparable [ ] a, int k ) { quickselect( a, 0, a.length - 1, k ); private static void quickselect( Comparable [ ] a, int low, int high, int k ) { if( low + CUTOFF > high ) insertionsort( a, low, high ); else { // Sort low, middle, high int middle = ( low + high ) / ; if( a[ middle ].lessthan( a[ low ] ) ) swapreferences( a, low, middle ); if( a[ high ].lessthan( a[ low ] ) ) swapreferences( a, low, high ); if( a[ high ].lessthan( a[ middle ] ) ) swapreferences( a, middle, high ); // Place pivot at position high - 1 swapreferences( a, middle, high - 1 ); Comparable pivot = a[ high - 1 ]; // Begin partitioning int i, j; for( i = low, j = high - 1; ; ) { while( a[ ++i ].lessthan( pivot ) ) ; while( pivot.lessthan( a[ --j ] ) ) ; if( i < j ) swapreferences( a, i, j ); else break; // Restore pivot swapreferences( a, i, high - 1 ); // Recurse; only this part changes if( k <= i ) quickselect( a, low, i - 1, k ); else if( k > i + 1 ) quickselect( a, i + 1, high, k ); 41