I. Introduction. II. Tri par sélection. III. Tri par insertion. IV. Tri rapide. V. Tri fusion. Algorithmes de tri. Informatique. Cours N 4.

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

1 Recherche en table par balayage

Initiation à la programmation en Python

Définitions. Numéro à préciser. (Durée : )

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

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

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

Chapitre 7. Récurrences

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

Les deux points les plus proches

Algorithmique I. Algorithmique I p.1/??

Licence Sciences et Technologies Examen janvier 2010

STAGE IREM 0- Premiers pas en Python

Quelques Algorithmes simples

Algorithmes récursifs

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

Recherche dans un tableau

# 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

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)

Logiciel Libre Cours 3 Fondements: Génie Logiciel

Corrigé des TD 1 à 5

CCP PSI Mathématiques 1 : un corrigé

Cours Informatique Master STEP

Algorithmique et Programmation, IMA

Les arbres binaires de recherche

Quelques algorithmes simples dont l analyse n est pas si simple

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

Calcul matriciel. Définition 1 Une matrice de format (m,n) est un tableau rectangulaire de mn éléments, rangés en m lignes et n colonnes.

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

Algorithmique et Programmation

Groupe symétrique. Chapitre II. 1 Définitions et généralités

Utilisation d objets : String et ArrayList

Représentation d un entier en base b

1 Définition et Appel d une fonction. V. Phan Luong. Cours 4 : Fonctions

MIS 102 Initiation à l Informatique

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP

Raisonnement par récurrence Suites numériques

Représentation des Nombres

Programmes des classes préparatoires aux Grandes Ecoles

Algorithmes et mathématiques. 1. Premiers pas avec Python. Exo Hello world!

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

Initiation à l algorithmique

Cours 1 : Introduction Ordinateurs - Langages de haut niveau - Application

Organigramme / Algorigramme Dossier élève 1 SI

Continuité et dérivabilité d une fonction

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

Cours de Systèmes d Exploitation

Introduction à MATLAB R

Chp. 4. Minimisation d une fonction d une variable

TP 1. Prise en main du langage Python

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

Découverte de Python

V- Manipulations de nombres en binaire

Probabilités sur un univers fini

MATLAB : COMMANDES DE BASE. Note : lorsqu applicable, l équivalent en langage C est indiqué entre les délimiteurs /* */.

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

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

Suites numériques 3. 1 Convergence et limite d une suite

Coefficients binomiaux

Chapitre 2 Devine mon nombre!


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

INTRODUCTION A JAVA. Fichier en langage machine Exécutable

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

Algorithmique et structures de données I

Arithmétique binaire. Chapitre. 5.1 Notions Bit Mot

BACCALAURÉAT GÉNÉRAL SESSION 2012 OBLIGATOIRE MATHÉMATIQUES. Série S. Durée de l épreuve : 4 heures Coefficient : 7 ENSEIGNEMENT OBLIGATOIRE

Algorithmique, Structures de données et langage C

Manuel d utilisation 26 juin Tâche à effectuer : écrire un algorithme 2

Présentation du langage et premières fonctions

Exercices du Cours de la programmation linéaire donné par le Dr. Ali DERBALA

Chapitre 2 Le problème de l unicité des solutions

Rappels sur les suites - Algorithme

ARBRES BINAIRES DE RECHERCHE

Projet de traitement d'image - SI 381 reconstitution 3D d'intérieur à partir de photographies

CHAPITRE V. Recherche et tri

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

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

Examen Médian - 1 heure 30

Probabilités. Rappel : trois exemples. Exemple 2 : On dispose d un dé truqué. On sait que : p(1) = p(2) =1/6 ; p(3) = 1/3 p(4) = p(5) =1/12

Probabilités sur un univers fini

Programmation linéaire

La boucle for La boucle while L utilisation du if else. while (condition) { instruction(s) }

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

Correction de l examen de la première session

Contexte. Pour cela, elles doivent être très compliquées, c est-à-dire elles doivent être très différentes des fonctions simples,

Algorithme. Table des matières

1 Introduction C+ + Algorithm e. languag. Algorigramm. machine binaire. 1-1 Chaîne de développement. Séance n 4

