Les algorithmes de tri et de recherche

4SI

Objectifs

À la fin de ce chapitre, l’élève doit être capable de :

  • trier un tableau d’entiers ou de chaînes par ordre croissant ou décroissant, selon quatre méthodes ;
  • dérouler à la main chacune de ces méthodes sur un petit tableau ;
  • rechercher un élément dans un tableau, de façon séquentielle ou dichotomique ;
  • choisir une méthode de recherche selon que le tableau est trié ou non ;
  • comparer les méthodes de tri selon le travail qu’elles effectuent.

Plan du chapitre

  1. Introduction
  2. Vocabulaire et exemple du chapitre
  3. Le tri à bulles
  4. Le tri par sélection
  5. La recherche d’un élément
  6. Le tri par insertion
  7. Le tri shell
  8. Comparaison des quatre tris
  9. Les erreurs les plus fréquentes
  10. Retenons

Les parties 3, 4 et 5 sont des rappels de 3ᵉ année ; les parties 6 et 7 sont nouvelles en 4ᵉ année.

1. Introduction

Activité 1

Un lycée compte 1 000 candidats au baccalauréat de la session 2027. Leurs noms sont rangés dans un tableau. Un parent vient demander si le nom de sa fille figure dans la liste.

Questions

  1. La liste est dans l’ordre des inscriptions. Combien de noms faut-il examiner, au pire, pour répondre ?
  2. La liste est maintenant dans l’ordre alphabétique. On ouvre la liste en son milieu : que peut-on conclure en comparant le nom cherché au nom trouvé à cet endroit ?
  3. En répétant ce procédé, combien de noms faut-il examiner, au pire ?

Réponse

Dans une liste en désordre, rien n’indique où se trouve le nom : il faut examiner les noms un par un, soit 1 000 noms au pire, lorsque le nom est absent ou placé en dernier.

Dans une liste triée, une seule comparaison avec le nom du milieu élimine la moitié de la liste : si le nom cherché vient avant dans l’alphabet, il ne peut se trouver que dans la première moitié, sinon dans la seconde. En répétant ce procédé, la partie restante est divisée par deux à chaque étape : 1 000, 500, 250, 125, 62, 31, 15, 7, 3, 1. Il suffit d’examiner 10 noms au pire.

Trier un tableau a donc un intérêt immédiat : cela rend la recherche beaucoup plus rapide. Ce chapitre étudie les deux questions ensemble : comment trier un tableau, et comment y rechercher un élément.

2. Vocabulaire et exemple du chapitre

2.1 Trier un tableau

Définition. Trier un tableau, c’est réorganiser ses éléments de façon qu’ils soient rangés dans un ordre donné : croissant, du plus petit au plus grand, ou décroissant, du plus grand au plus petit.

Toutes les méthodes de ce chapitre trient le tableau sur place : elles ne créent pas de second tableau, elles déplacent les éléments à l’intérieur du tableau lui-même. Le tableau est donc passé par référence (par adresse) à la procédure de tri : @T.

Pour décrire le travail d’une méthode, on utilise quatre mots.

MotSens
Parcoursun passage complet sur le tableau, ou sur une partie du tableau ; on dit aussi une passe
Comparaisonun test entre deux éléments, par exemple T[i] > T[i + 1]
Permutationl’échange du contenu de deux cases, à l’aide d’une variable auxiliaire
Décalagela copie d’un élément dans la case voisine, pour libérer une place

La permutation de deux cases s’écrit toujours en trois affectations :

Aux ← T[i]
T[i] ← T[j]
T[j] ← Aux

Remarque importante. L’ordre des trois affectations est imposé. Écrire T[i] ← T[j] en premier effacerait définitivement l’ancienne valeur de T[i].

2.2 L’exemple du chapitre

Toutes les méthodes du chapitre sont déroulées sur le même tableau de 7 entiers, afin de pouvoir les comparer à la fin :

T6285193
0123456

Après le tri par ordre croissant, il doit contenir :

T1235689
0123456

Les modules du chapitre utilisent le type suivant :

TDNT

Nouveau type
Tab = Tableau de 20 Entiers

Pour chaque méthode, on comptera le nombre de parcours, de comparaisons et de permutations ou de décalages nécessaires pour trier ce tableau.

2.3 Trier des chaînes de caractères

Les chaînes se comparent avec les mêmes opérateurs que les nombres : <, >, =. La comparaison se fait caractère par caractère, de gauche à droite, selon le code ASCII : "Amine" < "Chaima" est vrai, puisque Ord("A") = 65 est inférieur à Ord("C") = 67.

Toutes les méthodes de ce chapitre s’appliquent donc sans modification à un tableau de chaînes : seul le type du tableau change.

Remarque importante. Les majuscules ont des codes plus petits que les minuscules : "amine" < "Yasmine" est faux, puisque Ord("a") = 97 est supérieur à Ord("Y") = 89. Pour trier des noms dans l’ordre alphabétique, ils doivent être écrits de la même façon, par exemple avec une majuscule initiale.

3. Le tri à bulles

3.1 Principe

On parcourt le tableau en comparant chaque élément à son voisin de droite ; s’ils sont dans le mauvais ordre, on les permute. À la fin d’un parcours, le plus grand élément rencontré est arrivé en dernière position, comme une bulle qui remonte à la surface. On recommence les parcours tant qu’un parcours a produit au moins une permutation.

