Leçon 9 sur 19

Chapitre 9 — Tri fusion

Diviser, trier puis fusionner pour obtenir un tri stable en O(n log n)

Positionnement dans le parcours — Ce chapitre introduit une méthode de tri efficace fondée sur le paradigme « diviser pour régner ». Il consolide la récursivité, prépare l’analyse des relations de récurrence et fournit une base importante pour les tris externes et le traitement des listes chaînées.

 

Fiche pédagogique du chapitre

Objectifs d’apprentissage

À la fin de ce chapitre, l’étudiant devra être capable de :

  • expliquer le principe « diviser, résoudre et combiner » appliqué au tri fusion ;
  • décomposer un tableau en sous-tableaux jusqu’aux cas élémentaires ;
  • fusionner correctement deux séquences déjà triées ;
  • écrire la version récursive du tri fusion ;
  • réaliser une trace complète des divisions et des fusions ;
  • justifier la correction de l’algorithme à l’aide d’un invariant ou d’une induction ;
  • établir la complexité temporelle O(n log n) ;
  • évaluer la mémoire auxiliaire nécessaire ;
  • expliquer pourquoi le tri fusion est stable ;
  • adapter le tri fusion aux listes chaînées et aux données volumineuses.

Prérequis

  • Tableaux à une dimension et indices.
  • Fonctions, procédures et paramètres.
  • Récursivité et cas de base.
  • Complexités O(n), O(log n) et O(n log n).
  • Comparaison et copie d’éléments.

Organisation proposée

Partie

Contenu principal

Durée indicative

9.1Principe, division, tri des parties et recomposition2 h
9.2Fusion de deux tableaux triés et invariants3 h
9.3Version récursive, arbre d’appels et correction3 h
9.4Complexité, mémoire, stabilité et listes chaînées3 h
ApplicationsDonnées structurées, fichiers et tris externes2 h
TD / TPTraces, implémentation et mesures expérimentales4 à 6 h

 

Introduction

Les tris élémentaires étudiés précédemment, comme le tri par sélection, le tri à bulles et le tri par insertion, peuvent nécessiter un nombre quadratique d’opérations lorsque la taille du tableau augmente. Le tri fusion adopte une stratégie différente : il divise le problème en sous-problèmes plus petits, trie ceux-ci puis fusionne leurs résultats.

Cette méthode fournit un temps d’exécution en O(n log n) dans tous les cas. Elle est stable et se prête particulièrement bien aux listes chaînées, au tri de fichiers volumineux et aux traitements parallèles. Son principal coût est l’utilisation de mémoire auxiliaire lors de la fusion de tableaux.

Idée directrice — Trier une séquence devient simple lorsque l’on sait fusionner efficacement deux séquences déjà triées.

 

9.1 Principe

9.1.1 Le paradigme « diviser pour régner »

Le tri fusion suit les trois étapes classiques du paradigme « diviser pour régner » : diviser le problème, résoudre récursivement les sous-problèmes et combiner leurs solutions.

Étape

Dans le tri fusion

But

DiviserSéparer le tableau en deux parties de tailles presque égales.Réduire la taille du problème.
RésoudreTrier récursivement chaque partie.Obtenir deux séquences triées.
CombinerFusionner les deux séquences triées.Construire une séquence globale triée.

 

Observation — Une séquence contenant zéro ou un seul élément est déjà triée. Cette propriété fournit le cas de base de la récursion.

 

9.1.2 Division du tableau

À chaque niveau, le tableau est partagé autour d’un indice médian. Pour un intervalle [gauche, droite], le milieu peut être calculé par gauche + (droite - gauche) div 2. Cette écriture évite un dépassement de capacité possible avec (gauche + droite) div 2 dans certains langages.

Exemple de divisions successives

[38, 27, 43, 3, 9, 82, 10]

            /                         \

[38, 27, 43, 3]                 [9, 82, 10]

       /       \                      /      \

[38, 27]    [43, 3]               [9, 82]   [10]

 /    \      /   \                /   \

[38] [27]  [43] [3]              [9] [82]

 

La division n’effectue pas encore le tri. Elle produit uniquement des sous-problèmes plus petits jusqu’à obtenir des séquences élémentaires.

9.1.3 Tri des deux parties

Chaque moitié est triée avec le même algorithme. L’appel récursif ne retourne qu’après avoir complètement trié sa sous-partie. L’ordre d’exécution est généralement profondeur d’abord : la branche gauche est résolue, puis la branche droite, avant la fusion.

Ordre conceptuel du traitement

