Maintenant que nous disposons de tableaux pour stocker de grandes quantités de données, il faut qu'on apprenne à les classer. Il existe de nombreux algorithmes de tri plus ou moins efficaces, qui sont pour la plupart répertoriées dans The Art of Computer Programming, Volume 3, Sorting and Searching. de Knuth, Donald. E. [1998]. Le livre de chevet de tout programmeur.

Problématique

Comment ranger des données afin de faciliter leur accès futur ? C'est par exemple l'ordre alphabétique du dictionnaire, où les mots sont rangés dans un ordre logique qui permet de ne pas devoir parcourir tout l'ouvrage pour retrouver une définition. Ce peut être aussi l'ordre intuitif dans lequel un joueur de cartes va ranger son jeu afin de limiter le temps de recherche pendant le déroulement de la partie. Cette problématique permet d'introduire la notion de tri (avec plusieurs sens distincts : séparer, ordonner, choisir), puis d'étudier différents algorithmes de tri. Le tri permet essentiellement d'accélérer les recherches, grâce à l'algorithme de recherche dichotomique.

Source eduscol

Situation d'accroche

Un joueur de cartes reçoit 9 cartes lors de la donne en début de partie ; il les trie ensuite pour faciliter la lecture de son jeu.

  • Comment procède-t-il exactement pour réaliser cette opération ?
  • Y a-t-il plusieurs façons de procéder :

Vous rendre sur cette page sur laquelle vous est proposé un jeu de cartes à trier:

https://github.com/benjaminabel/order-cards-game.

Réalisez les consignes suivantes dans l'ordre.

  1. Consigne n° 1: « triez les cartes » en notant le nombre d'opérations nécessaires au tri, recommencer l'opération pour voir si le nombre de tours d'algorithmes varie, et de quoi peut dépendre ce nombre. Ensuite seulement,
  2. Consigne n° 2: « décrivez par écrit la façon précise dont vous vous y êtes pris pour effectuer le tri ».
  3. En plus, imaginez d'autres méthodes qui pourraient être plus efficaces pour effectuer le tri.

Implémentations en python

Nous allons maintenant voir comment implémenter deux algorithmes de tri pas forcément très efficaces, mais relativement simples en python:

  • le tri par sélection
  • le tri par insertion

Créer une liste de données aléatoire

Commencer par créer des données de façon aléatoire grâce au module random afin de pouvoir les classer.


Entrée
# Importer le module random pour créer des nombres au hasard
import random

def genere_liste_aleatoire(N, n):
    """Génére une liste aléatoire de N éléments compris entre 0 et n"""
    # Créer une liste vide pour accueillir les nombres
    data = []
    # ajoute les éléments aléatoires dans la liste
    for i in range(N):
        data.append(random.randrange(n))
    return data

# Création d'une liste de 50 valeurs comprises entre 0 et 100
liste_aléatoire = genere_liste_aleatoire(50, 100)
print(liste_aléatoire)
Sortie
[42, 1, 19, 89, 75, 1, 43, 77, 65, 80, 81, 32, 93, 54, 87, 5, 15, 96, 98, 23, 39, 39, 58, 7, 73, 1, 96, 68, 41, 47, 13, 36, 97, 68, 68, 10, 1, 34, 76, 65, 8, 80, 57, 96, 26, 54, 65, 4, 69, 52]

Le tri par sélection

Principe

Sur un tableau de n éléments (numérotés de 0 à n), le principe du tri par sélection est le suivant :

Source Wikipedia

Illustration graphique

Selection-Sort-Animation

Illustration en vidéo

Thumbnail of Youtube video Ns4TPTC8whw

Select-sort with Gypsy folk dance. Created at Sapientia University, Tirgu Mures (Marosvásárhely), Romania. Directed by Kátai Zoltán and Tóth László. In cooperation with "Maros Művészegyüttes", Tirgu Mures (Marosvásárhely), Romania.

Implémentation en python