Premier parcours sur l’exemple du chapitre

iComparaisonPermutation ?Tableau après
0T[0] = 6 > T[1] = 2oui2 6 8 5 1 9 3
1T[1] = 6 > T[2] = 8non2 6 8 5 1 9 3
2T[2] = 8 > T[3] = 5oui2 6 5 8 1 9 3
3T[3] = 8 > T[4] = 1oui2 6 5 1 8 9 3
4T[4] = 8 > T[5] = 9non2 6 5 1 8 9 3
5T[5] = 9 > T[6] = 3oui2 6 5 1 8 3 9

Après ce premier parcours, le plus grand élément, 9, occupe la dernière case.

3.2 Méthode 1 : répéter tant qu’il y a des permutations

Procédure Tri_Bulles (@T : Tab, n : Entier)
DEBUT
    Répéter
        Permut ← Faux
        Pour i de 0 à n - 2 Faire
            Si T[i] > T[i + 1] Alors
                Aux ← T[i]
                T[i] ← T[i + 1]
                T[i + 1] ← Aux
                Permut ← Vrai
            FinSi
        Fin Pour
    Jusqu'à Non(Permut)
FIN

TDOL

ObjetType / Nature
i, AuxEntier
PermutBooléen

La variable Permut est un drapeau : elle passe à Vrai dès qu’une permutation a lieu. Un parcours qui la laisse à Faux prouve que le tableau est trié.

Trace sur l’exemple du chapitre : état du tableau à la fin de chaque parcours.

Départ6285193
Parcours 12651839
Parcours 22516389
Parcours 32153689
Parcours 41235689
Parcours 51235689
0123456

Le parcours 5 ne produit aucune permutation : Permut reste à Faux et le tri s’arrête. Bilan : 5 parcours, 30 comparaisons, 11 permutations.

En détail

Le parcours 5 ne modifie rien, mais il est nécessaire : c’est lui qui constate que le tableau est trié. Sur un tableau déjà trié, la méthode 1 ne fait qu’un seul parcours.

3.3 Méthode 2 : la forme de référence en 4ᵉ année

La méthode 1 compare à chaque parcours tout le tableau, y compris la fin, qui est déjà en place : après le parcours 1, la case 6 contient définitivement 9 ; après le parcours 2, les cases 5 et 6 contiennent définitivement 8 et 9. La méthode 2 réduit la zone parcourue d’une case à chaque fois, en décrémentant n après chaque parcours : n représente alors le nombre de cases qui restent à trier.

Procédure Tri_Bulles (@T : Tab, n : Entier)
DEBUT
    Répéter
        Permut ← Faux
        Pour i de 0 à n - 2 Faire
            Si T[i] > T[i + 1] Alors
                Aux ← T[i]
                T[i] ← T[i + 1]
                T[i + 1] ← Aux
                Permut ← Vrai
            FinSi
        Fin Pour
        n ← n - 1
    Jusqu'à Non(Permut) Ou (n = 1)
FIN

TDOL

ObjetType / Nature
i, AuxEntier
PermutBooléen

Trace sur l’exemple du chapitre. Les cases entre crochets sont celles que le parcours a placées définitivement : elles ne seront plus parcourues.

Départ6285193
Parcours 12651839
Parcours 22516389
Parcours 32153689
Parcours 41235689
Parcours 51235689
0123456
Parcoursi varie de 0 àComparaisonsPermutationsn en fin de parcoursPermut
15646Vrai
24535Vrai
33424Vrai
42323Vrai
51202Faux

Bilan : 5 parcours, 20 comparaisons, 11 permutations. Les permutations sont les mêmes que dans la méthode 1 ; seules les comparaisons inutiles ont disparu : 20 au lieu de 30.

Remarque importante. Le paramètre n est passé par valeur : la procédure travaille sur une copie de n. La décrémenter ne modifie pas la variable n du programme appelant, qui garde la taille du tableau ; seul le tableau T, passé par référence (par adresse), est modifié.

Remarque importante. La condition d’arrêt est une disjonction : on s’arrête si plus rien ne permute, ou s’il ne reste qu’une case à trier. Sans Ou (n = 1), un tableau qui permute jusqu’au dernier parcours utile en ferait un de plus, vide, avec la borne n - 2 = -1.

En détail

On aurait pu recopier n dans une variable locale, par exemple NC ← n, et décrémenter NC. Le tri serait le même, avec les mêmes parcours et les mêmes comparaisons. Décrémenter n directement économise seulement une variable locale et une affectation : c’est un gain de mémoire minime, et aucun gain de temps.

En Python

def Tri_Bulles(T, n):
    Permut = True
    while Permut and n > 1:
        Permut = False
        for i in range(n - 1):
            if T[i] > T[i + 1]:
                Aux = T[i]
                T[i] = T[i + 1]
                T[i + 1] = Aux
                Permut = True
        n = n - 1

En détail

Python n’a pas de boucle Répéter … Jusqu'à. La boucle while continue tant que la condition d’arrêt est fausse : Non(Non(Permut) Ou (n = 1)), c’est-à-dire Permut and n > 1. L’initialisation Permut = True garantit le premier parcours.

4. Le tri par sélection

4.1 Principe