TriFusion(tableau complet)

   TriFusion(moitié gauche)

     ... divisions ...

     ... fusions ...

   TriFusion(moitié droite)

     ... divisions ...

     ... fusions ...

  Fusion(moitié gauche, moitié droite)

 

Point essentiel — La fusion d’un niveau ne commence que lorsque les deux sous-parties concernées sont déjà triées.

 

9.1.4 Fusion des parties triées

La fusion compare les premiers éléments non encore copiés des deux sous-tableaux. Le plus petit est ajouté au résultat, puis l’indice correspondant avance. Dès qu’un sous-tableau est épuisé, les éléments restants de l’autre sont recopiés.

Exemple de recomposition

[38] + [27]          -> [27, 38]

[43] + [3]           -> [3, 43]

[27, 38] + [3, 43]   -> [3, 27, 38, 43]

[9] + [82]           -> [9, 82]

[9, 82] + [10]       -> [9, 10, 82]

[3, 27, 38, 43] + [9, 10, 82]

                      -> [3, 9, 10, 27, 38, 43, 82]

 

9.1.5 Vue globale de l’algorithme

1. Si la séquence contient au plus un élément, terminer.

2. Calculer le milieu et séparer la séquence en deux parties.

3. Trier récursivement la partie gauche.

4. Trier récursivement la partie droite.

5. Fusionner les deux parties triées dans l’ordre croissant.

Pseudo-code — Vue abstraite du tri fusion

Fonction TriFusion(T) : Tableau

    Si Longueur(T) <= 1 Alors

        Retourner T

    FinSi

    milieu <- Longueur(T) div 2

    gauche <- SousTableau(T, 0, milieu - 1)

    droite <- SousTableau(T, milieu, Longueur(T) - 1)

    gauche <- TriFusion(gauche)

    droite <- TriFusion(droite)

    Retourner Fusionner(gauche, droite)

FinFonction

Cette version crée explicitement des sous-tableaux. Une version par indices évite certaines copies intermédiaires.

 

9.1.6 Invariant global

À la fin de chaque appel TriFusion portant sur un intervalle donné, cet intervalle contient exactement les mêmes éléments qu’au départ, mais classés dans l’ordre demandé. Cette propriété se propage des cas de base vers le tableau complet.

Invariant de correction — Chaque appel récursif préserve le multiensemble des valeurs et retourne une séquence triée.

 

9.2 Fusion de deux tableaux

9.2.1 Précondition et objectif

La procédure de fusion reçoit deux tableaux A et B triés selon le même ordre. Elle doit produire un tableau R trié contenant tous les éléments de A et de B, sans perte ni duplication artificielle.

Élément du contrat

Description

PréconditionA et B sont triés dans le même ordre.
PostconditionR est trié et contient exactement les éléments de A et B.
EntréesDeux tableaux et leurs longueurs.
SortieUn tableau de longueur |A| + |B|.
Coût attenduTemps linéaire O(|A| + |B|).

 

9.2.2 Comparaison des premiers éléments

Trois indices sont utilisés : i pour A, j pour B et k pour le tableau résultat. Tant que les deux tableaux possèdent des éléments non copiés, A[i] et B[j] sont comparés. Le plus petit est placé dans R[k].

État initial

A = [3, 12, 20, 31]       i = 0

B = [5, 9, 18, 40]        j = 0

R = [_, _, _, _, _, _, _, _]   k = 0

 

Comparer 3 et 5 -> copier 3, puis avancer i et k.

 

Invariant de boucle — Avant chaque comparaison, R[0..k-1] contient les k plus petits éléments de A et B, dans l’ordre.

 

9.2.3 Copie dans le tableau résultat

Pseudo-code — Fusionner deux tableaux triés

Fonction Fusionner(A, B) : Tableau

    i <- 0

    j <- 0

    k <- 0

    Creer R de taille Longueur(A) + Longueur(B)

    TantQue i < Longueur(A) ET j < Longueur(B) Faire

        Si A[i] <= B[j] Alors

            R[k] <- A[i]

            i <- i + 1

        Sinon

            R[k] <- B[j]

            j <- j + 1

        FinSi

        k <- k + 1

    FinTantQue

    TantQue i < Longueur(A) Faire

        R[k] <- A[i]

        i <- i + 1

        k <- k + 1

    FinTantQue

    TantQue j < Longueur(B) Faire

        R[k] <- B[j]

        j <- j + 1

        k <- k + 1

    FinTantQue

    Retourner R

FinFonction

Le test <= choisit l’élément de gauche en cas d’égalité et préserve ainsi la stabilité.

 