Voici un exemple de code implémentant cet algorithme de tri présentant l'état de la liste à chaque tour avancée dans le tableau. Vous pouvez voir que le tableau est bien classé en plaçant systématiquement l'élément minimum du tableau restant à trier à la fin des éléments triés.


Entrée
# Création d'une liste de 10 valeurs comprises entre 0 et 100 à trier
data = genere_liste_aleatoire(10, 100)
print("Liste initiale: ", data)

# Calculer la taille du tableau
N = len(data)
# Parcourir le tableau entier
for i in range(N):
    print('-' * 80)
    print("i= ", i)
    # Stocker la valeur initiale de la case d'indice i, et son indice
    minimum = data[i]
    i_min = i
    #  Parcourir le reste du tableau pour rechercher l'élément le plus petit restant
    for j in range(i, N):
        if data[j] < minimum:
            # Stocker la valeur du minimum et son indice
            minimum = data[j]
            i_min = j
    # Intervertir la valeur initiale de la case d'indice i et le minimum trouvé
    tmp = data[i]
    data[i] = minimum
    data[i_min] = tmp
    # Affiche les états intermédiaires de la liste
    print("Etat de la liste:", data)
    print("Éléments triés: ", data[:i+1], "Reste à trier: ", data[i+1:N])

print("Liste triée: ", data)
Sortie
Liste initiale:  [92, 77, 24, 67, 51, 34, 93, 27, 49, 3]
--------------------------------------------------------------------------------
i=  0
Etat de la liste: [3, 77, 24, 67, 51, 34, 93, 27, 49, 92]
Éléments triés:  [3] Reste à trier:  [77, 24, 67, 51, 34, 93, 27, 49, 92]
--------------------------------------------------------------------------------
i=  1
Etat de la liste: [3, 24, 77, 67, 51, 34, 93, 27, 49, 92]
Éléments triés:  [3, 24] Reste à trier:  [77, 67, 51, 34, 93, 27, 49, 92]
--------------------------------------------------------------------------------
i=  2
Etat de la liste: [3, 24, 27, 67, 51, 34, 93, 77, 49, 92]
Éléments triés:  [3, 24, 27] Reste à trier:  [67, 51, 34, 93, 77, 49, 92]
--------------------------------------------------------------------------------
i=  3
Etat de la liste: [3, 24, 27, 34, 51, 67, 93, 77, 49, 92]
Éléments triés:  [3, 24, 27, 34] Reste à trier:  [51, 67, 93, 77, 49, 92]
--------------------------------------------------------------------------------
i=  4
Etat de la liste: [3, 24, 27, 34, 49, 67, 93, 77, 51, 92]
Éléments triés:  [3, 24, 27, 34, 49] Reste à trier:  [67, 93, 77, 51, 92]
--------------------------------------------------------------------------------
i=  5
Etat de la liste: [3, 24, 27, 34, 49, 51, 93, 77, 67, 92]
Éléments triés:  [3, 24, 27, 34, 49, 51] Reste à trier:  [93, 77, 67, 92]
--------------------------------------------------------------------------------
i=  6
Etat de la liste: [3, 24, 27, 34, 49, 51, 67, 77, 93, 92]
Éléments triés:  [3, 24, 27, 34, 49, 51, 67] Reste à trier:  [77, 93, 92]
--------------------------------------------------------------------------------
i=  7
Etat de la liste: [3, 24, 27, 34, 49, 51, 67, 77, 93, 92]
Éléments triés:  [3, 24, 27, 34, 49, 51, 67, 77] Reste à trier:  [93, 92]
--------------------------------------------------------------------------------
i=  8
Etat de la liste: [3, 24, 27, 34, 49, 51, 67, 77, 92, 93]
Éléments triés:  [3, 24, 27, 34, 49, 51, 67, 77, 92] Reste à trier:  [93]
--------------------------------------------------------------------------------
i=  9
Etat de la liste: [3, 24, 27, 34, 49, 51, 67, 77, 92, 93]
Éléments triés:  [3, 24, 27, 34, 49, 51, 67, 77, 92, 93] Reste à trier:  []
Liste triée:  [3, 24, 27, 34, 49, 51, 67, 77, 92, 93]

