TD 7 : Algorithmes de tri - Diviser pour régner PC/PC* - Lycée Thiers Exercice 1 : Algorithme de tri Exercice 2 : Le tri par insertion Exercice 3 : Tri rapide Exercice 4 : Tri fusion Exercice 1 : Algorithme de tri Enoncé Correction Exercice 2 : Le tri par insertion Enoncé Corrigé Exercice 3 : Tri rapide Enoncé Corrigé Exercice 4 : Tri fusion Enoncé Corrigé PC/PC* - Lycée Thiers TD 7 : Algorithmes de tri - Diviser pour régner Exercice 1 : Algorithme de tri Exercice 2 : Le tri par insertion Exercice 3 : Tri rapide Exercice 4 : Tri fusion Enoncé Correction Exercice 1 : Algorithme de tri Un algorithme de Tri prend en paramètre un tableau d’éléments d’ordonnables, par exemple une liste de nombres et renvoie le tableau trié dans le sens croissant. Exercice 1. Écrire un algorithme de tri de son choix. Quels sont sa complexité dans le pire des cas ? Dans le meilleur des cas ? PC/PC* - Lycée Thiers TD 7 : Algorithmes de tri - Diviser pour régner Exercice 1 : Algorithme de tri Exercice 2 : Le tri par insertion Exercice 3 : Tri rapide Exercice 4 : Tri fusion Enoncé Correction Exercice 1 : Algorithme de tri ● Le tri par sélection : def triSelection(T): """Algorithme de tri par sélection""" N = len(T) # Balayage for k in range(N-1): # Recherche du minimum à partir de k ind = k for i in range(k,N): if T[i] < T[ind]: ind = i # Placement du minimum à l’indice k T[ind], T[k] = T[k], T[ind] return T de complexité quadratique dans le pire et le meilleur des cas. PC/PC* - Lycée Thiers TD 7 : Algorithmes de tri - Diviser pour régner Exercice 1 : Algorithme de tri Exercice 2 : Le tri par insertion Exercice 3 : Tri rapide Exercice 4 : Tri fusion Enoncé Correction Exercice 1 : Algorithme de tri ● Le tri à bulle : def triBulle(T): """Tri à bulle""" N = len(T) chgt = True while chgt: for k in range(N-1): chgt = False if T[i]>T[i+1]: T[i], T[i+1] = T[i+1], T[i] chgt = True N -= 1 return T ● Complexité linéaire dans le meilleur des cas (pour un tableau déjà trié), quadratique dans le meilleur des cas. PC/PC* - Lycée Thiers TD 7 : Algorithmes de tri - Diviser pour régner Exercice 1 : Algorithme de tri Exercice 2 : Le tri par insertion Exercice 3 : Tri rapide Exercice 4 : Tri fusion Enoncé Corrigé Exercice 2 : Le tri par insertion Exercice 2. Tri par insertion. C’est celui que l’on utilise habituellement dans la vie courante, par exemple, pour trier un paquet de carte : On constitue (imaginairement) 2 tas : – l’un dans la main droite, contenant toutes les cartes avant tri, – l’autre dans la main gauche, contenant les cartes déjà triées, Initialement la main gauche est vide. Chaque étape consiste à : – prendre la première carte du tas non trié – L’insérer progressivement à sa bonne place dans le tas trié, en la faisant descendre d’une position tant que sa valeur reste inférieure à celle de la carte située en dessous-d’elle. Après chaque étape le tas non trié contient une carte de moins, le tas trié une carte de plus. A la fin du tri la main droite est vide. La main gauche contient toutes les cartes, triées. PC/PC* - Lycée Thiers TD 7 : Algorithmes de tri - Diviser pour régner Exercice 1 : Algorithme de tri Exercice 2 : Le tri par insertion Exercice 3 : Tri rapide Exercice 4 : Tri fusion Enoncé Corrigé Exercice 2 : Le tri par insertion PC/PC* - Lycée Thiers TD 7 : Algorithmes de tri - Diviser pour régner Exercice 1 : Algorithme de tri Exercice 2 : Le tri par insertion Exercice 3 : Tri rapide Exercice 4 : Tri fusion Enoncé Corrigé Exercice 2 : Le tri par insertion 1. Ecrire une fonction triInsertion prenant en paramètre une liste de nombres et qui applique un tri par insertion pour le trier dans le sens croissant. 2. Quel invariant de boucle permet de justifier qu’à la fin de l’algorithme le tableau est trié ? 3. Complexité dans le meilleur des cas : quel est le meilleur des cas ? Quelle est alors la complexité ? 4. Complexité dans le pire des cas : quel est le pire des cas ? Quelle est alors la complexité ? PC/PC* - Lycée Thiers TD 7 : Algorithmes de tri - Diviser pour régner Exercice 1 : Algorithme de tri Exercice 2 : Le tri par insertion Exercice 3 : Tri rapide Exercice 4 : Tri fusion Enoncé Corrigé Exercice 2 : corrigé def triInsertion(T): """Tri par insertion""" N = len(T) # Balayage for k in range(1,N): # Insertion i = k while i > 0 and T[i-1] > T[i]: T[i-1], T[i] = T[i], T[i-1] i -= 1 return T ● Invariant de boucle : ”Après k insertions les k premiers éléments du tableau sont ordonnés dans le sens croissant.” (pour la boucle for). PC/PC* - Lycée Thiers TD 7 : Algorithmes de tri - Diviser pour régner Exercice 1 : Algorithme de tri Exercice 2 : Le tri par insertion Exercice 3 : Tri rapide Exercice 4 : Tri fusion Enoncé Corrigé Exercice 2 : corrigé Version optimisée : def triInsertion(T): """Tri par insertion""" N = len(T) # Balayage for k in range(1,N): # Insertion x = T[i] i = k while i > 0 and T[i-1] > x: T[i-1] = x i -= 1 T[i] = x return T ● Invariant de boucle : ”Après k insertions les k premiers éléments du tableau sont ordonnés dans le sens croissant.” (pour la boucle for). PC/PC* - Lycée Thiers TD 7 : Algorithmes de tri - Diviser pour régner Exercice 1 : Algorithme de tri Exercice 2 : Le tri par insertion Exercice 3 : Tri rapide Exercice 4 : Tri fusion Enoncé Corrigé Exercice 2 : corrigé ● Meilleur des cas : celui d’un tableau déjà trié. La complexité est linéaire (chaque insertion est en O(1)). ● Pire des cas : celui d’un tableau ordonné dans le sens décroissant : complexité quadratique : la k-ième insertion se fait en Θ(k). N−1 N−1 ∑ Θ(k) = Θ ( ∑ k) = Θ ( k=1 k=1 PC/PC* - Lycée Thiers N(N − 1) ) = Θ(N 2 ) . 2 TD 7 : Algorithmes de tri - Diviser pour régner Exercice 1 : Algorithme de tri Exercice 2 : Le tri par insertion Exercice 3 : Tri rapide Exercice 4 : Tri fusion Enoncé Corrigé Exercice 3 : Tri rapide Ce tri particulièrement rapide, est basé sur le principe de diviser pour régner : – Choisir arbitrairement un élément e dans le tableau T, e – Décomposer les autres éléments du tableau en deux sous-tableaux : – T- constitué des éléments inférieurs à e, – T+ constitué des éléments supérieurs à e. T- e T+ – Après appels récursifs sur les deux sous-tableaux T- et T+, le tableau T trié s’obtient en concaténant les sous-tableaux T- trié, suivi de e, suivi de T+ trié. T- trié e T+ trié Le tableau T est alors trié. PC/PC* - Lycée Thiers TD 7 : Algorithmes de tri - Diviser pour régner Exercice 1 : Algorithme de tri Exercice 2 : Le tri par insertion Exercice 3 : Tri rapide Exercice 4 : Tri fusion Enoncé Corrigé Exercice 3 : Tri rapide Exemple : (1) Tri rapide à la main de [7, 3, 6, 4, 2, 5, 1] : – Appel sur T = [7, 3, 6, 4, 2, 5, 1] e = 4, T1 = [3, 2, 1], T2 = [7, 6, 5] – Appel récursif sur T1 = [3, 2, 1] : e = 2, T11 = [1], T12 = [3] Ô⇒ T1 devient : T11 + [2] + T12 = [1, 2, 3] – Appel récursif sur T2 = [7,6,5] e = 6, T21 = [5], T22 = [7] Ô⇒ T2 devient : T21 + [6] + T22 = [5,6,7] Ô⇒ T devient : T1 + [4] + T2 = [1,2,3,4,5,6,7] PC/PC* - Lycée Thiers TD 7 : Algorithmes de tri - Diviser pour régner Exercice 1 : Algorithme de tri Exercice 2 : Le tri par insertion Exercice 3 : Tri rapide Exercice 4 : Tri fusion Enoncé Corrigé Exercice 3 : Tri rapide 1. Ecrire une fonction triRapide prenant en paramètre une liste de nombres T et qui renvoie un tableau trié contenant les mêmes éléments que T. 2. Lorsque l’élément e est chaque fois choisi médian, quelle et la complexité de l’algorithme ? 3. Lorsque l’élément e est chaque fois choisi extremal, quelle est la compléxité de l’algorithme ? PC/PC* - Lycée Thiers TD 7 : Algorithmes de tri - Diviser pour régner Exercice 1 : Algorithme de tri Exercice 2 : Le tri par insertion Exercice 3 : Tri rapide Exercice 4 : Tri fusion Enoncé Corrigé Exercice 3 : Corrigé def TriRapide(T): N = len(T) if N <= 1: return T e = T.pop(N//2) T1, T2 = [], [] for x in T: if x <= e: T1.append(x) else: T2.append(x) return TriRapide(T1) + [e] + TriRapide(T2) PC/PC* - Lycée Thiers TD 7 : Algorithmes de tri - Diviser pour régner Exercice 1 : Algorithme de tri Exercice 2 : Le tri par insertion Exercice 3 : Tri rapide Exercice 4 : Tri fusion Enoncé Corrigé Exercice 3 : Corrigé Dans le meilleur des cas, lorsque l’élément choisi est médian : N N/2 N/2 N/4 ⋮ 1 N/4 ⋮ 1 1 ⋮ 1 1 N/4 ⋮ 1 1 ⋮ 1 PC/PC* - Lycée Thiers 1 N/4 ⋮ 1 1 ⋮ 1 1 ⋮ 1 TD 7 : Algorithmes de tri - Diviser pour régner 1 1 Exercice 1 : Algorithme de tri Exercice 2 : Le tri par insertion Exercice 3 : Tri rapide Exercice 4 : Tri fusion Enoncé Corrigé Exercice 3 : Corrigé La profondeur de l’arbre est log2 (N) puisque : N = 2log2 (N) . De l’ordre de N opérations à chaque étage. Ô⇒ C (N) = Θ ⎛log2 (N) k N ⎞ ∑ 2 × k = Θ ((log2 (N) + 1) × N) = Θ(N log(N)) 2 ⎠ ⎝ k=0 Dans ce cas la complexité est en N log(N). PC/PC* - Lycée Thiers TD 7 : Algorithmes de tri - Diviser pour régner Exercice 1 : Algorithme de tri Exercice 2 : Le tri par insertion Exercice 3 : Tri rapide Exercice 4 : Tri fusion Enoncé Corrigé Exercice 3 : Corrigé Dans le pire des cas, lorsque l’élément choisi est toujours un élément extrémal (min ou max) : N N −1 1 1 N −k 1 1 1 1 PC/PC* - Lycée Thiers TD 7 : Algorithmes de tri - Diviser pour régner Exercice 1 : Algorithme de tri Exercice 2 : Le tri par insertion Exercice 3 : Tri rapide Exercice 4 : Tri fusion Enoncé Corrigé Exercice 3 : Corrigé La profondeur de l’arbre est N. De l’ordre de N − k opérations à chaque ”étage” k. N Ô⇒ C (N) = Θ ( ∑ n) = Θ (N × n=1 (N + 1) ) = Θ (N 2 ) 2 complexité quadratique PC/PC* - Lycée Thiers TD 7 : Algorithmes de tri - Diviser pour régner Exercice 1 : Algorithme de tri Exercice 2 : Le tri par insertion Exercice 3 : Tri rapide Exercice 4 : Tri fusion Enoncé Corrigé Exercice 4 : Tri fusion Le tri fusion est un autre exemple d’algorithme de tri basé sur le principe de ”Diviser pour régner”. Il est basé sur le fait que fusionner deux tableaux triés en un seul tableau trié T1, T2 se fait en temps linéaire (sur le nombre total d’éléments, dans le pire et le meilleur des cas) : i1, i2 = 0 T = tableau vide TANT QUE l’on n’a pas atteint la fin d’un des tableaux: SI T1[i1] <= T2[i2] ALORS Insérer T1[i1] à la fin de T incrémenter i1 SINON Insérer T2[i2] à la fin de T incrémenter i2 FIN TANT QUE Insérer les éléments restants en fin de T PC/PC* - Lycée Thiers TD 7 : Algorithmes de tri - Diviser pour régner Exercice 1 : Algorithme de tri Exercice 2 : Le tri par insertion Exercice 3 : Tri rapide Exercice 4 : Tri fusion Enoncé Corrigé Exercice 4 : Tri fusion On met alors en oeuvre la récursivité : – Décomposer le tableau en deux sous-tableaux de même longueur (±1) – Appliquer l’algorithme récursivement sur chacun des 2 sous-tableaux – Puis fusionner les 2 sous-tableaux triés en un tableau trié. 1. Ecrire une fonction fusion prenant en paramètre deux listes triées, et qui les fusionne en une liste triée dans le sens croissant, qu’elle renverra. 2. Ecrire une fonction triFusion qui exécute le Tri fusion. 3. Quelle est sa complexité dans le pire des cas ? dans le meilleur des cas ? PC/PC* - Lycée Thiers TD 7 : Algorithmes de tri - Diviser pour régner Exercice 1 : Algorithme de tri Exercice 2 : Le tri par insertion Exercice 3 : Tri rapide Exercice 4 : Tri fusion Enoncé Corrigé Exercice 4 : correction def fusion(T1,T2): T = [] i1 = i2 = 0 n1, n2 = len(T1), len(T2) while i1 < n1 and i2 < n2 : if T1[i1] <= T2[i2]: T.append(T1[i1]) i1 += 1 else: T.append(T2[i2]) i2 += 1 while i1 < n1: T.append(T1[i1]) i1 += 1 while i2 < n2: T.append(T2[i2]) i2 += 1 return T PC/PC* - Lycée Thiers TD 7 : Algorithmes de tri - Diviser pour régner Exercice 1 : Algorithme de tri Exercice 2 : Le tri par insertion Exercice 3 : Tri rapide Exercice 4 : Tri fusion Enoncé Corrigé Exercice 4 : correction def triFusion(T): N = len(T) if N == 1: return T T1, T2 = triFusion(T[:N//2]), triFusion(T[N//2:]) return fusion(T1,T2) ● Dans le pire et le meilleur des cas, la fonction fusion étant de complexité linéaire, triFusion est de complexité θ(N log(N)). N N/2 N/2 N/4 N/4 ⋮ 1 ⋮ 1 1 ⋮ 1 1 N/4 ⋮ 1 1 PC/PC* - Lycée Thiers ⋮ 1 1 N/4 ⋮ 1 1 ⋮ 1 1 ⋮ 1 1 1 TD 7 : Algorithmes de tri - Diviser pour régner