9.2.4 Trace complète d’une fusion

Fusion de A = [3, 12, 20, 31] et B = [5, 9, 18, 40].

Étape

A[i]

B[j]

Choix

R après copie

1

3

5

3 de A

[3]

2

12

5

5 de B

[3, 5]

3

12

9

9 de B

[3, 5, 9]

4

12

18

12 de A

[3, 5, 9, 12]

5

20

18

18 de B

[3, 5, 9, 12, 18]

6

20

40

20 de A

[3, 5, 9, 12, 18, 20]

7

31

40

31 de A

[3, 5, 9, 12, 18, 20, 31]

Reste

A épuisé

40

Copier le reste de B

[3, 5, 9, 12, 18, 20, 31, 40]

 

9.2.5 Traitement des éléments restants

La boucle principale s’arrête dès que l’un des deux tableaux est épuisé. Les éléments restants de l’autre tableau sont déjà triés et supérieurs ou égaux au dernier élément copié. Ils peuvent donc être ajoutés sans nouvelles comparaisons entre les deux sources.

Erreur fréquente — Oublier la copie des éléments restants conduit à perdre une partie des données lorsque les deux tableaux n’ont pas la même longueur ou ne s’épuisent pas simultanément.

 

9.2.6 Fusion dans un tableau global

Dans une implémentation par indices, la fusion porte sur deux intervalles contigus T[gauche..milieu] et T[milieu+1..droite]. Un tableau auxiliaire reçoit temporairement les éléments, puis ceux-ci sont recopiés dans T.

Pseudo-code — Fusion d’intervalles contigus

Procedure FusionnerIntervalles(T, gauche, milieu, droite, Aux)

    i <- gauche

    j <- milieu + 1

    k <- gauche

    TantQue i <= milieu ET j <= droite Faire

        Si T[i] <= T[j] Alors

            Aux[k] <- T[i]

            i <- i + 1

        Sinon

            Aux[k] <- T[j]

            j <- j + 1

        FinSi

        k <- k + 1

    FinTantQue

    TantQue i <= milieu Faire

        Aux[k] <- T[i]

        i <- i + 1 ; k <- k + 1

    FinTantQue

    TantQue j <= droite Faire

        Aux[k] <- T[j]

        j <- j + 1 ; k <- k + 1

    FinTantQue

    Pour k allant de gauche à droite Faire

        T[k] <- Aux[k]

    FinPour

FinProcedure

 

9.2.7 Stabilité lors de la fusion

Un tri est stable lorsque deux éléments ayant la même clé conservent leur ordre relatif initial. Pendant la fusion, si les clés sont égales, il faut sélectionner en premier l’élément provenant de la partie gauche.

Séquence initiale

Clé

Identité

Étudiant A14Arrivé avant B
Étudiant B14Arrivé après A

 

Avec le test A[i] <= B[j], A est copié avant B lorsque les clés sont égales. Remplacer <= par < peut inverser leur ordre et rendre l’implémentation instable.

9.3 Version récursive

9.3.1 Cas de base

Le cas de base est atteint lorsque l’intervalle contient zéro ou un seul élément. Aucun traitement n’est nécessaire, car cet intervalle est déjà trié.

Pseudo-code — Test du cas de base

Si gauche >= droite Alors

    Retourner

FinSi

 

Rôle du cas de base — Il garantit la terminaison de la récursion et empêche la subdivision infinie des intervalles.

 

9.3.2 Division et appels récursifs

Lorsque gauche < droite, l’intervalle est partagé en deux. Les deux appels récursifs portent sur des intervalles strictement plus petits, ce qui rapproche l’exécution du cas de base.

Pseudo-code — Tri fusion par indices

Procedure TriFusion(T, gauche, droite, Aux)

    Si gauche >= droite Alors

        Retourner

    FinSi

    milieu <- gauche + (droite - gauche) div 2

    TriFusion(T, gauche, milieu, Aux)

    TriFusion(T, milieu + 1, droite, Aux)

    FusionnerIntervalles(T, gauche, milieu, droite, Aux)

FinProcedure

Le tableau auxiliaire peut être créé une seule fois par l’appel principal et réutilisé à tous les niveaux.

 

9.3.3 Arbre des appels

Arbre des appels pour un tableau de 8 éléments

TriFusion(0,7)

├─ TriFusion(0,3)

│   ├─ TriFusion(0,1)

│   │  ├─ TriFusion(0,0)

│   │  └─ TriFusion(1,1)

│   └─ TriFusion(2,3)

│      ├─ TriFusion(2,2)

│      └─ TriFusion(3,3)