Résolution d équations non linéaires

Baccalauréat L spécialité, Métropole et Réunion, 19 juin 2009 Corrigé.

Fibonacci et les paquerettes

Les algorithmes de base du graphisme

avec des nombres entiers

Propagation sur réseau statique et dynamique

Ordonnancement temps réel

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

ÉPREUVE COMMUNE DE TIPE Partie D

TRIGONOMETRIE Algorithme : mesure principale

Transcription:

Informatique. Cours N 4.

L ordinateur a l intelligence de celui qui s en sert!!

1. Présentation du problème 2. Quelques définitions 3. Calcul de la médiane Trier une liste, ou un tableau à une dimension. En Python : >>>L=[5,2,4,3,1] >>>L.sort() >>>print(l) [1,2,3,4,5] Possible dès lors que l ensemble de ces objets est muni d un ordre total : >>>M=['pcsi','psi','mpsi'] >>>M.sort() >>>print(m) ['mpsi', 'pcsi', 'psi'] Nous allons présenter et comparer ici plusieurs méthodes de tri. A chaque fois : Principe Implémentation Complexité temporelle en évaluant le nombre de comparaisons entre deux élements.

1. Présentation du problème 2. Quelques définitions 3. Calcul de la médiane Définition 1.1 Un algorithme de tri permet d organiser une collection d objets selon un ordre déterminé. Les objets à trier doivent pour cela faire partie d une classe munie d une relation d ordre. Les relations d ordre les plus utilisées sont l ordre numérique et l ordre lexicographique. Définition 1.2 Un algorithme de tri est dit en place s il modifie directement la structure qu il est en train de trier. Nécessite que l objet trié soit modifiable. En Python, typiquement une liste. Intérêt principal : complexité en mémoire (ou spatiale) réduite! Définition 1.3 Un algorithme de tri d une liste est dit stable s il conserve la position relative dans la liste des quantités qui sont égales pour la relation d ordre. Exemple : on veut trier la liste de cartes T = [6, 5, 4, 5 ] Si le tri laisse le 5 avant le 5, il s agit d un tri stable, sinon il est instable : si une fois trié, on obtient : T = [4, 5, 5, 6 ], le tri est stable, si une fois trié, on obtient : T = [4, 5, 5, 6 ], le tri est instable.

1. Présentation du problème 2. Quelques définitions 3. Calcul de la médiane Pourquoi trier? Par exemple, pour faire des recherches ou encore pour déterminer la : Définition 1.4 Médiane. Soit L = [L[0], L[1],..., L[n 1]] une liste triée contenant n éléments. Lorsque n impair, il existe p N tel que n = 2p + 1, la médiane de L est l élément L[p] Lorsque n est pair, il existe p N tel que n = 2p, la médiane de L est alors la moyenne L[p 1]+L[p] des éléments L[p 1] et L[p] soit : 2 Si la liste L n est pas triée, la médiane de L est définie comme la médiane de la liste obtenue à partir de L en triant L. Si on dispose d une fonction_de_tri pour trier L, on pourra ainsi calculer avec Python : def mediane(l): """ calcule la médiane d'une liste non triée""" L=fonction_de_tri(L) #L'affectation est -elle nécessaire? n=len(l) if n%2==1: #si n=2p+1 return L[n//2] #on renvoie L[p] avec p=n//2 else: return 0.5*(L[n//2-1]+L[n//2]) #si n=2p c'est l'autre

3. Terminaison, correction, complexité Principe du tri par sélection : comme pour les photos de classe, on cherche d abord le plus petit élément du tableau que l on échange avec le premier. On applique alors de nouveau cette méthode au sous-tableau restant : recherche (et sélection) d un élément minimal : m permutation avec le premier : m T[0] tri du tableau restant : m tableau restant à trier

I. Introduction. 3. Terminaison, correction, complexité Tri par sélection (selection sort) à la main avec T = [, 3, 9, 6] : 3 9 6 3 9 6 3 6 9 3 6 9 Que penser du dernier? D où l algorithme...

