Diviser pour régner

Comment trier rapidement une grande liste ?

Environ 45 minutes

  • Décrire les trois étapes de diviser pour régner.
  • Programmer une fusion et un tri récursif.
  • Justifier terminaison, correction et ordre de grandeur du coût.
Sommaire
  1. Trois étapes et une condition d’arrêt
  2. Fusionner deux listes déjà triées
  3. Comprendre le coût et la mémoire
  4. Au bac : expliquer, implémenter et tester
  5. S’entraîner

Comment trier rapidement une grande liste ?

Un problème volumineux peut devenir plus simple lorsqu’on le découpe. Encore faut-il savoir résoudre les petits problèmes et assembler leurs réponses. Le tri fusion illustre ces trois gestes : diviser, résoudre récursivement, combiner. Tu dois déjà connaître les listes, les indices, les fonctions et le principe d’un appel récursif. L’objectif est de comprendre et programmer une méthode, puis de justifier son coût sans confondre la profondeur des appels avec le travail total.

Trois étapes et une condition d’arrêt

Diviser pour régner consiste à remplacer un problème par plusieurs sous-problèmes de même nature, mais plus petits. On résout chacun par la même méthode. On combine leurs solutions pour obtenir celle du problème initial. Une simple boucle qui traite les données une à une n’est pas automatiquement une application de cette méthode : il faut identifier le découpage et la combinaison.

Pour trier une liste de n valeurs comparables, on coupe à l’indice n // 2. La partie gauche contient les indices précédant cette coupure, la partie droite contient les autres. Si n est impair, les tailles diffèrent d’une unité. Les listes de longueur zéro ou un sont déjà triées : elles constituent les cas de base. Pour n supérieur à un, chacune des deux parties est strictement plus courte que la liste de départ.

La division s’arrête sur des listes d’un élément, déjà triées.

La terminaison vient de cette diminution d’une taille entière positive. On ne peut pas la diminuer indéfiniment : on finit par atteindre un cas de base. Cette justification serait invalide si une des sous-listes gardait toujours la taille initiale. La récursivité exige donc à la fois un arrêt explicite et une progression réelle vers cet arrêt. Un programme qui coupe mal peut boucler même si un cas de base est écrit.

Exemple résolu

Décompose le tri fusion de la liste [7, 2, 5, 1] jusqu’aux cas de base.

  1. Étape 1 : Couper la liste de quatre valeurs en [7, 2] et [5, 1]. Les deux sous-problèmes consistent encore à trier une liste.
  2. Étape 2 : Couper [7, 2] en [7] et [2], puis [5, 1] en [5] et [1]. Toutes ces listes ont longueur un.
  3. Étape 3 : Faire remonter les réponses : la fusion de [7] avec [2] donne [2, 7], celle de [5] avec [1] donne [1, 5].
  4. Étape 4 : Fusionner enfin [2, 7] et [1, 5] pour obtenir une seule liste triée.

Résultat : Le résultat est [1, 2, 5, 7]. Les valeurs restent toutes présentes, mais leur ordre a changé.

Piège à éviter : Concaténer simplement les deux moitiés triées donnerait [2, 7, 1, 5], qui n’est pas triée.

À toi d'essayer

Pour une liste de cinq éléments, quelles tailles obtient-on après la première division à l’indice n // 2 ? Pourquoi les deux appels progressent-ils vers l’arrêt ?

Voir la réponse

On obtient deux éléments à gauche et trois à droite, car 5 // 2 vaut 2. Les tailles 2 et 3 sont strictement inférieures à 5 ; chaque appel progresse vers une liste de taille zéro ou un.

Fusionner deux listes déjà triées

La fusion reçoit deux listes triées par ordre croissant. Elle possède un indice dans chacune et une liste résultat initialement vide. Tant qu’il reste une valeur dans les deux listes, elle compare les valeurs pointées, ajoute la plus petite au résultat et avance seulement l’indice correspondant. Quand une liste est épuisée, elle ajoute toutes les valeurs restantes de l’autre, qui sont déjà dans le bon ordre.

Fusionner compare les premières valeurs encore disponibles ; chaque valeur est recopiée une seule fois.

L’invariant utile est le suivant : le résultat contient, dans l’ordre, les valeurs déjà consommées, et aucune valeur encore disponible n’est plus petite que sa dernière valeur. Au départ, le résultat vide respecte cette propriété. À chaque étape, choisir le plus petit des deux éléments de tête conserve l’ordre, car les éléments suivants de chaque liste ne sont pas plus petits. À la fin, toutes les valeurs ont été consommées.