└─ TriFusion(4,7)

    ├─ TriFusion(4,5)

   └─ TriFusion(6,7)

 

L’arbre possède log2(n) niveaux de division lorsque n est une puissance de deux. À chaque niveau, la somme des tailles des intervalles fusionnés est n.

9.3.4 Ordre des fusions

Les fusions sont réalisées lors du retour des appels récursifs. Les plus petits intervalles sont donc fusionnés en premier, puis les résultats remontent progressivement vers l’intervalle initial.

Niveau

Fusions typiques pour 8 éléments

Volume total traité

1

4 fusions de 1 + 1

8 éléments

2

2 fusions de 2 + 2

8 éléments

3

1 fusion de 4 + 4

8 éléments

 

9.3.5 Trace complète sur un petit tableau

Considérons T = [7, 2, 6, 3].

Divisions et fusions

[7, 2, 6, 3]

    /       \

[7, 2]    [6, 3]

 /    \     /   \

[7] [2]   [6] [3]

  \ /      \ /

 [2, 7]    [3, 6]

        \   /

   [2, 3, 6, 7]

 

Action

Intervalle avant

Intervalle après

Fusion des indices 0 et 1[7, 2][2, 7]
Fusion des indices 2 et 3[6, 3][3, 6]
Fusion des indices 0 à 3[2, 7] + [3, 6][2, 3, 6, 7]

 

9.3.6 Terminaison

La terminaison est assurée car chaque appel portant sur un intervalle de taille supérieure à un le divise en deux intervalles strictement plus petits. La taille de l’intervalle est un variant entier positif qui diminue jusqu’à un.

Variant — droite - gauche + 1 diminue strictement le long de chaque branche récursive.

 

9.3.7 Justification de la correction

La correction peut être démontrée par induction sur la taille n de l’intervalle.

Étape de preuve

Argument

InitialisationPour n <= 1, l’intervalle est déjà trié.
HypothèseSupposons que TriFusion trie correctement tout intervalle de taille strictement inférieure à n.
HéréditéLes deux moitiés, de taille inférieure à n, sont triées par l’hypothèse ; Fusionner les combine correctement.
ConclusionTriFusion trie tout intervalle fini.

 

9.3.8 Version itérative ascendante

Le tri fusion peut aussi être écrit sans récursion. On fusionne d’abord des blocs de taille 1, puis 2, puis 4, jusqu’à couvrir tout le tableau. Cette version est appelée tri fusion ascendant ou bottom-up.

Pseudo-code — Tri fusion itératif

Procedure TriFusionIteratif(T, n, Aux)

    taille <- 1

    TantQue taille < n Faire

        gauche <- 0

        TantQue gauche < n - 1 Faire

            milieu <- Min(gauche + taille - 1, n - 1)

            droite <- Min(gauche + 2 * taille - 1, n - 1)

            Si milieu < droite Alors

                FusionnerIntervalles(T, gauche, milieu, droite, Aux)

            FinSi

            gauche <- gauche + 2 * taille

        FinTantQue

        taille <- 2 * taille

    FinTantQue

FinProcedure

 

Comparaison — La version itérative évite la pile d’appels, mais conserve le même coût temporel et le même besoin principal de mémoire auxiliaire.

 

9.4 Analyse

9.4.1 Complexité temporelle

Pour trier n éléments, l’algorithme effectue deux appels sur des sous-tableaux d’environ n/2 éléments, puis une fusion linéaire. La relation de récurrence est donc : T(n) = 2T(n/2) + Theta(n).

Interprétation par niveaux

Niveau 0 : 1 problème de taille n       -> travail de fusion n

Niveau 1 : 2 problèmes de taille n/2   -> travail total n

Niveau 2 : 4 problèmes de taille n/4   -> travail total n

...

Nombre de niveaux : log2(n)

Travail total : n × log2(n)

 

Cas

Complexité du tri fusion

Explication

Meilleur casTheta(n log n)La version classique divise et fusionne même si le tableau est déjà trié.
Cas moyenTheta(n log n)Le nombre de niveaux et le volume fusionné restent identiques.
Pire casTheta(n log n)Chaque niveau traite au plus n éléments.

 

Résultat principal — Le tri fusion garantit O(n log n), indépendamment de l’ordre initial des données.

 

9.4.2 Nombre de comparaisons

Fusionner deux séquences de longueurs p et q demande au plus p + q - 1 comparaisons entre éléments. Pour n éléments, le nombre total de comparaisons est de l’ordre de n log n.

Taille n

Ordre de grandeur n log2(n)