3. Terminaison, correction, complexité Nous avons d abord besoin d une fonction qui calcule imin l indice du minimum de la partie du tableau comprise entre les indices j et n 1. Pour la lisibilité, rédigeons la séparément : def indice_min(t,j): """ retour l'indice du minimum du sous tableau T[j:]""" mini = j for i in range(j+1,len(t)): if T[i]<T[mini]: mini = i return mini Nous pouvons maintenant implémenter facilement le tri par sélection : def tri_selection(t): for k in range(len(t) -1): # le dernier element sera forcement trie imin = indice_min(t,k) if imin!= k: #A quoi ça sert? T[iMin],T[k] = T[k],T[iMin] return T #Par commodité (car T modifié). Ce tri est en place et stable. Ainsi implémenté, un appel direct dans la console donnera : >>> tri_selection([,3,9,6]) [3, 6,, 9]

3. Terminaison, correction, complexité Terminaison : évidente car deux boucles for imbriquées. (une pour tri_selection et une pour indice_min) qui, forcément, terminent. On peut aussi vérifier qu il n y a pas de dépassement d indice... Correction. On justifie la validité de la fonction indice_min(t,j) en prouvant par récurrence l invariant suivant : { } A la fin de la i ème itération : T[mini] = min T[l], l j, j + i On justifie la validité de la fonction tri_selection en prouvant par récurrence l invariant suivant : A la fin de la i ème itération (i N ) : T[0 : i] est trié ET k i, T[k] T[i 1]

3. Terminaison, correction, complexité Complexité. Il y a une comparaison par itération de la boucle interne (celle de indice_min). Le nombre de comparaisons de données est ainsi avec n = len(t) : n 2 n 1 k=0 i=k+1 n 2 1 = (n 1 k) = (n 1) 2 k=0 (n 1)(n 2) 2 = n(n 1) 2 n2 2 = O(n2 ) Le nombre de comparaisons est donc constant, que ce soit le pire cas, le meilleur cas, ou le cas moyen. Synthèse tri par selection : Complexité meilleur des cas O(n 2 ) cas moyen O(n 2 ) pire des cas O(n 2 ) Coût quadratique (en terme de comparaisons). Avantage : le nombre réduit d échanges effectués (au pire n 1). Il présente un intérêt sur des données coûteuses à déplacer mais aisément comparables.

I. Introduction. 3. Terminaison, correction, complexité Tri par insertion (insertion sort) de T = [, 3, 9, 6]. Principe du jeu de carte : 3 9 6 3 9 6 3 9 6 3 9 6 3 9 6 3 9 6 3 6 9 Pour mettre 6 à sa place, il a fallu successivement décaler vers la droite le 9 puis le. D où l algorithme...

3. Terminaison, correction, complexité Le code Python du tri par insertion peut donc s écrire : def tri_insertion(t): for k in range(1,len(t)): # balayage à partir du 2eme element cle = T[k] # cle represente la valeur a inserer i = k # i represente l'indice ou inserer la cle while i >= 1 and cle < T[i-1] : #insertion dans partie triee T[i] = T[i-1] # decale valeurs d'un rang vers la droite i -= 1 T[i] = cle #Place trouvée : on insere cle a l'indice i return T Comme ce tri se fait en place, le return T de la fin est facultatif mais commode. Il permet par exemple de tester directement notre fonction dans la console : >>> tri_insertion([,3,9,6]) [3, 6,, 9]

I. Introduction. Terminaison. Le programme termine car : Une boucle for termine toujours. Dans la boucle while : i est un variant de boucle. Correction. La preuve nécessite 2 invariants de boucle : un pour la boucle for : 3. Terminaison, correction, complexité A la fin de la l ème itération : k 1, l, T[k 1] T[k] un pour la boucle while : A la fin de la j ème itération : k l j, l 1, cle < T[k] Complexité. Le nombre de comparaisons pour un tableau de taille n est : Au pire : n 1 k = k=1 Au mieux : n(n 1) 2 n2 2 = O(n2 ) si liste inversée n 1 1 = n 1 = O(n) si liste déjà triée k=1