Le tri par insertion

Principe

Dans l'algorithme, on parcourt le tableau à trier du début à la fin. Au moment où on considère le i-ème élément, les éléments qui le précèdent sont déjà triés. Pour faire l'analogie avec l'exemple du jeu de cartes, lorsqu'on est à la i-ème étape du parcours, le i-ème élément est la carte saisie, les éléments précédents sont la main triée et les éléments suivants correspondent aux cartes encore mélangées sur la table.

L'objectif d'une étape est d'insérer le i-ème élément à sa place parmi ceux qui précèdent. Il faut pour cela trouver où l'élément doit être inséré en le comparant aux autres, puis décaler les éléments afin de pouvoir effectuer l'insertion. En pratique, ces deux actions sont fréquemment effectuées en une passe, qui consiste à faire « remonter » l'élément au fur et à mesure jusqu'à rencontrer un élément plus petit.

Source Wikipedia

Illustration graphique

Insertion-sort-example-300px.gif
"Insertion-sort-example-300px" by Swfung8 - Own work. Licensed under CC BY-SA 3.0 via Wikimedia Commons.

Illustration en vidéo

Thumbnail of Youtube video ROalU379l3U

Insert-sort with Romanian folk dance. Created at Sapientia University, Tirgu Mures (Marosvásárhely), Romania. Directed by Kátai Zoltán and Tóth László. In cooperation with "Maros Művészegyüttes", Tirgu Mures (Marosvásárhely), Romania.

Implémentation en python

Voici un exemple d'implémentation ou le tableau est parcouru de la gauche vers la droite, observer bien ou est placée la valeur à insérer à chaque tour de la boucle.


Entrée
# Création d'une liste de 10 valeurs comprises entre 0 et 100 à trier
data = genere_liste_aleatoire(10, 100)
print("Liste initiale: ", data)

# Parcourir l'ensemble de la liste à partir de la deuxième case
for i in range(1, len(data)):
    print('-' * 80)
    print("i= ", i)
    # Stocker la valeur à "insérer"
    val = data[i]
    print("Valeur à insérer:", val)
    # Parcourir le tableau déjà trié de dimension i-1 vers la gauche
    # jusqu'à rencontrer une valeur inférieure à notre valeur à insérer
    j = i - 1
    while data[j] > val and j >=0:
        # Intervertir  les valeurs aux indices j et j+1
        data[j+1] = data[j]
        data[j] = val
        # Diminuer j de 1 pour la prochaine comparaison
        j = j - 1
        print("On remonte la valeur <-", data)
    print("Etat intérmédiaire de la liste: ", data)