Tri quadratique n²

16

64

256

1 024

10 240

1 048 576

1 000 000

environ 20 000 000

1 000 000 000 000

 

9.4.3 Mémoire supplémentaire

Pour les tableaux, la fusion classique utilise un tableau auxiliaire de taille n, soit O(n) mémoire. La pile récursive occupe en plus O(log n) cadres d’appels. Le terme dominant reste O(n).

Ressource

Coût

Commentaire

Tableau auxiliaireO(n)Stocke temporairement les éléments pendant les fusions.
Pile récursiveO(log n)Un cadre par niveau de division.
Variables localesO(1) par appelIndices, milieu et limites.
Mémoire totaleO(n)Le tableau auxiliaire domine asymptotiquement.

 

Pratique recommandée — Créer un unique tableau auxiliaire au début et le réutiliser évite des allocations répétées à chaque appel.

 

9.4.4 Stabilité

Le tri fusion est naturellement stable lorsque la fusion choisit l’élément gauche en cas d’égalité. Cette propriété est importante pour les tris multicritères et les enregistrements contenant plusieurs champs.

Exemple de stabilité

Avant le tri par note : (Amina, 14), (Yassine, 12), (Omar, 14)

Après tri stable       : (Yassine, 12), (Amina, 14), (Omar, 14)

Amina reste avant Omar parmi les éléments de note 14.

 

9.4.5 Tri fusion et listes chaînées

Le tri fusion est particulièrement adapté aux listes chaînées. Une liste peut être divisée à l’aide de deux pointeurs, un lent et un rapide. La fusion s’effectue en réorientant les liens entre nœuds, sans recopier les valeurs dans un tableau auxiliaire de taille n.

Aspect

Tableau

Liste chaînée

DivisionCalcul direct du milieu par indice.Recherche du milieu en O(n) avec pointeurs lent/rapide.
FusionCopie généralement vers un tableau auxiliaire.Réenchaînement des nœuds.
Mémoire auxiliaireO(n) pour les éléments.O(log n) pour la récursion, hors nœuds existants.
AccèsAccès direct par indice.Accès séquentiel.
PertinenceTrès bon tri stable général.L’un des meilleurs choix pour une liste chaînée.

 

Pseudo-code — Fusion de deux listes chaînées triées

Fonction FusionnerListes(L1, L2) : Noeud

    Si L1 = NUL Alors Retourner L2

    Si L2 = NUL Alors Retourner L1

    Si L1.valeur <= L2.valeur Alors

        L1.suivant <- FusionnerListes(L1.suivant, L2)

        Retourner L1

    Sinon

        L2.suivant <- FusionnerListes(L1, L2.suivant)

        Retourner L2

    FinSi

FinFonction

 

9.4.6 Avantages et limites

Critère

Avantages

Limites

TempsO(n log n) dans tous les cas.Peu adaptatif dans sa version classique.
StabilitéPréserve l’ordre des clés égales.Dépend du test utilisé pendant la fusion.
MémoireTrès favorable aux listes chaînées.O(n) auxiliaire pour les tableaux.
PrévisibilitéPerformances régulières.Constantes parfois supérieures au tri rapide en mémoire vive.
Données massivesExcellent pour le tri externe et la fusion de fichiers.Nécessite une organisation des lectures et écritures.
ParallélismeLes deux moitiés peuvent être triées indépendamment.La fusion finale doit combiner les résultats.

 

9.4.7 Comparaison avec d’autres tris

Algorithme

Meilleur

Moyen

Pire

Mémoire

Stable

Insertion

O(n)

O(n²)

O(n²)

O(1)

Oui

Sélection

O(n²)

O(n²)

O(n²)

O(1)

Non en général

Tri fusion

O(n log n)

O(n log n)

O(n log n)

O(n)

Oui

Tri rapide

O(n log n)

O(n log n)

O(n²)

O(log n) moyen

Non en général

Tri par tas

O(n log n)

O(n log n)

O(n log n)

O(1)

Non

 

Applications du tri fusion

Application 1 — Trier des résultats d’étudiants

Des enregistrements Étudiant peuvent être triés par moyenne croissante ou décroissante. La stabilité permet de conserver l’ordre alphabétique établi auparavant lorsque deux étudiants ont la même moyenne.

Pseudo-code — Comparaison d’étudiants

Fonction Avant(E1, E2) : Booleen

    Si E1.moyenne < E2.moyenne Alors Retourner VRAI

    Si E1.moyenne > E2.moyenne Alors Retourner FAUX

    Retourner E1.nom <= E2.nom

FinFonction