Exemple résolu

Fusionne [2, 4, 4] et [1, 4, 6]. En cas d’égalité, choisis d’abord la liste gauche.

  1. Étape 1 : Comparer 2 et 1 : prendre 1 à droite. Comparer ensuite 2 et 4 : prendre 2 à gauche.
  2. Étape 2 : Comparer 4 et 4 : prendre le premier 4 de gauche, puis comparer à nouveau 4 et 4 et prendre le second 4 de gauche.
  3. Étape 3 : La liste gauche est épuisée. Recopier les deux valeurs restantes à droite, 4 puis 6.

Résultat : La liste obtenue est [1, 2, 4, 4, 4, 6]. Il y a eu quatre comparaisons entre les têtes des deux listes.

Piège à éviter : Utiliser un ensemble pour supprimer les doublons change les données ; trier doit conserver les trois occurrences de 4.

La stabilité signifie que des éléments de même clé gardent leur ordre relatif. Par exemple, deux dossiers ayant la même note conservent leur ordre initial. Le choix de la gauche en cas d’égalité permet cette stabilité si les tris récursifs la préservent aussi. Un tri fusion n’est donc pas stable par son seul nom : cela dépend notamment du traitement des égalités dans son implémentation.

Programmer la fusion avec des indices

  1. Initialiser i et j à zéro et resultat à une liste vide. Les indices désignent les prochaines valeurs non consommées dans gauche et droite.
  2. Tant que i est inférieur à len(gauche) et j inférieur à len(droite), comparer gauche[i] et droite[j]. Ajouter la valeur choisie puis augmenter son indice d’une unité.
  3. Après cette boucle, ajouter gauche[i :] puis droite[j :] au résultat. Au moins une de ces deux tranches est vide.
  4. Renvoyer resultat. Tester aussi le cas où une entrée est vide dès le début.

À toi d'essayer

On veut trier des dossiers par note en conservant l’ordre des dossiers ex æquo. Lors d’une égalité entre la tête gauche et la tête droite, quel choix faut-il faire et pourquoi ?

Correction détaillée pas à pasDans ce chapitre : 2 corrections détaillées.

Comprendre le coût et la mémoire

Fusionner deux listes contenant au total n éléments demande de recopier n éléments. Chaque comparaison consomme un élément tant que les deux listes sont non vides. Il y a au plus n − 1 comparaisons de têtes, pour n supérieur ou égal à deux et deux listes non vides. Le coût de fusion est donc linéaire en n. Retirer systématiquement le premier élément avec pop(0) dans une liste Python déplacerait les éléments restants et fausserait cette analyse.

Quand n est une puissance de deux, les divisions créent log₂(n) niveaux jusqu’aux éléments isolés. Sur chaque niveau de fusion, l’ensemble des listes représente n éléments à traiter. Le travail total est ainsi de l’ordre de n × log₂(n). Pour une taille quelconque, les parties restent équilibrées et on conserve le même ordre de grandeur O(n log n) dans le pire cas. Le logarithme indique ici combien de divisions par deux sont nécessaires.

Exemple résolu

Pour n = 8, compte les niveaux de fusion et le nombre total de valeurs produites par les fusions.

  1. Étape 1 : Le niveau le plus bas fusionne quatre paires de listes unitaires : il produit quatre listes de deux éléments, soit 8 valeurs.
  2. Étape 2 : Le niveau suivant produit deux listes de quatre éléments : il produit encore 8 valeurs.
  3. Étape 3 : Le dernier niveau produit une liste de huit éléments : il produit encore 8 valeurs.

Résultat : Il y a trois niveaux de fusion et 24 valeurs produites au total par ces fusions, soit 8 × log₂(8). Ce compte n’est pas le nombre exact de comparaisons.

Piège à éviter : Compter seulement les trois niveaux oublie que plusieurs opérations ont lieu à chaque niveau.

Le tri fusion présenté crée des listes intermédiaires. Son espace auxiliaire maximal simultané est O(n), auquel s’ajoute une pile d’appels de profondeur O(log n), absorbée dans cette borne. Il ne trie pas en place. Le volume cumulé des allocations au cours du temps est une autre mesure : il ne faut pas l’identifier à la mémoire maximale utilisée à un instant donné.

Comparer deux algorithmes demande de fixer ce que l’on mesure : comparaisons, affectations, mémoire ou durée réelle sur une machine. O(n log n) n’est pas une durée en secondes ni un nombre exact d’instructions. Sur de toutes petites listes, les constantes peuvent rendre une méthode plus simple intéressante. Sur des listes presque triées, le coût du tri par insertion dépend du nombre d’inversions ; le mot « presque » ne suffit pas à prouver une borne linéaire.