3. Terminaison, correction, complexité Synthèse tri par insertion : Complexité meilleur des cas O(n) cas moyen O(n 2 ) pire des cas O(n 2 ) Remarques. 1 Notre tri par insertion est en place : sa complexité en espace mémoire est en O(1). 2 C est un tri quadratique (donc peu efficace), cependant, on pourrait démontrer que dans le cas d un petit nombre d éléments à trier, c est le plus rapide en moyenne (hors programme). 3 Il est également très efficace lorsque le tableau est déjà presque trié car en O(n). 4 Ce n est évidemment pas le cas lorsque le tri doit être effectué sur de grands tableaux très «désordonnés».

I. Introduction. naïve 3. Terminaison, correction, complexité 4. Tri rapide en place Le tri rapide (quick sort) : tri récursif basé sur une méthode «diviser pour régner». Le principe (récent) est le suivant : Choisir arbitrairement dans le tableau un élément pivot p : p Enlever le pivot de la liste, et segmenter le tableau en deux sous-tableaux l un contenant les éléments strictement plus petits que p, l autre les élements restants supérieurs à p : < p p p Recommencer récursivement avec les tableaux situés à gauche et à droite du pivot, puis rassembler le tout : tri p tri

naïve 3. Terminaison, correction, complexité 4. Tri rapide en place Dans ce cours, le pivot p sera le dernier élément de la liste. Appliquons cet algorithme récursif à la main avec T = [6, 5, 2, 1, 3, 4]. On prend pour premier pivot 4, on obtient donc : [2, 1, 3] [4] [6, 5] Puis on prend 3 comme pivot dans la liste de gauche, et 5 dans celle de droite : En continuant ce processus, on obtient : [2, 1] [3] [] [4] [] [5] [6] [] [1] [2] [3] [] [4] [] [5] [6] Exercice d application 1 Décrire l algorithme de tri rapide en pseudo-code puis le traduire en une fonction récursive Python tri_rapide(l) qui renvoie une copie triée de la liste L passée en argument sans modifier cette liste L. Ici ce n est pas un tri en place que nous implémentons...

naïve 3. Terminaison, correction, complexité 4. Tri rapide en place Terminaison du tri rapide. Notons n la longueur de la liste à trier. Soit (u p ) la suite des longueurs maximales successives des listes passées en argument de tri_rapide. Reprenons l exemple de T = [6, 5, 2, 1, 3, 4]. On a donc u 0 = 6 puis, avec l algorithme : [2, 1, 3] [4] [6, 5] donc u 1 = 3 A l étape suivante : [2, 1] [3] [] [4] [] [5] [6] donc En continuant ce processus, on obtient : [] [1] [2] [3] [] [4] [] [5] [6] donc Pour tout p, on a u p+1 < u p du pivot, on a retiré un élément : le pivot. u 2 = 2 u 3 = 1 car même si tous les éléments restants sont du même côté La suite (u p ) est une suite strictement décroissante d entiers naturels. Elle ne prend qu un nombre fini de valeurs, ce qui signifie que la fonction récursive tri_rapide n est appelée qu un nombre fini de fois. L algorithme se termine.

naïve 3. Terminaison, correction, complexité 4. Tri rapide en place Correction du tri rapide. Par récurrence forte sur la longueur n de la liste passée en argument. Initialisation. Si n = 0 ou n = 1, la liste est déjà triée et la fonction tri_rapide ne la modifie pas. Hérédité. Soit n N, on suppose que, pour toute liste L de longueur inférieure ou égale à n, l appel tri_rapide(l) renvoie une copie triée de L. Soit L une liste de longueur n + 1. Comme n + 1 > 1, on pose p = L[ 1] et on définit deux listes L 1 et L 2 contenant les éléments de L respectivement strictement inférieur à p et supérieur à p. Ainsi L1 et L2 de longueurs inférieures où égale à n car L privée de p ne contient que n éléments. Par conséquent, l hypothèse de récurrence assure que tri_rapide(l 1 ) et tri_rapide(l 2 ) renvoient deux listes triées, l une contenant les éléments strictement plus petit que p et l autre les éléments plus grand que p. Il s ensuit que la liste concaténée tri_rapide(l 1 ) + [p] + tri_rapide(l 2 ) est bien une copie triée de la liste L de longueur n + 1.

