Chapitre 9 : Diviser pour régner.

Rappel :

Vous avez vu l'année dernière le tri par insertion et le tri par sélection et tous les deux avaient une complexité en \(\mathcal{O}\left(n^2\right)\).

1. Diviser pour régner (divide and conquer)

C’est une méthode de conception d’algorithmes qui consiste à :

Des exemples classiques d’algorithmes « diviser pour régner » sont le tri fusion (merge sort), le tri rapide (quick sort) ou encore la recherche dichotomique.

2. Exercice : (sujet 9 - 2025) recherche dichotomique dans un tableau trié.

On s’intéresse à la recherche dichotomique dans un tableau trié d’entiers.

Compléter la fonction suivante en respectant la spécification.

Exemples :

>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33], 28)
True
>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33], 27)
False
def dichotomie(tab, x): """ tab : tableau d'entiers trié dans l'ordre croissant x : nombre entier La fonction renvoie True si tab contient x et False sinon """ debut = 0 fin = len(tab) - 1 while debut <= fin: m = ... if x == tab[m]: return ... if x > tab[m]: debut = m + 1 else: fin = ... return ... tab = [15,16,18,19,23,24,28,29,31,33] valeur_cherchee = 29 if dichotomie(tab, valeur_cherchee): print(f"{valeur_cherchee} est présente dans la table tab.") else: print(f"{valeur_cherchee} n'est pas présente dans la table tab.")

    
>>>

3. Le tri fusion (merge sort)

Le tri fusion est un algorithme de tri fondé sur la stratégie du diviser pour régner. Il consiste à découper la liste à trier en sous-listes de plus en plus petites, jusqu’à n’obtenir que des listes d’un seul élément, puis à les fusionner progressivement dans l’ordre croissant.

Cet algorithme garantit un temps d’exécution en \(\mathcal{O}\left(n \log(n)\right)\) dans tous les cas, ce qui le rend très fiable même pour de grandes quantités de données.

Observe l'animation ci-dessous : chaque cadre est une liste réellement présente dans la mémoire de Python. Les découpages créent de nouvelles listes (des copies), la fusion construit une nouvelle liste final élément par élément, et les listes locales disparaissent dès que Python libère leur mémoire — exactement ce que fait le code des exercices suivants.

liste non triée liste triée élément comparé / milieu élément ajouté à final liste en cours de traitement

Clique sur « Démarrer / Redémarrer » pour lancer l'animation.

4. Exercice : fusion !

Compléter la fonction fusion(liste1,liste2), qui prend comme paramètres deux listes triées et qui renvoie une liste triée composée des éléments des deux autres.

def fusion(liste1,liste2): ''' fusion prend deux listes triées et retourne une grande liste triée contenant les éléments des deux autres. ''' final = [] # liste qui sera retournée curseur1 = 0 # curseur de la liste1 curseur2 = 0 # curseur de la liste2 while ...................................................... : # tant qu'il reste des éléments non traités dans une des deux listes if ............... : # le plus petit élément est dans la liste 1 final.append(liste1[curseur1]) curseur1 += 1 else: # le plus petit élément est celui de la liste 2 ...................... ...................... if ......................... : # il reste des éléments dans la liste 2 à traiter for i in range(curseur2, len(liste2)): final.append(.......) else : # il reste des éléments dans la liste 1 à traiter for i in range(curseur1, len(liste1)): final.append(.......) return final # données de test liste_a = [2, 5, 7, 8, 9, 11, 13, 15, 19, 21, 25, 29, 35, 38, 39, 40, 52, 69, 78, 89] liste_b = [3, 4, 5, 7, 12, 14, 15, 18, 23, 30, 32, 33, 34, 42, 53] print(f"Fusion des deux listes : {fusion(liste_a, liste_b)}.")

    
>>>

5. Exercice : tri fusion

Compléter la fonction tri_par_fusion(liste) en vous appuyant sur la fonction fusion (fusion de deux listes triées) de l'exercice précédent.

def fusion(liste1, liste2): """Fusionne deux listes triées en une liste triée (avec doublons conservés).""" # RECOPIER LA FONCTION COMPLÉTÉE DE L'EXERCICE PRÉCÉDENT def tri_par_fusion(liste): """Retourne une nouvelle liste triée par la méthode "diviser pour régner" (merge sort).""" if ...: # Il y a un élément dans la liste ou moins. return liste else: moitie = ... # indice correspondant au milieu de la liste gauche = tri_par_fusion(...) # partie gauche droite = tri_par_fusion(...) # partie droite return fusion(gauche, droite) liste = [142, 92, 86, 483, 87, 997, 515, 243, 193, 175, 680, 226, 794, 332, 534, 305, 656, 393, 66, 659, 361, 362, 387, 469, 274, 343, 471, 443, 982, 786, 636, 587, 768, 966, 816, 959, 438, 784, 584, 196, 515, 249, 737, 704, 635, 572, 101, 209, 298, 832, 338, 750, 922, 566, 704, 113, 6, 560, 62, 451, 98, 708, 69, 600, 669, 404, 685, 707, 440, 741, 423, 129, 545, 237, 178, 870, 654, 849, 453, 894, 60, 140, 777, 894, 403, 672, 248, 627, 282, 723, 176, 994, 342, 806, 259, 422, 733, 644, 400, 3] print(tri_par_fusion(liste))

    
>>>

6. Exercice : comparaison des complexités des tris.

À faire dans le cahier.

Ce code a permis de générer les 3 images ci-dessous :

Il peut sembler que les courbes soient similaires mais :

  1. Comparer les performances de chaque tri.
  2. À quelle courbe vue en seconde ressemblent les deux premières ci-dessus ?
  3. Quel est l'aspect de la troisième courbe ?
  4. Dans les deux premières courbes :
    • Prendre deux points de la courbe dont les abscisses sont à peu près le double l'une de l'autre.
    • Calculer une approximation du rapport de ces ordonnées.
  5. Dans les deux premières courbes :
    • Prendre deux points de la courbe dont les abscisses sont à peu près le triple l'une de l'autre.
    • Calculer une approximation du rapport de ces ordonnées.
  6. Dans les deux premières courbes :
    • Prendre deux points de la courbe dont les abscisses sont à peu près le quadruple l'une de l'autre.
    • Calculer une approximation du rapport de ces ordonnées.
  7. Dans la troisième courbe :
    • Prendre deux points de la courbe dont les abscisses sont à peu près le quadruple l'une de l'autre.
    • Calculer une approximation du rapport de ces ordonnées.

7. À retenir !

Les tris par insertion et par sélection sont de complexités quadratiques en \(\mathcal{O}\left(n^2 \right)\).

Le tri par fusion est de complexité linéarithmique en \(\mathcal{O}\left(n \log(n)\right)\).