À toi d'essayer

Un programme coupe bien la liste en deux, mais sa combinaison compare chaque élément gauche à chaque élément droit. Peut-on conclure que son coût total est O(n log n) parce qu’il divise par deux ?

Correction détaillée pas à pasDans ce chapitre : 2 corrections détaillées.

Au bac : expliquer, implémenter et tester

Au bac : construire une justification

  1. Identifier l’entrée et la sortie : la sortie est triée et contient exactement les mêmes éléments avec les mêmes multiplicités.
  2. Énoncer les cas de base. Montrer que les tailles des appels récursifs diminuent strictement.
  3. Expliquer pourquoi les solutions des deux sous-problèmes permettent la fusion et pourquoi la fusion produit un résultat trié.
  4. Pour le coût, séparer le nombre de niveaux du travail par niveau. Pour la mémoire, nommer les listes créées et la pile d’appels.

Une implémentation Python du tri fusion renvoie une copie de la liste lorsque sa longueur est inférieure à deux. Sinon, elle calcule le milieu, trie récursivement les deux tranches et appelle la fonction fusion. Pour la mettre au point, commence par tester fusion seule sur des entrées déjà triées. Tester uniquement le tri complet rend plus difficile l’identification d’une erreur de comparaison ou d’indice.

Un jeu de tests utile contient la liste vide, un seul élément, des doublons, des nombres négatifs, une liste déjà triée, une liste en ordre inverse et une taille impaire. Il faut vérifier l’ordre final, la conservation des valeurs et l’absence de modification de l’entrée si le contrat annonce une nouvelle liste. Comparer le résultat à sorted sur ces données aide à trouver des erreurs ; cela complète, sans remplacer, la justification générale.

La méthode se rencontre aussi dans des traitements d’images ou des calculs sur des structures récursives. Pour reconnaître un nouveau cas, demande-toi si les sous-problèmes sont de même nature, comment ils diminuent et comment leurs résultats se combinent. Le tri rapide est un autre exemple possible, mais ses règles de partition et son coût dépendent du pivot ; il constitue ici un prolongement, pas une étape nécessaire du tri fusion.

Attention :

Erreurs fréquentes : oublier le cas vide ; perdre un doublon ; avancer les deux indices après une seule copie ; oublier la fin de la liste non épuisée ; annoncer un coût logarithmique en ne comptant que la profondeur.

Vocabulaire

Cas de base :
Situation suffisamment petite pour être résolue sans appel récursif.
Fusion :
Assemblage ordonné de listes déjà triées.
Invariant :
Propriété conservée à chaque étape d’un traitement.
Stabilité :
Conservation de l’ordre relatif des éléments de même clé.

Bilan

RepèreSens
DiviserDeux sous-listes de tailles proches.
RésoudreAppels récursifs jusqu’à zéro ou un élément.
CombinerFusion linéaire ; coût global O(n log n).

S’entraîner

Pour poursuivre ton entraînement, ouvre la rubrique S’entraîner du site, à l’adresse /exercices. Reprends d’abord les questions de cette leçon sans afficher les réponses, puis compare ton raisonnement à la correction.

À retenir

  • Le tri fusion combine deux listes déjà triées.
  • Les cas de base sont les listes de longueur zéro ou un.
  • Le coût du tri fusion équilibré est O(n log n) dans le pire cas.
  • La conservation des doublons fait partie de la correction d’un tri.

Fiche de révision

Schéma à retrouver

couper, trier les deux parties, fusionner. La concaténation ne remplace pas la fusion.

Pour huit valeurs

trois étages de fusion traitent chacun huit valeurs ; ce compte illustre le produit taille × nombre d’étages.

Test décisif

fusionner une liste vide et une liste non vide doit restituer toutes les valeurs de cette dernière.

Stabilité

à égalité, choisir d’abord à gauche ; mémoire : la version avec nouvelles listes utilise un espace auxiliaire linéaire.

Et maintenant ?

Tu as lu le cours. L’étape suivante tient en une action.

Relis le coursReprends l’essentiel avant de passer à la suite.

Prolonge l’expérience !

Continue à explorer ce chapitre à travers de nouvelles activités, des défis et des expériences interactives. Avec Premium, l’apprentissage continue !

Ici, tu débloques aussi 2 corrections détaillées.

Parent ? Suivez les progrès de votre enfant.

Tous les cours de NSI