On sélectionne le plus petit élément du tableau et on le place dans la première case, par une permutation. Puis on sélectionne le plus petit des éléments restants et on le place dans la deuxième case, et ainsi de suite jusqu’à l’avant-dernière case. La dernière case contient alors forcément le plus grand élément.

4.2 Algorithme

Procédure Tri_Selection (@T : Tab, n : Entier)
DEBUT
    Pour i de 0 à n - 2 Faire
        posmin ← i
        Pour j de i + 1 à n - 1 Faire
            Si T[j] < T[posmin] Alors
                posmin ← j
            FinSi
        Fin Pour
        Si posmin ≠ i Alors
            Aux ← T[i]
            T[i] ← T[posmin]
            T[posmin] ← Aux
        FinSi
    Fin Pour
FIN

TDOL

ObjetType / Nature
i, j, posmin, AuxEntier

La boucle intérieure est la recherche de la position du minimum, déjà rencontrée avec la fonction pos_min_tab, mais limitée à la partie du tableau qui commence en i.

4.3 Trace sur l’exemple du chapitre

iposminMinimumPermutation
041T[0] ↔ T[4]
112aucune, 2 est déjà en place
263T[2] ↔ T[6]
335aucune
446aucune
568T[5] ↔ T[6]

Les cases entre crochets sont définitivement placées.

Départ6285193
i = 01285693
i = 11285693
i = 21235698
i = 31235698
i = 41235698
i = 51235689
0123456

Bilan : 6 parcours, 21 comparaisons, 3 permutations. Le tri par sélection fait toujours le même nombre de comparaisons, quel que soit l’ordre de départ, mais très peu de permutations : au plus une par parcours.

En détail

Le test Si posmin ≠ i évite de permuter une case avec elle-même. Sans lui, le tri resterait correct, mais on compterait ici 6 permutations au lieu de 3.

En Python

def Tri_Selection(T, n):
    for i in range(n - 1):
        posmin = i
        for j in range(i + 1, n):
            if T[j] < T[posmin]:
                posmin = j
        if posmin != i:
            Aux = T[i]
            T[i] = T[posmin]
            T[posmin] = Aux

5. La recherche d’un élément

5.1 La recherche séquentielle

On examine les éléments un par un, du premier au dernier, jusqu’à trouver l’élément cherché ou atteindre la fin du tableau. Cette méthode s’applique à n’importe quel tableau, trié ou non.

Elle s’écrit de quatre façons, toutes correctes : deux avec la boucle Tant que, deux avec la boucle Répéter … Jusqu'à.

Méthode 1 : avec un drapeau

Fonction Recherche_sequentielle (T : Tab, n, x : Entier) : Booléen
DEBUT
    Trouve ← Faux
    i ← 0
    Tant que (i < n) Et (Non(Trouve)) Faire
        Si T[i] = x Alors
            Trouve ← Vrai
        Sinon
            i ← i + 1
        FinSi
    Fin Tant que
    Retourner Trouve
FIN

TDOL

ObjetType / Nature
TrouveBooléen
iEntier

Méthode 2 : la condition dans la boucle

Fonction Recherche_sequentielle (T : Tab, n, x : Entier) : Booléen
DEBUT
    i ← 0
    Tant que (i < n) Et (T[i] ≠ x) Faire
        i ← i + 1
    Fin Tant que
    Retourner i < n
FIN

TDOL

ObjetType / Nature
iEntier

Dans la méthode 2, la boucle s’arrête pour l’une des deux raisons de sa condition. Si elle s’arrête parce que T[i] = x, alors i < n ; si elle s’arrête parce que i = n, l’élément est absent. La fonction retourne donc le résultat de la comparaison i < n.

**Méthode 3 : Répéter avec un drapeau**

Fonction Recherche_sequentielle (T : Tab, n, x : Entier) : Booléen
DEBUT
    Trouve ← Faux
    i ← 0
    Répéter
        Si T[i] = x Alors
            Trouve ← Vrai
        Sinon
            i ← i + 1
        FinSi
    Jusqu'à (Trouve) Ou (i = n)
    Retourner Trouve
FIN

TDOL

ObjetType / Nature
TrouveBooléen
iEntier

**Méthode 4 : Répéter avec la condition d’arrêt**

Fonction Recherche_sequentielle (T : Tab, n, x : Entier) : Booléen
DEBUT
    i ← -1
    Répéter
        i ← i + 1
    Jusqu'à (T[i] = x) Ou (i = n - 1)
    Retourner T[i] = x
FIN

TDOL

ObjetType / Nature
iEntier

Dans la méthode 4, i vaut au plus n - 1 à la sortie de la boucle : on ne peut donc pas retourner i < n, qui serait toujours vrai. On retourne le résultat du test T[i] = x. Lorsque x est le dernier élément, les deux conditions d’arrêt sont vraies en même temps, et c’est encore ce test qui donne la bonne réponse : sur l’exemple du chapitre, la recherche de 3 et la recherche de 4 s’arrêtent toutes deux en i = 6, la première retourne Vrai, la seconde Faux.

Remarque importante. La boucle Répéter exécute son corps au moins une fois : les méthodes 3 et 4 lisent T[0] avant tout test. Elles supposent donc que le tableau contient au moins un élément, n ≥ 1. Les méthodes 1 et 2, avec Tant que, fonctionnent aussi sur un tableau vide : c’est pourquoi on les préfère.