naïve 3. Terminaison, correction, complexité 4. Tri rapide en place Complexité (en nombre de comparaisons entre les éléments de la liste). La complexité de tri_rapide dépend de la distribution autour du pivot. Notons C(n) le nombre de comparaisons lors d un appel à tri_rapide pour un tableau de longueur n. Si n 2, une fois le pivot choisi, il y a n 1 comparaisons et le tri des deux sous-listes. On obtient donc la relation de récurrence suivante : C(n) = n 1 + C(k) + C(n k 1) où 0 k n 1 avec k le nombre d éléments dans la liste L 1 (et n k 1 éléments dans L2). On peut raisonnablement penser que : le pire des cas correspond à un pivot qui est inférieur à tous les autres éléments du tableau (k = 0) ou supérieur à tous les autres éléments du tableau (k = n 1) le meilleur des cas est celui où les deux sous-tableaux ont à peu près le même nombre d éléments... Vu l algorithme du tri rapide, C(0) = 0 et C(1) = 0

naïve 3. Terminaison, correction, complexité 4. Tri rapide en place Étude de la complexité au pire. Au pire, k = 0 ou k = n 1 dans C(n) = n 1 + C(k) + C(n k 1) où 0 k n 1 Avec C(0) = 0 on obtient dans les deux cas : C(n) = C(n 1) + n 1 donc C(n) C(n 1) = n 1 En sommant pour i 1; n, on obtient par télescopage (à gauche) et décalage d indice (à droite) : Or n n n 1 C(i) C(i 1) = (i 1) C(n) C(0) = i i=1 On en déduit finalement i=1 C(0) = 0 et C(n) = n 1 i = i=0 n(n 1) 2 n(n 1) 2 = O(n 2 ) i=0

naïve 3. Terminaison, correction, complexité 4. Tri rapide en place Étude de la complexité en moyenne. Hors-programme mais... Le pivot dans la liste triée a autant de chances d être sur chacune des n places : ( ) C(n) = n 1 + 1 n 1 (C(k) + C(n k 1)) n k=0 sommes en miroir : n 1 (C(k) + C(n k 1)) = 2 n 1 C(k) k=0 k=0 En multipliant la relation ( ) par n, on obtient ainsi : n 1 n C(n) = 2 C(k) + n (n 1) relation que l on peut aussi écrire au rang précédent n 1 sous la forme : k=0 n 2 (n 1) C(n 1) = 2 C(k) + (n 1) (n 2) k=0 En soustrayant les 2 lignes précédentes, on obtient : n C(n) (n 1)C(n 1) = 2C(n 1) + n (n 1) (n 1) (n 2) n C(n) (n + 1)C(n 1) = 2(n 1) C(n) C(n 1) = 2 n 1 n + 1 n n(n + 1)

naïve 3. Terminaison, correction, complexité 4. Tri rapide en place On somme cette relation pour k 1; n. Télescopage à gauche : n k=1 C(k) C(k 1) k + 1 k = n k=1 2 k 1 k(k + 1) puis en on décompose la fraction rationnelle qui intervient côté droit : Ainsi C(n) n + 1 C(0) 1 n ( 4 = k + 1 2 ) k k=1 C(n) ( ) n + 1 = 4 H(n + 1) 1 2H(n) avec H(n) = où C(0) = 0 Or, le cours de Mathématiques 1 nous permet d écrire H(n) = ln(n) + O(1). On en déduit donc : C(n) = 2 ln(n) + O(1) n + 1 d où C(n) 2n ln(n) ( ) La complexité en moyenne du tri rapide est C(n) = O n ln(n) n k=1 1 k (la série harmonique) 1. Qui n a jamais entendu parler de la fameuse constante gamma d Euler?