Une autre stratégie consiste à trier d’abord par nom, puis par moyenne avec un tri stable.

 

Application 2 — Fusionner des journaux déjà triés

Deux serveurs produisent des journaux triés par date. La procédure de fusion peut construire un journal global en temps linéaire, sans retrier toutes les lignes depuis le début.

Fusion chronologique

Serveur A : 08:01, 08:04, 08:09

Serveur B : 08:02, 08:05, 08:07

Global    : 08:01, 08:02, 08:04, 08:05, 08:07, 08:09

 

Application 3 — Tri externe de fichiers volumineux

Lorsque les données ne tiennent pas entièrement en mémoire, le fichier est découpé en blocs. Chaque bloc est trié en mémoire et enregistré sur disque. Les blocs triés sont ensuite fusionnés, éventuellement par groupes, jusqu’à produire un fichier global trié.

1. Lire un bloc pouvant tenir en mémoire.

2. Trier le bloc et l’écrire dans un fichier temporaire.

3. Répéter pour tous les blocs.

4. Fusionner les fichiers temporaires triés.

5. Écrire le résultat final et supprimer les fichiers temporaires.

Application majeure — Le tri fusion est la base de nombreux tris externes utilisés par les bases de données et les systèmes de traitement massif.

 

Application 4 — Trier une liste chaînée

Dans une liste chaînée, l’insertion d’éléments au milieu ne nécessite pas de décalages. Le tri fusion exploite cet avantage et réalise les fusions en modifiant uniquement les références entre nœuds.

Application 5 — Traitement parallèle

Les deux moitiés étant indépendantes, elles peuvent être triées simultanément sur deux cœurs ou deux machines. Les résultats sont ensuite fusionnés. Cette propriété facilite la parallélisation, sous réserve de gérer le coût des communications et de la fusion.

Erreurs fréquentes et bonnes pratiques

Erreur

Conséquence

Bonne pratique

Cas de base absent ou incorrectRécursion infinie ou indices invalides.Arrêter lorsque gauche >= droite.
Milieu mal calculéPerte ou duplication d’un intervalle.Utiliser gauche + (droite - gauche) div 2.
Sous-tableaux non triés avant fusionRésultat incorrect.Appeler TriFusion sur les deux moitiés avant Fusionner.
Éléments restants non copiésValeurs perdues.Prévoir deux boucles de copie finale.
Test < au lieu de <=Perte possible de stabilité.Choisir la partie gauche en cas d’égalité.
Tableau auxiliaire recréé à chaque appelAllocations nombreuses.Créer Aux une seule fois et le réutiliser.
Confusion entre indices inclusifs et exclusifsDécalages et dépassements.Documenter clairement la convention.

 

Travaux dirigés

TD 1 — Identifier les étapes

Pour T = [11, 4, 8, 2, 7, 5], représenter toutes les divisions puis toutes les fusions du tri fusion.

TD 2 — Fusion manuelle

Fusionner A = [1, 6, 12, 15] et B = [2, 3, 9, 20, 25]. Indiquer à chaque étape les valeurs de i, j et le contenu de R.

TD 3 — Compléter le pseudo-code

Compléter les conditions manquantes d’une procédure de fusion puis justifier les tests utilisés.

Pseudo-code à compléter

TantQue ............... Faire

    Si ............... Alors

        R[k] <- A[i]

        i <- i + 1

    Sinon

        R[k] <- B[j]

        j <- j + 1

    FinSi

    k <- k + 1

FinTantQue

 

TD 4 — Détecter une erreur de stabilité

On fusionne des enregistrements avec le test A[i].clé < B[j].clé. Expliquer pourquoi le tri peut devenir instable et proposer la correction.

TD 5 — Analyser la complexité

Pour n = 32, déterminer le nombre de niveaux de division, le volume total d’éléments traité par niveau et l’ordre de grandeur du travail total.

TD 6 — Mémoire auxiliaire

Comparer la mémoire utilisée par une implémentation qui crée deux nouveaux sous-tableaux à chaque appel et une implémentation qui réutilise un tableau Aux unique.

TD 7 — Version descendante et ascendante

Comparer le tri fusion récursif descendant et le tri fusion itératif ascendant selon la pile d’appels, l’ordre des fusions et la lisibilité.

TD 8 — Listes chaînées

Décrire comment diviser une liste simplement chaînée en deux moitiés à l’aide de deux pointeurs, puis indiquer comment fusionner deux listes triées.

TD 9 — Tri multicritère stable