Trace sur l’exemple du chapitre, T = 6 2 8 5 1 9 3.

Recherche de 5

iT[i]T[i] ≠ 5
06Vrai
12Vrai
28Vrai
35Faux

Recherche de 4

iT[i]T[i] ≠ 4
0 à 66, 2, 8, 5, 1, 9, 3Vrai à chaque tour
7la boucle s’arrête : i < n est faux

La recherche de 5 s’arrête en i = 3 et retourne Vrai, après 4 comparaisons. La recherche de 4 parcourt tout le tableau et retourne Faux, après 7 comparaisons. Une recherche sans succès examine toujours tous les éléments.

En Python

Python n’a pas de boucle Répéter … Jusqu'à : on traduit les méthodes écrites avec Tant que. Voici la méthode 2.

def Recherche_sequentielle(T, n, x):
    i = 0
    while (i < n) and (T[i] != x):
        i = i + 1
    return i < n

5.2 La recherche dichotomique

Lorsque le tableau est trié, on compare l’élément cherché à l’élément du milieu de la zone de recherche. Selon le résultat, on poursuit la recherche dans la moitié gauche ou dans la moitié droite, et l’on recommence. La zone de recherche, délimitée par les indices d et f, est divisée par deux à chaque tour.

Fonction Recherche_dichotomique (T : Tab, n, x : Entier) : Booléen
DEBUT
    d ← 0
    f ← n - 1
    Trouve ← Faux
    Tant que (d ≤ f) Et (Non(Trouve)) Faire
        Milieu ← (d + f) Div 2
        Si T[Milieu] = x Alors
            Trouve ← Vrai
        Sinon Si T[Milieu] > x Alors
            f ← Milieu - 1
        Sinon
            d ← Milieu + 1
        FinSi
    Fin Tant que
    Retourner Trouve
FIN

TDOL

ObjetType / Nature
d, f, MilieuEntier
TrouveBooléen

La recherche dichotomique s’écrit aussi avec la boucle Répéter … Jusqu'à. La condition d’arrêt réunit les deux raisons de s’arrêter : l’élément est trouvé, ou la zone de recherche est vide.

Fonction Recherche_dichotomique (T : Tab, n, x : Entier) : Booléen
DEBUT
    d ← 0
    f ← n - 1
    Trouve ← Faux
    Répéter
        Milieu ← (d + f) Div 2
        Si T[Milieu] = x Alors
            Trouve ← Vrai
        Sinon Si T[Milieu] > x Alors
            f ← Milieu - 1
        Sinon
            d ← Milieu + 1
        FinSi
    Jusqu'à (Trouve) Ou (d > f)
    Retourner Trouve
FIN

Le TDOL est le même. Comme pour la recherche séquentielle, cette forme suppose n ≥ 1 : sur un tableau vide, le premier tour lirait T[0], qui n’existe pas.

Trace sur le tableau trié de l’exemple

T1235689
0123456
Recherche de 6dfMilieuT[Milieu]Décision
Tour 106355 < 6 : d ← 4
Tour 246588 > 6 : f ← 4
Tour 34446trouvé
Recherche de 4dfMilieuT[Milieu]Décision
Tour 106355 > 4 : f ← 2
Tour 202122 < 4 : d ← 2
Tour 322233 < 4 : d ← 3
Fin32d > f : absent

Sur ce tableau de 7 éléments, la dichotomie conclut toujours en 3 tours au plus, contre 7 pour la recherche séquentielle. L’écart grandit avec la taille : 10 tours au plus pour 1 000 éléments, 20 tours au plus pour un million.

En détail

Le nombre maximal de tours est le nombre de fois que l’on peut diviser n par 2 avant d’atteindre 1, plus un : 3 pour n = 7, 10 pour n = 1 000, 20 pour n = 1 000 000.

5.3 La condition indispensable : un tableau trié

Remarque importante. La recherche dichotomique ne s’applique qu’à un tableau trié. Sur un tableau non trié, elle ne signale aucune erreur : elle donne simplement une réponse fausse.

Exemple. On applique la recherche dichotomique au tableau non trié de l’exemple du chapitre, pour chercher 1.

T6285193
0123456
Recherche de 1dfMilieuT[Milieu]Décision
Tour 106355 > 1 : f ← 2
Tour 202122 > 1 : f ← 0
Tour 300066 > 1 : f ← -1
Fin0-1d > f : absent

La fonction retourne Faux, alors que 1 se trouve en T[4]. Au premier tour, la comparaison 5 > 1 a éliminé toute la moitié droite, parce qu’elle supposait que les éléments situés après 5 sont plus grands que 5. Sur ce tableau, la dichotomie déclare absents 4 des 7 éléments présents : 6, 8, 1 et 3.

C’est la raison d’être du couple tri et recherche : on trie une fois, puis chaque recherche est rapide.

Recherche séquentielleRecherche dichotomique
Tableauquelconquetrié obligatoirement
Principeexaminer les éléments un par undiviser la zone de recherche par deux
Tours au pire, n = 773
Tours au pire, n = 1 0001 00010

En Python