naïve 3. Terminaison, correction, complexité 4. Tri rapide en place Étude de la complexité au meilleur. On obtient pour n impair la relation de récurrence : ( n ) C(n) = n 1 + 2C 2 Commençons par calculer cette complexité en des entiers de la forme 2 K 1. Pour k N, puisque n = 2 k+1 1 est impair et s écrit 2p + 1 avec p = 2 k 1 : C(2 k+1 1) = 2 k+1 2 + 2 C ( 2 k 1 ) et donc C(2 k+1 1) = 2 k+1 2 + 2 C ( 2 k 1 ) Exercice d application 2 Dans le calcul précédent de la complexité au meilleur du tri rapide, on pose pour tout k N, x k = C ( 2 k 1 ) 1 Donner la valeur de x 0, puis, pour k N, une relation entre x k+1 et x k. 2 Démontrer par récurrence que : k N, x k = (k 2)2 k + 2 Ainsi x k = O(k 2 k ) donc C(n) = O(k 2 k ) avec n 2 k c-à-d k log 2 (n). Ca ressemble (mais il reste un peu de travail) à C(n) = O(n log 2 (n))

naïve 3. Terminaison, correction, complexité 4. Tri rapide en place Synthèse Tri rapide : Complexité meilleur des cas O(n log(n)) cas moyen O(n log(n)) pire des cas O(n 2 ) Remarques. Force du tri rapide : Complexité en moyenne en O(n log(n)). Le tri rapide est aujourd hui probablement le tri le plus employé au monde! Cette complexité en moyenne en O(nlog(n)) ne peut pas être battue... La complexité au pire du tri rapide est O(n 2 )...mais on peut s adapter.

I. Introduction. 1. 2. 3. 4. Principe Implémentation naïve Terminaison, correction, complexité Tri rapide en place Tri rapide : comment partitionner en place? Reprenons l exemple du début T = [6, 5, 2, 1, 3, 4] : : trié : pivot : non trié Voici les différentes étapes de la première partition : on compare 6 et 4, 6 est plus grand, c est le premier plus grand, en position 0 ; on le permutera avec le premier élément qu on trouvera plus petit que le pivot ; on compare 5 et 4, 5 est plus grand, (c est le 2ème plus grand, en position 1) : pas d échange car on n a pas encore trouvé d élément plus petit que le pivot ; on compare 2 et 4, 2 est plus petit, on le permute avec le premier plus grand (ici 6) : 6 5 2 1 3 4 2 5 6 1 3 4

I. Introduction. 1. 2. 3. 4. Principe Implémentation naïve Terminaison, correction, complexité Tri rapide en place Compare 1 et 4, 1 est plus petit, on permute avec le 1er plus grand (qui est 5 ici) : 2 5 6 1 3 4 2 1 6 5 3 4 Compare 3 et 4, 3 est plus petit, on permute avec le 1er plus grand (qui est 6 ici) : 2 1 6 5 3 4 2 1 3 5 6 4

I. Introduction. 1. 2. 3. 4. Principe Implémentation naïve Terminaison, correction, complexité Tri rapide en place Le premier «tri» est terminé, on pose le pivot (ici 4) à sa position, c est à dire à la place du premier plus grand (ici 5) : 2 1 3 5 6 4 2 1 3 4 6 5 Le pivot est à sa place. En effet les termes placés avant lui sont strictement inférieurs et les termes placés après lui sont supérieurs. Il reste alors à trier récusrivement les sous-tableaux situés à la gauche et à la droite du pivot.

naïve 3. Terminaison, correction, complexité 4. Tri rapide en place Algorithme de tri rapide en place (composé de deux fonctions.) D abord partition(t,debut,fin) prend en arguments un tableau T, un indice de début et un indice de fin. Elle segmente le tableau T[debut :fin] et renvoie l indice de la place du pivot. def partition(t,debut,fin): """ retourne l'indice du pivot dans T[debut:fin] et partitionne """ pivot = T[fin -1] k = debut #place du 1er plus grand for i in range(debut,fin -1): if T[i] < pivot: T[i],T[k] = T[k],T[i] #on échange (parfois pour rien...) k += 1 T[fin -1],T[k] = T[k],T[fin -1] return k Pour T = [6,5,2,1,3,4] partition(t,0,6) renvoie... Mais la liste T a été modifiée et T =... Exercice d application 3 Écrire la fonction principale tri_rapide2(t,debut,fin) qui renvoie trié le tableau T[ debut : fin ] en utilisant la fonction partition. C est une fonction récursive! Ce tri est en place mais il n est pas stable.