On souhaite classer des étudiants par moyenne décroissante, puis conserver l’ordre alphabétique pour les égalités. Proposer une stratégie utilisant la stabilité du tri fusion.

TD 10 — Choisir un algorithme

Pour chacun des contextes suivants, dire si le tri fusion est adapté : petit tableau presque trié, liste chaînée volumineuse, données ne tenant pas en mémoire, tableau en mémoire avec contrainte stricte O(1) supplémentaire.

Corrigés indicatifs des travaux dirigés

Corrigé du TD 1

Trace attendue

[11, 4, 8, 2, 7, 5]

-> [11, 4, 8] | [2, 7, 5]

-> [11, 4] | [8] | [2, 7] | [5]

-> [11] | [4] | [8] | [2] | [7] | [5]

Fusions : [4, 11], puis [4, 8, 11]

           [2, 7], puis [2, 5, 7]

Fusion finale : [2, 4, 5, 7, 8, 11]

 

Corrigé du TD 2

Étape

Comparaison

Élément copié

Résultat partiel

1

1 / 2

1

[1]

2

6 / 2

2

[1, 2]

3

6 / 3

3

[1, 2, 3]

4

6 / 9

6

[1, 2, 3, 6]

5

12 / 9

9

[1, 2, 3, 6, 9]

6

12 / 20

12

[1, 2, 3, 6, 9, 12]

7

15 / 20

15

[1, 2, 3, 6, 9, 12, 15]

Reste

A épuisé

20 puis 25

[1, 2, 3, 6, 9, 12, 15, 20, 25]

 

Corrigé du TD 3

Conditions complétées

TantQue i < Longueur(A) ET j < Longueur(B) Faire

    Si A[i] <= B[j] Alors

        ...

    FinSi

FinTantQue

La conjonction garantit que les deux valeurs comparées existent ; <= conserve la stabilité.

 

Corrigé du TD 4

Lorsque les clés sont égales, le test strict < sélectionne l’élément de B, même si celui de A apparaissait plus tôt dans la séquence initiale. Le test doit être A[i].clé <= B[j].clé pour choisir la partie gauche en cas d’égalité.

Corrigé du TD 5

Pour n = 32 = 2^5, il existe 5 niveaux de fusion. Chaque niveau traite au total 32 éléments. Le travail principal est donc proportionnel à 32 × 5 = 160, soit Theta(n log n).

Corrigé du TD 6

Créer des sous-tableaux à chaque appel provoque de nombreuses allocations et copies temporaires. Le pic mémoire reste généralement O(n), mais les coûts constants et la pression sur l’allocateur augmentent. Un unique tableau Aux de taille n, réutilisé, est plus efficace et plus prévisible.

Corrigé du TD 7

Critère

Version récursive

Version itérative

Pile d’appelsO(log n)Aucune pile récursive.
OrdreDivisions descendantes puis fusions au retour.Blocs de tailles 1, 2, 4, 8...
LisibilitéTrès proche du principe diviser pour régner.Plus de gestion explicite des bornes.
ComplexitéO(n log n)O(n log n)

 

Corrigé du TD 8

Un pointeur lent avance d’un nœud tandis qu’un pointeur rapide avance de deux nœuds. Lorsque le rapide atteint la fin, le lent se trouve près du milieu. La liste est coupée à cet endroit. La fusion compare les têtes et relie au résultat le nœud possédant la plus petite clé.

Corrigé du TD 9

On peut d’abord trier les étudiants par nom croissant, puis appliquer un tri fusion stable par moyenne décroissante. Les étudiants ayant la même moyenne conservent alors l’ordre alphabétique issu du premier tri. On peut également utiliser un comparateur multicritère explicite.

Corrigé du TD 10

Contexte

Choix

Justification

Petit tableau presque triéPlutôt tri par insertionSimple, en place et proche de O(n) dans ce cas.
Liste chaînée volumineuseTri fusionFusion par réenchaînement, temps garanti O(n log n).
Données hors mémoireTri fusion externeFusion séquentielle efficace des blocs triés.
Tableau avec O(1) auxiliaire strictTri par tas ou autre tri en placeLe tri fusion classique nécessite O(n) mémoire.

 

Travail pratique — Implémentation et étude expérimentale du tri fusion

Objectifs

  • Implémenter une procédure de fusion stable.
  • Implémenter le tri fusion récursif par indices.
  • Tester la correction sur des cas variés.
  • Mesurer le nombre de comparaisons et de copies.
  • Comparer les performances avec le tri par insertion.
  • Observer l’influence de la taille et de l’ordre initial des données.

Travail demandé