def Recherche_dichotomique(T, n, x):
    d = 0
    f = n - 1
    Trouve = False
    while (d <= f) and (not Trouve):
        Milieu = (d + f) // 2
        if T[Milieu] == x:
            Trouve = True
        elif T[Milieu] > x:
            f = Milieu - 1
        else:
            d = Milieu + 1
    return Trouve

6. Le tri par insertion

6.1 Principe

C’est la méthode du joueur de cartes qui range sa main : il prend les cartes une par une et insère chacune à sa place parmi celles qu’il tient déjà, qui sont rangées.

Au début de l’étape i, la partie gauche du tableau, de T[0] à T[i - 1], est déjà triée. On retire T[i] dans une variable aux, on décale d’une case vers la droite tous les éléments de la partie triée qui sont plus grands que aux, puis on dépose aux dans la case libérée.

6.2 Algorithme

Procédure Tri_Insertion (@T : Tab, n : Entier)
DEBUT
    Pour i de 1 à n - 1 Faire
        aux ← T[i]
        j ← i
        Tant que (j > 0) Et (T[j - 1] > aux) Faire
            T[j] ← T[j - 1]
            j ← j - 1
        Fin Tant que
        T[j] ← aux
    Fin Pour
FIN

TDOL

ObjetType / Nature
i, j, auxEntier

Remarque importante. Le tri par insertion ne permute pas : il décale. La valeur à insérer est mise de côté dans aux avant les décalages, qui écrasent la case T[i], puis elle est déposée une seule fois, dans T[j].

La boucle Pour commence à 1 : une partie triée d’un seul élément, T[0], est triée par définition. La boucle Tant que s’arrête dès que l’on rencontre un élément inférieur ou égal à aux, ou que l’on atteint le début du tableau.

6.3 Trace sur l’exemple du chapitre

iauxDécalagesaux déposé en
121T[0]
280T[2]
352T[1]
414T[0]
590T[5]
634T[2]

La case entre crochets est celle où aux vient d’être déposé.

Départ6285193
i = 12685193
i = 22685193
i = 32568193
i = 41256893
i = 51256893
i = 61235689
0123456

**Détail de l’étape i = 3** : aux ← 5, la partie triée est 2 6 8.

jTest T[j - 1] > auxAction
3T[2] = 8 > 5 : VraiT[3] ← 8, j ← 2
2T[1] = 6 > 5 : VraiT[2] ← 6, j ← 1
1T[0] = 2 > 5 : Fauxfin de la boucle, T[1] ← 5

Bilan : 6 parcours, 15 comparaisons, 11 décalages.

En détail

Le nombre de décalages est égal au nombre de permutations du tri à bulles : 11 dans les deux cas. Ce n’est pas un hasard : chacune de ces opérations corrige une et une seule paire d’éléments mal ordonnés. Mais un décalage est une seule affectation, alors qu’une permutation en demande trois.

Lorsque le tableau est déjà presque trié, le tri par insertion ne fait presque aucun décalage : aux étapes i = 2 et i = 5, aux reste en place après une seule comparaison.

En Python

def Tri_Insertion(T, n):
    for i in range(1, n):
        aux = T[i]
        j = i
        while j > 0 and T[j - 1] > aux:
            T[j] = T[j - 1]
            j = j - 1
        T[j] = aux

7. Le tri shell

7.1 Principe

Le tri par insertion ne déplace un élément que d’une case à la fois. À l’étape i = 4 de l’exemple, le 1 a dû traverser quatre cases, au prix de quatre décalages, pour aller de T[4] à T[0].

Le tri shell, du nom de son inventeur Donald Shell, corrige ce défaut. C’est un tri par insertion qui compare d’abord des éléments distants de p cases, appelé le pas, pour déplacer rapidement les éléments loin de leur position. Le pas est ensuite réduit, jusqu’à 1 : le dernier parcours utile est alors un tri par insertion ordinaire, mais sur un tableau presque trié.

7.2 Algorithme

Procédure Tri_Shell (@T : Tab, n : Entier)
DEBUT
    p ← 1
    Tant que p < n Faire
        p ← 3 * p + 1
    Fin Tant que
    Tant que p ≥ 1 Faire
        p ← p Div 3
        Pour i de p à n - 1 Faire
            aux ← T[i]
            j ← i
            Tant que (j ≥ p) Et (T[j - p] > aux) Faire
                T[j] ← T[j - p]
                j ← j - p
            Fin Tant que
            T[j] ← aux
        Fin Pour
    Fin Tant que
FIN

TDOL

ObjetType / Nature
p, i, j, auxEntier

Comparé au tri par insertion, le corps de la boucle Pour est le même, où le pas 1 est remplacé par le pas p : j - 1 devient j - p, et j > 0 devient j ≥ p.

7.3 Le calcul du pas

Le pas ne dépend que de n. La première boucle parcourt la suite 1, 4, 13, 40, 121, …, où chaque terme vaut 3p + 1, et s’arrête sur le premier terme qui atteint ou dépasse n. La seconde boucle redescend cette suite par divisions entières par 3, avant chaque parcours.

**Pour n = 7**

Première bouclepp < 7 ?
initialisation1Vrai
p ← 3 * 1 + 14Vrai
p ← 3 * 4 + 113Faux, fin

La seconde boucle applique ensuite les pas 13 Div 3 = 4, puis 4 Div 3 = 1, puis 1 Div 3 = 0.

7.4 Trace sur l’exemple du chapitre