# Afficher le résultat
print('\nListe triée:')
print(data)
Sortie
Liste initiale:  [75, 53, 97, 76, 13, 10, 98, 10, 46, 65]
--------------------------------------------------------------------------------
i=  1
Valeur à insérer: 53
On remonte la valeur <- [53, 75, 97, 76, 13, 10, 98, 10, 46, 65]
Etat intérmédiaire de la liste:  [53, 75, 97, 76, 13, 10, 98, 10, 46, 65]
--------------------------------------------------------------------------------
i=  2
Valeur à insérer: 97
Etat intérmédiaire de la liste:  [53, 75, 97, 76, 13, 10, 98, 10, 46, 65]
--------------------------------------------------------------------------------
i=  3
Valeur à insérer: 76
On remonte la valeur <- [53, 75, 76, 97, 13, 10, 98, 10, 46, 65]
Etat intérmédiaire de la liste:  [53, 75, 76, 97, 13, 10, 98, 10, 46, 65]
--------------------------------------------------------------------------------
i=  4
Valeur à insérer: 13
On remonte la valeur <- [53, 75, 76, 13, 97, 10, 98, 10, 46, 65]
On remonte la valeur <- [53, 75, 13, 76, 97, 10, 98, 10, 46, 65]
On remonte la valeur <- [53, 13, 75, 76, 97, 10, 98, 10, 46, 65]
On remonte la valeur <- [13, 53, 75, 76, 97, 10, 98, 10, 46, 65]
Etat intérmédiaire de la liste:  [13, 53, 75, 76, 97, 10, 98, 10, 46, 65]
--------------------------------------------------------------------------------
i=  5
Valeur à insérer: 10
On remonte la valeur <- [13, 53, 75, 76, 10, 97, 98, 10, 46, 65]
On remonte la valeur <- [13, 53, 75, 10, 76, 97, 98, 10, 46, 65]
On remonte la valeur <- [13, 53, 10, 75, 76, 97, 98, 10, 46, 65]
On remonte la valeur <- [13, 10, 53, 75, 76, 97, 98, 10, 46, 65]
On remonte la valeur <- [10, 13, 53, 75, 76, 97, 98, 10, 46, 65]
Etat intérmédiaire de la liste:  [10, 13, 53, 75, 76, 97, 98, 10, 46, 65]
--------------------------------------------------------------------------------
i=  6
Valeur à insérer: 98
Etat intérmédiaire de la liste:  [10, 13, 53, 75, 76, 97, 98, 10, 46, 65]
--------------------------------------------------------------------------------
i=  7
Valeur à insérer: 10
On remonte la valeur <- [10, 13, 53, 75, 76, 97, 10, 98, 46, 65]
On remonte la valeur <- [10, 13, 53, 75, 76, 10, 97, 98, 46, 65]
On remonte la valeur <- [10, 13, 53, 75, 10, 76, 97, 98, 46, 65]
On remonte la valeur <- [10, 13, 53, 10, 75, 76, 97, 98, 46, 65]
On remonte la valeur <- [10, 13, 10, 53, 75, 76, 97, 98, 46, 65]
On remonte la valeur <- [10, 10, 13, 53, 75, 76, 97, 98, 46, 65]
Etat intérmédiaire de la liste:  [10, 10, 13, 53, 75, 76, 97, 98, 46, 65]
--------------------------------------------------------------------------------
i=  8
Valeur à insérer: 46
On remonte la valeur <- [10, 10, 13, 53, 75, 76, 97, 46, 98, 65]
On remonte la valeur <- [10, 10, 13, 53, 75, 76, 46, 97, 98, 65]
On remonte la valeur <- [10, 10, 13, 53, 75, 46, 76, 97, 98, 65]
On remonte la valeur <- [10, 10, 13, 53, 46, 75, 76, 97, 98, 65]
On remonte la valeur <- [10, 10, 13, 46, 53, 75, 76, 97, 98, 65]
Etat intérmédiaire de la liste:  [10, 10, 13, 46, 53, 75, 76, 97, 98, 65]
--------------------------------------------------------------------------------
i=  9
Valeur à insérer: 65
On remonte la valeur <- [10, 10, 13, 46, 53, 75, 76, 97, 65, 98]
On remonte la valeur <- [10, 10, 13, 46, 53, 75, 76, 65, 97, 98]
On remonte la valeur <- [10, 10, 13, 46, 53, 75, 65, 76, 97, 98]
On remonte la valeur <- [10, 10, 13, 46, 53, 65, 75, 76, 97, 98]
Etat intérmédiaire de la liste:  [10, 10, 13, 46, 53, 65, 75, 76, 97, 98]

Liste triée:
[10, 10, 13, 46, 53, 65, 75, 76, 97, 98]

Autres algorithmes

Ces deux algorithmes ne sont que des exemples d'algorithmes de tri, et il en existe bien d'autres plus efficace comme le fameux quicksort, ou le timsort utilisé comme algorithme par défaut en Python.

La littérature ne manque pas sur ce sujet car il s'agit d'une introduction de choix à de nombreux concepts clés de l'algorithmique:

Vous pouvez consulter cet article du site interstices.info pour en savoir plus.