I. Introduction. 3. Terminaison correction complexité VI. Synthèse Le tri fusion (merge sort) utilise aussi une approche «diviser pour régner» : on partage le tableau de taille n en deux parties de tailles égales (à une unité près lorsque n impair) que l on trie par un appel récursif, puis on fusionne les deux parties triées. Cet algorithme repose donc sur une fonction auxiliaire, la fonction de fusion. liste L1 triée liste L2 triée fusion Notre fonction de fusion prendra en argument deux listes triées L1 et L2 et renverra la liste fusionnée. Remarque. C est possible (mais complexe) de l implémenter en place.

3. Terminaison correction complexité VI. Synthèse Phases d empilage et de dépilage des appels récursifs sur un exemple : 33 27 54 16 31 14 33 27 33 27 33 27 54 16 31 14 54 16 31 14 54 16 31 14 33 27 54 16 31 14 33 27 16 54 14 31 27 33 14 16 31 54 14 16 27 31 33 54 Détaillons la dernière fusion du schéma précédent pour bien comprendre.

I. Introduction. 3. Terminaison correction complexité VI. Synthèse Pour réaliser cette fusion de L1 et L2, on utilise un tableau temporaire M. A l issue de la procédure, le tableau M sera clairement de longueur len(l1) + len(l2). : trié : en cours de tri : non trié 27 33 14 16 31 54 27 33 14 16 31 54 14

I. Introduction. 27 33 14 16 31 54 14 16 27 33 14 16 31 54 14 16 27 27 33 14 16 31 54 14 16 27 31 3. Terminaison correction complexité VI. Synthèse

I. Introduction. 27 33 14 16 31 14 16 27 31 33 27 33 14 16 31 54 14 16 27 31 33 54 3. Terminaison correction complexité VI. Synthèse 54 Exercice d application 4 1 En s appuyant sur l exemple précédent, proposer en pseudo-code un algorithme qui fusionne deux listes L1 et L2 triée en une liste M triée. 2 Décrire l évolution de l état des variables de cet algorithme lors de son appel sur l exemple ci-dessus.

3. Terminaison correction complexité VI. Synthèse fusion(l1,l2) permet de fusionner deux listes triées au préalable en une seule liste triée. def fusion(l1,l2): """ fusionne deux listes triées en une seule liste triée""" M = [None]*(len(L1)+len(L2)) # on initialise la liste temporaire i,j = 0,0 # on initialise les indices de chaque morceau for k in range(len(l1)+len(l2)): #on remplit la liste fusionnee if i == len(l1): # cas ou il ne reste plus que L2 M[k] = L2[j] j += 1 elif j == len(l2): # cas ou il ne reste plus que L1 M[k] = L1[i] i += 1 elif L1[i] <= L2[j]: # on compare les plus petits des 2 listes M[k] = L1[i] i += 1 else: M[k] = L2[j] j += 1 return M On peut tester notre fonction dans la console : >>> fusion([,27,33],[14,16,31,54]) [, 14, 16, 27, 31, 33, 54]