Parcours de pas 4. Les éléments comparés sont distants de 4 cases : T[0] et T[4], T[1] et T[5], T[2] et T[6].

iauxComparaisonAction
41T[0] = 6 > 1 : VraiT[4] ← 6, puis T[0] ← 1
59T[1] = 2 > 9 : Faux9 reste en T[5]
63T[2] = 8 > 3 : VraiT[6] ← 8, puis T[2] ← 3
Départ6285193
Pas 41235698
Pas 11235689
Pas 01235689
0123456

Les cases entre crochets sont celles que le parcours a modifiées. Après le seul parcours de pas 4, le 1 a sauté directement de T[4] à T[0], et le 3 de T[6] à T[2] : il ne reste qu’une paire mal ordonnée, 9 et 8. Le parcours de pas 1 la corrige par un seul décalage.

Bilan : 3 parcours, 17 comparaisons, 3 décalages, contre 11 décalages pour le tri par insertion.

Le parcours de pas 0. Le dernier parcours s’exécute avec p = 0. La condition T[j - 0] > aux compare alors chaque élément à lui-même : elle est fausse d’emblée, et le tableau n’est pas modifié. Ce parcours coûte 7 comparaisons sur les 17 ; il est inutile, mais on le laisse s’exécuter pour garder l’algorithme simple.

7.5 Pourquoi le pas 3p + 1 ?

Le principe du tri shell fonctionne avec toute suite de pas qui se termine par 1. Mais toutes les suites ne se valent pas. La suite 3p + 1 est celle retenue dans ce cours, pour deux raisons :

  • elle se calcule à partir de n seul, par deux boucles très courtes ;
  • deux pas successifs, p et 3p + 1, ne sont jamais multiples l’un de l’autre, puisque (3p + 1) Mod p = 1 dès que p > 1 : un parcours ne se contente pas de refaire les comparaisons du précédent.

Une suite plus naturelle en apparence, qui divise le pas par 2 en partant de n Div 2, a un défaut : lorsque n est une puissance de 2, tous ses pas sont pairs sauf le dernier, et les éléments des cases paires ne sont jamais comparés à ceux des cases impaires avant le dernier parcours.

En détail

Donald Shell, qui a inventé ce tri en 1959, divisait le pas par 2. La suite 3p + 1 a été proposée plus tard par Donald Knuth.

En Python

def Tri_Shell(T, n):
    p = 1
    while p < n:
        p = 3 * p + 1
    while p >= 1:
        p = p // 3
        for i in range(p, n):
            aux = T[i]
            j = i
            while j >= p and T[j - p] > aux:
                T[j] = T[j - p]
                j = j - p
            T[j] = aux

8. Comparaison des quatre tris

8.1 Bilan sur l’exemple du chapitre

Tableau de départ : 6 2 8 5 1 9 3.

TriIdée en une phraseParcoursComparaisonsPermutations ou décalages
À bulles (méthode 2)Comparer chaque élément à son voisin et les permuter s’ils sont mal ordonnés, jusqu’à ce qu’un parcours ne permute plus rien.52011 permutations
Par sélectionChercher le plus petit des éléments restants et le placer à la suite de ceux déjà placés.6213 permutations
Par insertionPrendre chaque élément et l’insérer à sa place dans la partie gauche, déjà triée.61511 décalages
ShellTrier par insertion des éléments distants d’un pas p, puis réduire le pas jusqu’à 1.317, dont 7 au pas 03 décalages

8.2 Trier par ordre décroissant

Chacune des quatre méthodes trie par ordre décroissant en inversant la comparaison entre éléments, et rien d’autre :

TriOrdre croissantOrdre décroissant
À bullesT[i] > T[i + 1]T[i] < T[i + 1]
Par sélectionT[j] < T[posmin]T[j] > T[posmax]
Par insertionT[j - 1] > auxT[j - 1] < aux
ShellT[j - p] > auxT[j - p] < aux

Les comparaisons sur les indices, comme j > 0 ou i < n, ne changent pas.

Application résolue 1 — La liste d’appel

À la rentrée 2027, un professeur saisit les prénoms des élèves de son groupe dans l’ordre où ils se sont inscrits. Il veut obtenir la liste dans l’ordre alphabétique, retrouver rapidement un élève, et afficher les élèves dont le prénom commence par une lettre donnée.

Les prénoms sont rangés dans un tableau T de n chaînes de caractères, déclaré ainsi :

Nouveau type
TabCh = Tableau de 40 Chaînes de caractères

Exemple : n = 8.

TYasmineAmineRaniaChaimaOmarRamiInesFiras
01234567

Travail demandé

  1. Écrire l’algorithme de la procédure Trier(T, n) qui trie le tableau T par ordre alphabétique, selon la méthode du tri par insertion.
  2. Écrire l’algorithme de la fonction Position(T, n, p) qui retourne la position du prénom p dans le tableau T trié, ou -1 si ce prénom n’y figure pas. La recherche est dichotomique.
  3. Écrire l’algorithme de la procédure Afficher_Initiale(T, n, c) qui affiche, à raison d’un prénom par ligne, les prénoms du tableau T trié qui commencent par la lettre c. Le parcours s’arrête dès que les prénoms suivants ne peuvent plus commencer par c.