1. Écrire FusionnerIntervalles en utilisant un tableau auxiliaire unique.

2. Écrire TriFusion récursif et une fonction d’appel principale.

3. Ajouter des compteurs de comparaisons et d’affectations.

4. Tester des tableaux vides, unitaires, triés, inversés, aléatoires et contenant des doublons.

5. Vérifier la stabilité sur des enregistrements (clé, ordreInitial).

6. Comparer les temps avec un tri par insertion pour plusieurs tailles.

7. Tracer ou présenter un tableau des résultats.

8. Rédiger une conclusion reliant les mesures à O(n log n).

Jeux d’essai minimaux

Cas

Entrée

Sortie attendue

Vide

[]

[]

Un élément

[5]

[5]

Déjà trié

[1, 2, 3, 4]

[1, 2, 3, 4]

Ordre inverse

[5, 4, 3, 2, 1]

[1, 2, 3, 4, 5]

Doublons

[4, 2, 4, 1, 2]

[1, 2, 2, 4, 4]

Valeurs négatives

[3, -1, 0, -5]

[-5, -1, 0, 3]

 

Architecture suggérée

Pseudo-code — Organisation du programme

Algorithme TP_TriFusion

    Lire ou generer T

    Creer Aux de meme taille que T

    comparaisons <- 0

    affectations <- 0

    TriFusion(T, 0, Longueur(T) - 1, Aux)

    Afficher T

    Afficher comparaisons, affectations et temps

FinAlgorithme

 

Grille d’évaluation indicative

Critère

Points

Fusion correcte et stable

4

Récursion et gestion correcte des bornes

4

Réutilisation du tableau auxiliaire

2

Jeux d’essai et validation

3

Instrumentation et mesures

3

Comparaison avec un autre tri

2

Qualité du code et compte rendu

2

 

Pistes d’extension

  • Implémenter la version itérative ascendante.
  • Trier une liste chaînée.
  • Ajouter un ordre décroissant paramétrable.
  • Trier des enregistrements avec un comparateur multicritère.
  • Paralléliser les deux appels récursifs au-dessus d’un seuil.
  • Simuler un tri externe avec plusieurs fichiers temporaires.

Synthèse du chapitre

Notion

À retenir

PrincipeDiviser la séquence, trier chaque moitié, puis fusionner.
Cas de baseUne séquence de taille 0 ou 1 est déjà triée.
FusionSélection linéaire du plus petit élément courant des deux parties.
Complexité temporelleTheta(n log n) dans le meilleur, le moyen et le pire cas.
MémoireO(n) pour un tableau, généralement O(log n) pour une liste chaînée hors données.
StabilitéOui si la partie gauche est choisie en cas d’égalité.
ForcesPrévisible, stable, adapté aux listes et au tri externe.
Limite principaleMémoire auxiliaire pour les tableaux.

 

Glossaire

Terme

Définition

Diviser pour régnerMéthode consistant à décomposer un problème, résoudre les parties puis combiner les résultats.
FusionCombinaison ordonnée de deux séquences déjà triées.
Cas de baseSituation élémentaire arrêtant la récursion.
StablePréserve l’ordre relatif des éléments ayant la même clé.
Tableau auxiliaireZone temporaire utilisée pour stocker les résultats d’une fusion.
Tri externeTri de données ne tenant pas entièrement en mémoire principale.
Top-downVersion récursive qui divise avant de fusionner.
Bottom-upVersion itérative qui fusionne des blocs de tailles croissantes.
Invariant de fusionPropriété selon laquelle le résultat partiel contient les plus petits éléments déjà traités, dans l’ordre.

 

Auto-évaluation

Je suis capable de…

Oui

À revoir

expliquer les trois étapes du tri fusion ;

fusionner manuellement deux tableaux triés ;

écrire la procédure de fusion complète ;

identifier le cas de base et les deux appels récursifs ;

réaliser une trace des divisions et des fusions ;

justifier la complexité Theta(n log n) ;

expliquer le coût mémoire O(n) sur un tableau ;

préserver la stabilité pendant la fusion ;

adapter la méthode à une liste chaînée ;

choisir le tri fusion dans un contexte approprié.

 

Conclusion

Le tri fusion illustre de manière complète la méthode « diviser pour régner ». Sa fusion linéaire, sa complexité garantie en Theta(n log n) et sa stabilité en font un algorithme de référence. Il est particulièrement pertinent pour les listes chaînées, les tris externes et les applications exigeant des performances prévisibles. Sa compréhension prépare directement l’étude du tri rapide, des relations de récurrence et d’autres algorithmes récursifs avancés.