3. Terminaison correction complexité VI. Synthèse Remarque La position relative de deux éléments équivalents n est pas modifiée, ce qui permettra d avoir une fonction de tri stable. La fonction principale tri_fusion(t) gère les appels récursifs. Elle prend en argument un tableau T et renvoie une copie triée de T en utilisant la fonction fusion. def tri_fusion(t): if len(t) <2: return T else: L1=tri_fusion(T[:len(T)//2]) #tri de la moitié gauche L2=tri_fusion(T[len(T)//2:]) #tri de la moitié droite return fusion(l1,l2) #on fusionne et on renvoie On peut tester notre fonction dans la console : >>> T = [33,27,,54,16,31,14] >>> tri_fusion(t) [, 14, 16, 27, 31, 33, 54]

3. Terminaison correction complexité VI. Synthèse Terminaison des deux fonctions précédentes : fusion et tri_fusion. Il est clair que fusion termine car elle ne fait appel qu à une boucle for. La fonction récursive tri_fusion ne fait rien si le tableau a 0 ou 1 élément. Sinon tri_fusion s appelle elle-même avec des tableaux de taille strictement inférieure : En effet, pour n la longueur de la liste T à trier, en appelant (u p ) la suite définie par u 0 = n et u p la longueur maximale des listes passées en argument de tri_fusion à up+1 l étape p, on a (pour u p pair ou impair) la relation de récurrence u p+1 = 2. Ainsi, tant que u p > 1, up + 1 2 u p + 1 < u p c-à-d u p+1 < u p 2 donc la suite (u p ) est une suite strictement décroissante d entiers naturels. Elle prend un nombre fini de valeurs supérieures ou égales à 1 donc la fonction tri_fusion n est appelée qu un nombre fini de fois. La fonction tri_fusion termine donc.

3. Terminaison correction complexité VI. Synthèse Correction. Preuve à envisager pour chacune des deux fonctions fusion et tri_fusion : Pour la fonction fusion, on peut considérer l invariant de boucle suivant : la liste M est triée et les éléments de M sont inférieurs ou égaux aux éléments de L1 et L2 non parcours. Pour tri_fusion, on s en sort (comme pour le tri rapide) grâce à un raisonnement par récurrence forte sur la longueur n de la liste à trier.

3. Terminaison correction complexité VI. Synthèse Complexité. Commençons par détailler la complexité de la fonction fusion en nombre de comparaisons des éléments de deux listes triées L1 et L2 de longueurs k et l (avec n = k + l taille du tableau fusionné et k l 1). Le pire des cas est celui où la liste fusionnée M reçoit alternativement un élément de L1 puis un élément de L2. Il y aura dans ce cas k + l 1 = n 1 comparaisons. Le meilleur des cas est celui où tous les éléments d une des listes L1 ou L2 sont inférieurs au minimum de l autre liste (donc à tous les éléments de cette autre liste). Il y aura dans ce cas min(k, l) comparaisons. Dans les deux cas, pour un tableau fusionné M de taille n, on a une complexité en O(n).

3. Terminaison correction complexité VI. Synthèse Pour la fonction récursive tri_fusion, en notant C(n) le nombre de comparaisons lors d un appel pour un tableau de longueur n, on obtient la relation de récurrence : ( n ) ( n ) C(n) = C + C + O(n) le O(n) provenant de l appel à fusion. 2 2 Dans le cas particulier où n = 2 p, cette relation devient donc : C(2 p ) = 2C(2 p 1 ) + O(2 p ) ce que l on peut encore écrire en divisant par 2 p C(2 p ) : 2 p = C(2p 1 ) 2 p 1 + O(1) Comme pour la complexité du tri rapide, une sommation pour k 1, p donne : p k=1 C(2 k ) 2 k C(2k 1 ) 2 k 1 = p O(1) k=1 donc par télescopage C(2 p ) 2 p C(20 ) 2 0 = O(p) Il est clair que C(2 0 ) = C(1) = 0 et donc que : C(2p ) 2 p = O(p) puis C(2 p ) = O(p2 p ) soit pour n = 2 p et donc p = log 2 (n) la relation : C(n) = O(n log(n)) Pour passer à n quelconque, il faut justifier la croissance de n C(n) en prouvant, à l aide d une récurrence forte, la propriété P(n) : C(n) C(n + 1). Complexité dans tous les cas en O(n log(n)).

3. Terminaison correction complexité VI. Synthèse Synthèse pour le tri fusion : meilleur des cas cas moyen pire des cas Complexité O(n log(n)) O(n log(n)) O(n log(n)) Remarques. 1 Avantage du tri fusion : sa complexité est la même dans tous les cas! Il n y a pas de cas où sa complexité est en O(n 2 ) (comme le pire des cas du tri rapide). 2 Inconvénient du tri fusion présenté ici : ce n est pas un tri en place. 3 Expérimentalement, il est moins bon que le tri rapide!

3. Terminaison correction complexité VI. Synthèse

3. Terminaison correction complexité VI. Synthèse