N.B. Le tableau T est déjà rempli. On suppose que les prénoms sont distincts et commencent tous par une majuscule suivie de minuscules : le candidat n’est pas appelé à les vérifier.

Voir le corrigé

1. Trier

C’est le tri par insertion du paragraphe 6.2, appliqué à un tableau de chaînes : seul le type de aux change.

Procédure Trier (@T : TabCh, n : Entier)
DEBUT
    Pour i de 1 à n - 1 Faire
        aux ← T[i]
        j ← i
        Tant que (j > 0) Et (T[j - 1] > aux) Faire
            T[j] ← T[j - 1]
            j ← j - 1
        Fin Tant que
        T[j] ← aux
    Fin Pour
FIN

TDOL

ObjetType / Nature
i, jEntier
auxChaîne de caractères

Sur l’exemple, le tri fait 17 décalages et donne :

TAmineChaimaFirasInesOmarRamiRaniaYasmine
01234567

En détail

"Rami" < "Rania" est vrai : les trois premiers caractères sont égaux, et la comparaison se décide sur le quatrième, "m" contre "n".

2. Position

La fonction retourne un entier : la position, ou la valeur -1, qui ne peut pas être une position. Cette valeur sert aussi de condition d’arrêt : la boucle continue tant que la position n’a pas été trouvée.

Fonction Position (T : TabCh, n : Entier, p : Chaîne de caractères) : Entier
DEBUT
    d ← 0
    f ← n - 1
    pos ← -1
    Tant que (d ≤ f) Et (pos = -1) Faire
        Milieu ← (d + f) Div 2
        Si T[Milieu] = p Alors
            pos ← Milieu
        Sinon Si T[Milieu] > p Alors
            f ← Milieu - 1
        Sinon
            d ← Milieu + 1
        FinSi
    Fin Tant que
    Retourner pos
FIN

TDOL

ObjetType / Nature
d, f, Milieu, posEntier

Exemple. Sur le tableau trié, Position(T, 8, "Omar") retourne 4.

TourdfMilieuT[Milieu]Décision
1073InesInes < Omar : d ← 4
2475RamiRami > Omar : f ← 4
3444Omartrouvé : pos ← 4

Position(T, 8, "Salma") retourne -1, après 4 tours.

En détail

Comparée à la fonction Recherche_dichotomique du paragraphe 5.2, cette fonction remplace le drapeau Trouve par la variable pos, qui porte à la fois le succès de la recherche et la position trouvée.

3. Afficher_Initiale

Le tableau étant trié, les prénoms qui commencent par c sont consécutifs. Une première boucle saute les prénoms dont l’initiale précède c ; une seconde affiche les prénoms qui commencent par c, et s’arrête au premier qui ne commence plus par c.

Procédure Afficher_Initiale (T : TabCh, n : Entier, c : Caractère)
DEBUT
    i ← 0
    Tant que (i < n) Et (T[i][0] < c) Faire
        i ← i + 1
    Fin Tant que
    Tant que (i < n) Et (T[i][0] = c) Faire
        Écrire_nl(T[i])
        i ← i + 1
    Fin Tant que
FIN

TDOL

ObjetType / Nature
iEntier

Exemple. Afficher_Initiale(T, 8, "R") affiche :

Rami
Rania

Le parcours s’arrête sur T[7] = "Yasmine", sans avoir à examiner d’autres prénoms.

En détail

Sur un tableau non trié, il faudrait parcourir tout le tableau, puisqu’un prénom en R pourrait se trouver n’importe où. C’est l’ordre du tableau qui autorise l’arrêt anticipé.

Application résolue 2 — Le concours de programmation

Le club d’informatique d’un lycée organise en 2027 un concours de programmation. Les scores des équipes, des entiers positifs, sont rangés dans un tableau S de n entiers. Le jury veut afficher le classement du meilleur au moins bon score, ajouter le score d’une équipe arrivée en retard sans refaire le tri, et vérifier si un score donné a été obtenu.

Exemple : n = 6.

S120851508520060
012345

Travail demandé

  1. Écrire l’algorithme de la procédure Trier_Decroissant(S, n) qui trie le tableau S par ordre décroissant, selon la méthode du tri shell.
  2. Écrire l’algorithme de la procédure Inserer(S, n, x) qui insère le score x dans le tableau S trié par ordre décroissant, de façon qu’il reste trié, et met à jour n.
  3. Écrire l’algorithme de la fonction Existe(S, n, x) qui vérifie, par une recherche dichotomique, si le score x figure dans le tableau S trié par ordre décroissant.

N.B. Le tableau S est déjà rempli ; il est déclaré de type Tab. On suppose que S contient moins de 20 scores avant l’insertion : le candidat n’est pas appelé à le vérifier.

Voir le corrigé

1. Trier_Decroissant

C’est le tri shell du paragraphe 7.2, dont la comparaison entre éléments est inversée.

Procédure Trier_Decroissant (@S : Tab, n : Entier)
DEBUT
    p ← 1
    Tant que p < n Faire
        p ← 3 * p + 1
    Fin Tant que
    Tant que p ≥ 1 Faire
        p ← p Div 3
        Pour i de p à n - 1 Faire
            aux ← S[i]
            j ← i
            Tant que (j ≥ p) Et (S[j - p] < aux) Faire
                S[j] ← S[j - p]
                j ← j - p
            Fin Tant que
            S[j] ← aux
        Fin Pour
    Fin Tant que
