Adloun

Les tris

Cours · algorithmique (école d'ingénieur), chapitre 14 · école d'ingénieur, informatique · le début du chapitre, la suite sur Adloun

Objectifs du chapitre

  • Programmer, justifier par leurs invariants et analyser quatre tris classiques : par insertion, par fusion, par segmentation (tri rapide) et par tas.
  • Connaître leurs complexités dans le pire cas, en moyenne et dans le meilleur cas, et savoir les comparer expérimentalement.
  • Comprendre pourquoi aucun tri par comparaisons ne peut faire mieux que .

Trier un tableau, c'est réorganiser ses valeurs par ordre croissant. Le tri est partout : pour chercher par dichotomie (chapitre 12), pour détecter des doublons, pour afficher, pour fusionner des fichiers… C'est aussi un formidable terrain d'exercice : les quatre algorithmes de ce chapitre illustrent chacun une méthode du livre.

Définition 14.1Tableau trié

Le tableau est trié (par ordre croissant au sens large) si . Trier , c'est permuter ses valeurs de sorte qu'il soit trié.

Notation : pour deux sous-tableaux, on écrit si toute valeur du premier est inférieure ou égale à toute valeur du second.

14.1 Tri par insertion

C'est le tri du joueur de cartes : on prend les cartes une à une et on insère chacune à sa place parmi celles déjà en main, qui sont triées.

Invariant.

: « est trié (et contient les premières valeurs initiales) ».


static void triInsertion(int[] T) { int n = T.length;
    // I(k) : T[0:k] est trié (et contient les k premières valeurs initiales)
    for (int k = 1; k < n; k++) {      // I(1) : un 1-préfixe est trié
        int x = T[k], j = k;
        // J(j) : T[0:j] et T[j+1:k+1] triés, T[j+1:k+1] > x, case j libre
        while (j > 0 && T[j-1] > x) { T[j] = T[j-1]; j--; }
        T[j] = x;                      // I(k+1)
    }
    // I(n) : T[0:n] est trié
}
Exemple 14.2tri par insertion de
valeur insérée après insertion (puis le reste)décalages
121
290
313
461
533

En gras : le préfixe trié de l'invariant. Le nombre total de décalages, , est exactement le nombre d'inversions du tableau initial (couples tels que ).

Complexité.

L'insertion de fait au plus décalages.

À retenir

Le tri par insertion est quadratique, mais il est très rapide sur les petits tableaux et sur les tableaux « presque triés » (son temps de calcul est proportionnel à plus le nombre d'inversions). Les tris efficaces des bibliothèques l'utilisent pour finir le travail sur les petits sous-tableaux.

14.2 Tri par fusion

Le tri par fusion (merge sort, John von Neumann, 1945) est l'exemple type du « diviser pour régner » (chapitre 13) :


static void triFusion(int[] T) { triFusion(T, 0, T.length, new int[T.length]); }

static void triFusion(int[] T, int i, int j, int[] B) { // trie T[i:j]
    if (j - i <= 1) return;            // 0 ou 1 valeur : T[i:j] trié
    int k = (i + j) / 2;
    triFusion(T, i, k, B);             // T[i:k] trié
    triFusion(T, k, j, B);             // T[k:j] trié
    fusionner(T, i, k, j, B);          // T[i:j] trié
}

14.2.1 La fusion

Deux sous-tableaux triés et sont donnés. On construit leur fusion triée dans un tableau de travail , en prenant à chaque étape la plus petite des deux valeurs de tête.

Invariant de la fusion.

: « est la fusion triée de et , et , ». Comme , chaque tour place une valeur.


static void fusionner(int[] T, int i, int k, int j, int[] B) {
    int p = i, q = k, r = i;
    // I(p,q,r) : B[i:r] est la fusion triée de T[i:p] et T[k:q],
    //            et B[i:r] <= T[p:k], B[i:r] <= T[q:j]
    while (p < k && q < j)
        if (T[p] <= T[q]) B[r++] = T[p++];   // <= : le tri est stable
        else              B[r++] = T[q++];
    while (p < k) B[r++] = T[p++];      // reste de T[i:k]
    while (q < j) B[r++] = T[q++];      // reste de T[k:j]
    for (r = i; r < j; r++) T[r] = B[r];
}

La suite du cours est sur Adloun

Le chapitre en entier, formules et figures comprises, avec le tuteur, les fiches, les QCM et les exercices.

Lire la suite du cours

En accès libre, sans inscription.

Exercices corrigés de ce chapitre

Lire la suite du cours →