FIN

TDOL

ObjetType / Nature
p, i, j, auxEntier

Trace. Pour n = 6, les pas sont 4, 1 et 0.

Départ120851508520060
Pas 4200851508512060
Pas 1200150120858560
Pas 0200150120858560
012345

2. Inserer

On part de la fin du tableau et l’on décale vers la droite les scores plus petits que x, puis on dépose x dans la case libérée. C’est exactement une étape du tri par insertion.

Procédure Inserer (@S : Tab, @n : Entier, x : Entier)
DEBUT
    j ← n
    Tant que (j > 0) Et (S[j - 1] < x) Faire
        S[j] ← S[j - 1]
        j ← j - 1
    Fin Tant que
    S[j] ← x
    n ← n + 1
FIN

TDOL

ObjetType / Nature
jEntier

Exemple. L’insertion de 130 dans le tableau trié :

Avant200150120858560
Après200150130120858560
0123456

En détail

Le paramètre n est passé par référence (par adresse), @n, puisque la procédure modifie le nombre de scores. On ne retrie pas le tableau : il est déjà trié, et une seule étape d’insertion suffit à y placer le nouveau score.

3. Existe

C’est la recherche dichotomique du paragraphe 5.2 sur un tableau décroissant : les grands scores sont à gauche. Si l’élément du milieu est plus petit que x, le score cherché ne peut se trouver qu’à gauche.

Fonction Existe (S : Tab, n, x : Entier) : Booléen
DEBUT
    d ← 0
    f ← n - 1
    Trouve ← Faux
    Tant que (d ≤ f) Et (Non(Trouve)) Faire
        Milieu ← (d + f) Div 2
        Si S[Milieu] = x Alors
            Trouve ← Vrai
        Sinon Si S[Milieu] < x Alors
            f ← Milieu - 1
        Sinon
            d ← Milieu + 1
        FinSi
    Fin Tant que
    Retourner Trouve
FIN

TDOL

ObjetType / Nature
d, f, MilieuEntier
TrouveBooléen

Exemple. Sur le tableau trié 200 150 120 85 85 60, Existe(S, 6, 85) retourne Vrai et Existe(S, 6, 100) retourne Faux.

9. Les erreurs les plus fréquentes

Les erreurs suivantes sont relevées sur les algorithmes du cours. Chaque résultat a été obtenu en exécutant l’algorithme erroné sur l’exemple du chapitre, 6 2 8 5 1 9 3.

Instruction erronéeInstruction correcteConséquence
Bulles : Pour i de 0 à n - 1 FairePour i de 0 à n - 2 Faireau dernier tour, T[i + 1] désigne une case hors du tableau
Bulles : Jusqu'à PermutJusqu'à Non(Permut) Ou (n = 1)le tri s’arrête après le parcours 1 : 2 6 5 1 8 3 9
Bulles : Jusqu'à Non(Permut) Et (n = 1)Jusqu'à Non(Permut) Ou (n = 1)le résultat est juste, mais un tableau déjà trié coûte 6 parcours au lieu d’un
Sélection : posmin ← 0posmin ← ile minimum est recherché dans tout le tableau : 8 1 2 3 5 6 9
Insertion : T[i] ← aux après la boucleT[j] ← auxaux est reposé à son ancienne place : 6 6 2 8 1 9 3
Insertion : Tant que (j ≥ 0) Et …Tant que (j > 0) Et …pour j = 0, T[j - 1] désigne une case hors du tableau
Dichotomie : Tant que (d < f) Et …Tant que (d ≤ f) Et …la zone d’une seule case n’est jamais examinée : 1, 3, 6 et 9 sont déclarés absents du tableau trié
Dichotomie : Milieu ← (d + f) / 2Milieu ← (d + f) Div 2/ donne un réel, qui ne peut pas servir d’indice

10. Retenons

Trier. Trier un tableau, c’est ranger ses éléments dans l’ordre croissant ou décroissant. Les tris du chapitre travaillent sur place : le tableau est passé par référence (par adresse), @T.

Quatre méthodes. Bulles : permuter les voisins mal ordonnés. Sélection : placer le minimum des éléments restants. Insertion : insérer chaque élément dans la partie triée. Shell : insertion avec un pas décroissant 3p + 1, jusqu’à 1.

Bulles en 4ᵉ année. La forme de référence réduit la zone parcourue par n ← n - 1, n étant passé par valeur, et s’arrête par Jusqu'à Non(Permut) Ou (n = 1).

Rechercher. La recherche séquentielle s’applique à tout tableau. La recherche dichotomique exige un tableau trié ; elle divise la zone de recherche par deux à chaque tour.

Décroissant. On inverse la comparaison entre éléments, jamais les comparaisons sur les indices.

MéthodeTableauOpération de base
Tri à bullesquelconquepermutation de voisins
Tri par sélectionquelconquepermutation avec le minimum
Tri par insertionquelconquedécalage d’une case
Tri shellquelconquedécalage de p cases
Recherche séquentiellequelconquecomparaison un par un
Recherche dichotomiquetriécomparaison au milieu

Teste tes connaissances

Un quiz corrigé question par question, puis des flashcards pour mémoriser les notions du chapitre.

Animations des tris

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *