Algorithmes de tri, recherche et efficacité

Découvre comment les ordinateurs trouvent et ordonnent les données, et comment distinguer une méthode rapide d’une méthode lente. Suis la recherche séquentielle, la recherche dichotomique et trois algorithmes de tri classiques, le tri à bulles, le tri par sélection et le tri fusion, sur des listes concrètes. Compte les étapes de chacun, observe comment leur nombre augmente avec celui des données et prévois les temps d’exécution. Justifie ensuite qu’un algorithme donne toujours la bonne réponse, teste-le avec des cas limites et choisis l’algorithme adapté à une situation.

DébutantUnité 4 sur 7 de la formation Formation : Informatique : données, algorithmes, Internet et IA

Ce que tu vas apprendre

  1. Trouve une valeur recherchée dans une liste par recherche séquentielle et, si la liste est triée, par recherche dichotomique. Suis chaque méthode sur des listes concrètes et compte les éléments vérifiés.
    • Effectue une recherche séquentielle dans une liste quelconque
      Vérifie les éléments un par un depuis le début, renvoie la position de la première correspondance ou indique que la valeur recherchée est absente, et compte les comparaisons dans le meilleur et le pire cas.
    • Effectue une recherche dichotomique dans une liste triée
      Utilise l’ordre de la liste pour diviser par deux la partie encore à examiner à chaque vérification, suis les positions basse, haute et médiane, et explique pourquoi environ log₂ n vérifications suffisent.
  2. Indique ce qu’un tri correct doit produire, puis suis le tri à bulles et le tri par sélection passage par passage et compte leurs comparaisons et leurs échanges.
    • Décris les propriétés d’une liste correctement triée
      Définis l’ordre de tri, les clés de tri, les échanges, la stabilité, le tri en place et les inversions afin de suivre, vérifier et comparer les algorithmes de tri.
    • Suis l’exécution du tri à bulles et compte ses opérations
      Trie une liste en échangeant à plusieurs reprises les éléments voisins qui ne sont pas dans l’ordre, suis le tri passage par passage, arrête-toi dès qu’un passage ne fait aucun échange et compte les comparaisons et les échanges.
    • Suis l’exécution du tri par sélection et compte ses opérations
      Trie une liste en sélectionnant à chaque fois le plus petit élément restant et en l’échangeant pour le mettre à sa place, suis le tri passage par passage et compare ses nombres de comparaisons et d’échanges à ceux du tri à bulles.
  3. Fusionne deux listes triées en une seule, suis le tri fusion lorsqu’il divise une liste puis fusionne les morceaux, et explique pourquoi il nécessite environ n log₂ n comparaisons.
    • Fusionne deux listes triées en une seule
      Combine deux listes déjà triées en prenant à chaque fois le plus petit élément de tête, compte les comparaisons et explique pourquoi le résultat est trié.
    • Suis l’exécution du tri fusion et explique sa croissance en n log n
      Trie en divisant une liste en deux jusqu’à obtenir des éléments isolés, puis en fusionnant les morceaux dans l’ordre ; utilise un cas de base pour arrêter la division et compte les comparaisons niveau par niveau.
  4. Compte les étapes élémentaires d’un algorithme en fonction de la taille de l’entrée, compare les croissances logarithmique, linéaire, en n log n et quadratique, et utilise les ordres de croissance pour prévoir les temps d’exécution.
    • Compte les étapes effectuées par un algorithme
      Mesure un algorithme par le nombre d’opérations élémentaires qu’il effectue pour une entrée de taille n, détermine ce nombre pour des boucles et des boucles imbriquées, et distingue le meilleur cas, le pire cas et le cas moyen.
    • Compare la croissance du nombre d’étapes selon la taille de l’entrée
      Reconnais les croissances constante, logarithmique, linéaire, en n log n, quadratique et exponentielle, observe ce qui se passe quand l’entrée double, lis les notations O informelles et explique pourquoi l’ordre de croissance compte davantage que les facteurs constants pour les grandes entrées.
    • Prévois et mesure des temps d’exécution
      Utilise un temps d’exécution connu et un ordre de croissance pour estimer le temps nécessaire à une entrée plus grande, vérifie un ordre de croissance en chronométrant un programme pour des tailles qui doublent et présente les prévisions comme des estimations.
  5. Montre qu’un algorithme s’arrête et donne la bonne réponse pour toute entrée valide, teste-le avec des cas limites et évalue les compromis entre temps, mémoire et autres facteurs afin de choisir un algorithme adapté à une situation.
    • Justifie la correction d’un algorithme
      Énonce ce qu’un algorithme doit accomplir, explique pourquoi les tests seuls ne peuvent pas prouver sa correction et utilise des invariants de boucle et un argument de terminaison pour montrer que les algorithmes de recherche et de tri fonctionnent.
    • Teste des algorithmes avec des cas limites
      Choisis des entrées aux limites de ce que l’algorithme peut traiter, prévois la sortie attendue avant l’exécution et trouve les erreurs de décalage d’une unité et les boucles infinies que les entrées ordinaires ne révèlent pas.
    • Choisis un algorithme adapté à la situation
      Compare les algorithmes de recherche et de tri selon leur temps, leur mémoire, leur stabilité et leurs exigences sur les données, puis détermine lequel convient à une tâche donnée, notamment quand il est avantageux de trier d’abord.

Algorithmes de tri : cours

5 chapitres

1

Effectue une recherche dans une liste étape par étape

Pour trouver une valeur, commence par une question simple : quelles positions restent à vérifier ? Suis la recherche séquentielle dans une liste ordinaire, puis utilise l’ordre d’une liste triée pour en écarter de grandes parties avec la recherche dichotomique. Tu suivras les positions séparément des valeurs, tu verras comment chaque recherche indique un échec et tu compteras le travail nécessaire pour des entrées faciles et difficiles. De courts suivis montrent aussi pourquoi la dernière position restante doit encore être vérifiée.

1.1 Effectue une recherche séquentielle dans une liste quelconque

Une recherche détermine si une valeur recherchée apparaît et où elle apparaît. Une liste possède des positions numérotées appelées indices. Python compte à partir de zéro : dans [7, 3, 9, 3, 5], l’indice 0 contient 7 et l’indice 4 contient 5. La valeur et son indice répondent à des questions différentes.

Vérifier un élément à la fois

La recherche séquentielle commence au premier élément et compare chaque élément à la valeur recherchée. Elle renvoie immédiatement l’indice lorsqu’elle trouve une correspondance. Si la liste se termine sans correspondance, elle renvoie -1, notre signal pour « non trouvé ».

def linear_search(items, target):
    for i in range(len(items)):
        if items[i] == target:
            return i
    return -1

len(items) donne le nombre d’éléments. range(len(items)) fournit tous les indices valides, à partir de 0 et jusqu’à la valeur juste avant la longueur. items[i] lit la valeur à l’indice courant. Un return met fin à la fonction : une correspondance ultérieure ne remplace donc jamais la première.

La recherche de 3 dans la liste ci-dessus se déroule ainsi :

  1. À l’indice 0, compare 7 à 3. Ils diffèrent, donc continue.
  2. À l’indice 1, compare 3 à 3. Ils correspondent, donc renvoie l’indice 1.

Le résultat est l’indice 1 après deux comparaisons. Le second 3, à l’indice 3, n’est jamais vérifié. Chercher 4 vérifie au contraire 7, 3, 9, 3 et 5, puis renvoie -1 après cinq comparaisons. Un indice renvoyé égal à 1 désigne le deuxième élément, pas un élément de valeur 1.

Compter le travail

Soit n le nombre d’éléments. Pour une liste non vide, le meilleur cas demande une comparaison : le premier élément correspond. Le pire cas demande n comparaisons : la valeur recherchée est en dernier ou absente. Une liste vide ne nécessite aucune comparaison et renvoie -1.

Si une valeur recherchée apparaît une fois et a autant de chances d’occuper chaque position, son nombre moyen de comparaisons est

1+2+⋯+nn=n+12.

Pour 1 000 éléments, cela représente 500,5 comparaisons. Une moyenne peut être fractionnaire même si chaque recherche individuelle effectue un nombre entier de comparaisons. Cette moyenne décrit cette distribution particulière de recherches fructueuses ; des recherches infructueuses fréquentes augmenteraient la moyenne globale.

Placer l’échec après la boucle

Un else: return -1 dans la boucle abandonnerait dès la première absence de correspondance. Sur [7, 3, 9], il rejetterait une recherche de 3 après avoir vu seulement 7. Le retour indiquant l’échec doit se trouver après la boucle, quand toutes les positions ont été écartées.

La recherche séquentielle ne nécessite ni ordre trié ni préparation. Elle fonctionne avec des nombres, des mots ou des enregistrements comparés selon un identifiant. Une version conçue pour des données triées peut s’arrêter lorsqu’elle dépasse la position possible de la valeur recherchée : dans [2, 5, 8, 12], voir 8 suffit à exclure 6. Le code ci-dessus poursuit volontairement le parcours jusqu’à trouver une correspondance ou atteindre la fin.

Des tâches apparentées utilisent le même parcours mais une règle d’arrêt différente. Compter toutes les occurrences, recueillir tous les indices correspondants et trouver un plus grand élément exigent d’examiner toute la liste ; trouver la première correspondance permet un retour anticipé.

Points clés

  • La recherche séquentielle vérifie les positions dans l’ordre et renvoie le premier indice correspondant.
  • Ne renvoie -1 qu’après avoir écarté toutes les correspondances possibles.
  • Une liste non vide nécessite une comparaison dans le meilleur cas et n dans le pire.
  • La moyenne (n+1)/2 suppose une seule occurrence de la valeur recherchée, ayant autant de chances de se trouver à chaque position.

1.2 Effectue une recherche dichotomique dans une liste triée

La recherche dichotomique utilise l’ordre des données triées pour écarter des positions sans les vérifier individuellement. Son entrée doit être triée par ordre croissant. Elle nécessite aussi un accès rapide à un élément d’indice choisi, comme le permet un tableau ou une liste Python.

Conserver un intervalle bornes comprises

low et high indiquent la première et la dernière position encore possibles, bornes comprises. Commence avec low = 0 et high = len(items) - 1. Choisis l’indice médian en arrondissant à l’entier inférieur. Si la valeur médiane est trop petite, toutes les valeurs à sa gauche sont aussi trop petites ; déplace low après le milieu. Si elle est trop grande, déplace high juste avant le milieu.

def binary_search(items, target):
    low = 0
    high = len(items) - 1
    while low <= high:
        mid = (low + high) // 2
        if items[mid] == target:
            return mid
        elif items[mid] < target:
            low = mid + 1
        else:
            high = mid - 1
    return -1

// divise et arrondit à l’entier inférieur. La boucle inclut le cas low == high car il reste une position non vérifiée. Lorsque low > high, l’intervalle est vide.

Suivre une recherche fructueuse et une recherche infructueuse

Utilise [3, 8, 12, 17, 23, 31, 42, 56, 64, 77, 85], dont les indices vont de 0 à 10. Pour trouver 64, le premier indice médian est 5, qui contient 31. Comme 31 est trop petit, fixe low = 6. L’indice médian suivant est 8, qui contient 64. Renvoie 8 après deux vérifications d’éléments médians.

Pour chercher 20 dans la même liste :

VérificationlowhighmidValeur médianeMise à jour
1010531high devient 4
204212low devient 3
334317low devient 4
444423high devient 3

L’intervalle est maintenant vide : renvoie donc -1. Cet échec est justifié : l’ordre de la liste a permis d’écarter chaque partie.

Pourquoi la méthode est rapide

Chaque vérification infructueuse laisse au plus la moitié de l’intervalle. Pour une liste non vide, le nombre maximal de vérifications d’éléments médians est ⌊log⁡2n⌋+1. Le logarithme en base 2 décrit les divisions successives par deux : 210=1 024, donc un millier d’éléments nécessite au plus 10 vérifications ; un million en nécessite au plus 20. Une vérification dans ce code Python peut effectuer deux comparaisons, == et <. Les vérifications et les comparaisons sont deux unités de comptage différentes.

Conditions et bogues aux limites

L’ordre trié est indispensable. Chercher 2 dans [9, 2, 7, 4, 1] rencontre d’abord 7 et écarte la partie droite, puis rencontre 9 et écarte la correspondance restante à l’indice 1. Un accès rapide au milieu compte aussi : suivre les liens pour atteindre le milieu d’une liste chaînée fait perdre l’avantage de vitesse de la version sur tableau.

Exclus toujours le milieu testé après une absence de correspondance. Utiliser low = mid peut laisser [10, 20] inchangée indéfiniment lors de la recherche de 20. Utiliser while low < high saute le dernier élément candidat et échoue en cherchant 5 dans [5]. Sur une liste vide, high = -1 : la boucle correcte ne démarre donc jamais.

En présence de doublons, cette version renvoie un indice correspondant quelconque. Chercher 4 dans [2, 4, 4, 4, 9] renvoie immédiatement l’indice 2 ; trouver la première occurrence nécessite une recherche modifiée qui continue à gauche après une correspondance.

Points clés

  • La recherche dichotomique nécessite des données triées et un accès rapide aux positions.
  • Suis un intervalle bornes comprises et continue tant que low <= high.
  • Après une absence de correspondance, exclus mid avec mid + 1 ou mid - 1.
  • Le maximum est de ⌊log⁡2n⌋+1 vérifications d’éléments médians pour n>0.
  • Un indice correspondant n’est pas nécessairement celui de la première occurrence.
  • Un intervalle vide signifie que la valeur recherchée est absente.
2

Trie une liste par tri à bulles et par tri par sélection

Une liste peut sembler ordonnée tout en contenant les mauvais éléments. Commence par préciser la tâche de tri, y compris pour les clés répétées et les enregistrements associés. Suis ensuite deux méthodes qui créent l’ordre par des échanges : le tri à bulles place le plus grand élément restant à droite, tandis que le tri par sélection place le plus petit élément restant à gauche. Le suivi de leur exécution révèle des coûts différents en comparaisons et en déplacements.

2.1 Décris les propriétés d’une liste correctement triée

Trier consiste à réorganiser des éléments selon une clé choisie. Pour des nombres en ordre croissant, chaque élément est inférieur ou égal au suivant. L’expression « non décroissant » autorise des voisins égaux : [2, 5, 5, 9] est triée. L’ordre décroissant inverse le sens.

Vérifier deux conditions

Un tri correct doit produire une sortie ordonnée contenant exactement les éléments d’origine, en conservant chaque répétition. Trier [3, 1, 2] en [1, 2, 3] réussit. Les deux résultats [1, 2] et [1, 1, 3] échouent, même si leurs éléments voisins sont dans l’ordre. Le premier perd un élément ; le second modifie les éléments présents. Un réarrangement qui conserve toutes les occurrences est appelé une permutation.

Pour un enregistrement, la clé est uniquement le champ utilisé pour la comparaison. Des villes pourraient être triées par nom ou par population. L’enregistrement entier d’une ville se déplace lorsque sa clé de population se déplace ; détacher le nom corromprait les données.

L’ordre du texte dépend de la clé

Une comparaison simple de texte suit les codes de caractères, un caractère à la fois. En ASCII et en Unicode, les lettres de A à Z utilisent les codes de 65 à 90 et celles de a à z les codes de 97 à 122. Une comparaison simple place donc « Zèbre » avant « abeille ». Comparer des copies en minuscules peut fournir un ordre insensible à la casse pour ces exemples.

Les chiffres sous forme de texte se comportent aussi comme des caractères. « 10 » est trié avant « 9 » car son premier caractère est « 1 ». Une clé numérique convertit ces chaînes en nombres qu’elles représentent, ce qui place 9 avant 10. Détermine ce que signifient les données avant de choisir la comparaison.

Déplacer des valeurs sans les perdre

Un échange permute deux positions. Une variable temporaire protège la valeur qui serait sinon écrasée :

temp = items[i]
items[i] = items[j]
items[j] = temp

Python permet aussi items[i], items[j] = items[j], items[i]. Écrire les deux affectations sans sauvegarder la première valeur transforme [4, 7] en [7, 7]. Les tris à bulles et par sélection déplacent les éléments par échange ; le tri fusion les copie dans une sortie fusionnée.

Stabilité et mémoire

Un tri stable conserve l’ordre initial des enregistrements dont les clés sont égales. Partons de Ana 85, Ben 92, Cara 85, par ordre alphabétique. Un tri stable par note décroissante produit Ben 92, Ana 85, Cara 85. Ana reste avant Cara. Un tri ultérieur par note peut ainsi conserver un ordre alphabétique antérieur au sein de chaque groupe de même note. Le tri intégré de Python est stable.

Un tri en place réorganise la liste existante avec seulement quelques variables supplémentaires, quelle que soit sa longueur. Les méthodes à bulles et par sélection enseignées ici sont en place. Le tri fusion habituel nécessite un espace de stockage supplémentaire proportionnel au nombre d’éléments. La stabilité et la mémoire décrivent des propriétés différentes : un tri peut être en place tout en étant instable.

Mesurer le désordre avec les inversions

Une inversion est une paire de positions où la clé d’un élément situé avant est supérieure à celle d’un élément situé après. Dans [5, 1, 4, 2, 8], les inversions sont (5, 1), (5, 4), (5, 2) et (4, 2) : quatre au total. Les éléments d’une paire ne sont pas nécessairement voisins.

Une liste triée a zéro inversion. Une liste de n éléments distincts en ordre inverse en a n(n−1)/2, le maximum. Des clés égales ne forment jamais une inversion : [3, 3, 1] en a deux, une pour chaque 3 placé avant 1. Compter les inversions est utile pour expliquer le nombre d’échanges du tri à bulles.

Points clés

  • Un tri correct conserve chaque élément d’origine et met les clés dans l’ordre.
  • Une clé de tri détermine le champ ou la valeur qui commande l’ordre.
  • La stabilité conserve l’ordre des enregistrements de même clé.
  • Un tri en place ne nécessite qu’une quantité fixe d’espace de travail supplémentaire.
  • Une inversion est une paire dont les éléments ne sont pas dans l’ordre, y compris lorsqu’ils ne sont pas voisins.

2.2 Suis l’exécution du tri à bulles et compte ses opérations

Le tri à bulles compare les éléments voisins de gauche à droite. Lorsque celui de gauche est plus grand, il échange la paire. Chaque parcours est un passage. Un grand élément peut se déplacer plusieurs fois vers la droite pendant un passage, jusqu’à ce que le plus grand élément restant atteigne sa position finale.

Suivre le premier passage

Partons de [5, 1, 4, 2, 8] :

  1. Compare 5 et 1 ; échange-les pour obtenir [1, 5, 4, 2, 8].
  2. Compare 5 et 4 ; échange-les pour obtenir [1, 4, 5, 2, 8].
  3. Compare 5 et 2 ; échange-les pour obtenir [1, 4, 2, 5, 8].
  4. Compare 5 et 8 ; laisse-les en place.

Le passage effectue quatre comparaisons et trois échanges. Le plus grand élément, 8, est placé. Le reste n’est pas encore trié : 4 précède 2. Un passage garantit la position finale du maximum, mais pas l’ordre de tous les éléments.

Le passage 2 ne nécessite que les quatre premières positions. Compare 1 à 4, puis échange 4 et 2, puis compare 4 à 5. Cela donne [1, 2, 4, 5, 8] après trois comparaisons supplémentaires et un échange. Le passage 3 compare 1 à 2 et 2 à 4. Il ne fait aucun échange, ce qui confirme que la liste est triée. Totaux : neuf comparaisons et quatre échanges.

Raccourcir chaque passage et s’arrêter tôt
def bubble_sort(items):
    n = len(items)
    for p in range(n - 1):
        swapped = False
        for j in range(n - 1 - p):
            if items[j] > items[j + 1]:
                items[j], items[j + 1] = items[j + 1], items[j]
                swapped = True
        if not swapped:
            break

Le compteur de passages p commence à zéro. La plus grande valeur de j est n - 2 - p, donc j + 1 reste dans la partie non triée. Réinitialise swapped au début de chaque passage ; un échange lors d’un passage précédent ne dit rien sur le déplacement éventuel d’un élément au passage actuel.

Après chaque passage, une position supplémentaire à droite est définitive. Un passage sans échange prouve que tous les voisins comparés sont dans l’ordre. Le suffixe déjà placé est également dans l’ordre : l’algorithme peut donc s’arrêter. Le passage de confirmation compte tout de même comme travail.

Comparer le meilleur et le pire cas

Pour une liste non vide triée, la version avec arrêt anticipé effectue n−1 comparaisons et zéro échange. Sur une liste d’éléments distincts en ordre inverse, elle effectue

(n−1)+(n−2)+⋯+1=n(n−1)2

comparaisons et le même nombre d’échanges. Cinq éléments en nécessitent 10 ; 1 000 éléments en nécessitent 499 500. Sans arrêt anticipé, l’exemple de cinq éléments effectuerait aussi son dernier passage d’une comparaison, pour atteindre 10 comparaisons.

Chaque échange supprime exactement une inversion. Les quatre inversions de la liste initiale de l’exemple expliquent ses quatre échanges. Les voisins égaux restent en place car le test utilise >, ce qui rend cette version stable et en place. Remplacer > par >= peut inverser des enregistrements de même clé.

La position compte même lorsqu’il y a peu d’inversions. [5, 1, 2, 3, 4] utilise quatre échanges et un deuxième passage pour confirmer l’ordre, soit sept comparaisons. [2, 3, 4, 5, 1] nécessite aussi quatre échanges, mais son 1 ne peut avancer vers la gauche qu’une fois par passage. Elle nécessite les quatre passages et 10 comparaisons.

Points clés

  • Chaque passage place le plus grand élément restant à droite.
  • Un passage sans échange permet un arrêt anticipé.
  • Compte le passage qui confirme l’ordre, même s’il ne fait aucun échange.
  • Le pire cas demande n(n−1)/2 comparaisons ; une entrée triée en nécessite n−1.
  • Échanger uniquement les voisins strictement dans le mauvais ordre préserve la stabilité.
  • Le nombre d’échanges est égal au nombre d’inversions de l’entrée.

2.3 Suis l’exécution du tri par sélection et compte ses opérations

Le tri par sélection construit un préfixe trié à gauche. Chaque passage trouve le plus petit élément dans le suffixe restant, puis l’échange pour le placer à la position suivante du préfixe. Le parcours trouve la position ; l’échange a lieu après le parcours.

Retenir un indice

À la position i, commence avec smallest = i. Compare chaque élément suivant à items[smallest]. Mets à jour smallest seulement lorsqu’un élément plus petit apparaît. À la fin du parcours, échange items[i] et items[smallest].

def selection_sort(items):
    n = len(items)
    for i in range(n - 1):
        smallest = i
        for j in range(i + 1, n):
            if items[j] < items[smallest]:
                smallest = j
        if smallest != i:
            items[i], items[smallest] = items[smallest], items[i]

Ne retenir que la plus petite valeur ne donnerait pas sa position pour l’échange. Commencer le parcours à l’indice 0 ferait examiner à nouveau les éléments déjà placés ; la recherche dans la partie restante commence juste après i.

Suivre les passages

Partons de [29, 10, 14, 37, 13].

PassageMinimum restantListe après placementComparaisonsÉchanges qui déplacent des éléments
110[10, 29, 14, 37, 13]41
213[10, 13, 14, 37, 29]31
314[10, 13, 14, 37, 29]20
429[10, 13, 14, 29, 37]11

Le troisième minimum est déjà à sa place : aucune valeur ne bouge. Après quatre passages, le dernier élément est nécessairement le plus grand ; il ne nécessite pas de passage distinct. On compte 10 comparaisons et trois échanges qui déplacent des éléments. La condition dans le code évite les échanges d’une position avec elle-même ; l’omettre ne change pas le résultat.

Comparaisons et échanges ont des coûts différents

Le tri par sélection effectue toujours n(n−1)/2 comparaisons d’éléments : chaque passage doit examiner tout le suffixe restant pour en déterminer le minimum. Le total est de 10 pour cinq éléments ou de 499 500 pour 1 000, même si l’entrée est déjà triée. Un parcours qui ne modifie pas l’indice retenu détermine le minimum de ce passage, mais ne garantit pas en général que le suffixe restant soit ordonné.

Pour une liste non vide, il y a au plus un échange qui déplace des éléments par passage, donc au plus n−1 au total. Une entrée vide ne nécessite ni passage ni échange. Le tri à bulles peut nécessiter n(n−1)/2 échanges sur une liste d’éléments distincts en ordre inverse. Si déplacer de grands enregistrements coûte beaucoup plus cher que comparer leurs clés, le faible nombre d’échanges du tri par sélection peut compter malgré ses nombreuses comparaisons. Échanger chaque fois qu’un nouveau minimum apparaît pendant le parcours fait perdre cet avantage.

Des clés égales peuvent changer d’ordre

Cette méthode fondée sur les échanges est en place mais instable. Notons 4a et 4b des enregistrements de même clé afin de les distinguer. En partant de [4a, 4b, 1], le premier passage échange 4a et 1, ce qui produit [1, 4b, 4a]. Les éléments de même clé ont inversé leur ordre initial, même si l’algorithme ne les a jamais comparés directement comme étant différents. Conserver le premier minimum trouvé pendant un parcours n’empêche pas un échange à distance de faire passer un élément devant un enregistrement de même clé.

Points clés

  • Le tri par sélection parcourt la liste à la recherche d’un minimum, puis effectue un échange après le parcours.
  • Après chaque passage, le préfixe trié gagne un élément.
  • Son nombre de comparaisons est toujours n(n−1)/2.
  • Pour une entrée non vide, il effectue au plus n−1 échanges qui déplacent des éléments et utilise un espace supplémentaire fixe.
  • La version habituelle avec échange à distance est instable.
3

Trie plus rapidement avec le tri fusion

Trier une grande liste en répétant des parcours complets devient coûteux. Le tri fusion suit un autre plan : diviser la liste en morceaux plus petits, trier ces morceaux et combiner leurs résultats. Apprends d’abord pourquoi deux listes triées peuvent être fusionnées en ne regardant que leurs éléments de tête. Suis ensuite les divisions et les fusions récursives, en tenant compte du travail à chaque niveau et de la mémoire supplémentaire nécessaire pour conserver la sortie.

3.1 Fusionne deux listes triées en une seule

La fusion combine deux listes déjà triées en une seule sortie triée. Place un curseur sur le premier élément inutilisé de chaque entrée. Compare ces deux éléments de tête, copie le plus petit et avance uniquement son curseur.

Choisir le plus petit élément suivant

Fusionne [3, 27, 38, 43] avec [9, 10, 82] :

Comparaison des éléments de têteCopie dans la sortieSortie obtenue
3 et 93[3]
27 et 99[3, 9]
27 et 1010[3, 9, 10]
27 et 8227[3, 9, 10, 27]
38 et 8238[3, 9, 10, 27, 38]
43 et 8243[3, 9, 10, 27, 38, 43]

La liste de gauche est maintenant épuisée. Copie le 82 restant sans autre comparaison d’éléments. Le résultat est [3, 9, 10, 27, 38, 43, 82], avec six comparaisons. Copier la queue fait partie de l’algorithme : s’arrêter lorsque les comparaisons s’arrêtent ferait perdre des données.

Pourquoi la méthode peut-elle ignorer les éléments derrière ceux de tête ? Chaque élément de tête est le plus petit élément restant de sa propre liste. Le plus petit des éléments de tête est donc le plus petit élément restant au total. Ce raisonnement reste valable après chaque déplacement d’un curseur car les parties inutilisées restent triées.

Lire le code de fusion
def merge(left, right):
    result = []
    i = j = 0
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
    result.extend(left[i:])
    result.extend(right[j:])
    return result

append ajoute un élément. Une tranche comme left[i:] contient la queue inutilisée, et extend en copie les éléments. Une seule queue inutilisée peut être non vide à la fin de la boucle. Si une entrée est vide au départ, la boucle effectue zéro comparaison et l’autre liste est copiée intacte.

Compter les comparaisons et l’espace de stockage

Pour deux listes non vides de longueurs m et k, il faut au plus m+k−1 comparaisons d’éléments de tête. Chaque comparaison place un élément et au moins le dernier élément peut être copié sans comparaison. Le plus petit nombre possible de comparaisons pour une fusion est la longueur de la liste la plus courte : fusionner [1, 2, 3] avec [4, 5, 6] utilise trois comparaisons avant que la partie gauche soit épuisée.

Le travail total de copie augmente avec m+k même lorsque les comparaisons se terminent tôt, car chaque élément doit apparaître dans la sortie. La nouvelle liste nécessite aussi de la place pour m+k éléments. Le nombre de comparaisons, le travail de copie et l’espace supplémentaire mesurent différentes parties d’une même opération.

Traiter les égalités et l’ordre des entrées

Le test <= prend l’élément de gauche lorsque les clés sont égales. Si les deux entrées proviennent de parties consécutives d’une liste d’origine, cela maintient l’enregistrement antérieur avant l’enregistrement ultérieur de même clé. C’est la règle en cas d’égalité nécessaire à un tri fusion stable.

L’exigence d’entrées triées est impérative. Fusionner [5, 1] avec [3] copie 3, puis la queue [5, 1], ce qui produit [3, 5, 1]. La règle des éléments de tête a échoué car 5 n’était pas la plus petite valeur restante dans sa propre entrée.

Points clés

  • La fusion compare les premiers éléments inutilisés de deux entrées triées.
  • Copie la queue inutilisée lorsqu’un côté est épuisé.
  • Deux entrées non vides nécessitent au plus m+k−1 comparaisons d’éléments de tête.
  • Prendre l’élément de gauche lorsque les clés sont égales préserve l’ordre entre les deux moitiés.

3.2 Suis l’exécution du tri fusion et explique sa croissance en n log n

Le tri fusion résout une grande tâche de tri en la divisant en tâches de tri plus petites. C’est le principe diviser pour régner : diviser la liste, trier chaque moitié et fusionner les moitiés triées.

Arrêter la division au cas de base

Une fonction est récursive lorsqu’elle s’appelle elle-même. Le tri fusion s’appelle sur des listes plus courtes. Son cas de base renvoie une liste de zéro ou un élément sans modification, puisqu’une telle liste est déjà triée.

def merge_sort(items):
    if len(items) <= 1:
        return items
    mid = len(items) // 2
    left = merge_sort(items[:mid])
    right = merge_sort(items[mid:])
    return merge(left, right)

Les tranches divisent l’entrée sans perdre d’éléments. Pour une longueur impaire, la partie droite contient un élément de plus : [6, 2, 9, 4, 1, 7, 3] se divise en [6, 2, 9] et [4, 1, 7, 3]. Les deux moitiés sont plus courtes : les appels récursifs atteignent donc finalement le cas de base. Un cas de base seul ne garantirait pas la terminaison si un appel continuait à se transmettre la liste d’origine.

Reconstruire la liste triée

Suis [38, 27, 43, 3, 9, 82, 10, 15]. La liste se divise en deux moitiés de quatre éléments, puis en quatre morceaux de deux éléments, puis en éléments isolés. La division ne réorganise pas les valeurs. L’ordre se construit pendant les fusions :

  1. Fusionne les éléments isolés en [27, 38], [3, 43], [9, 82] et [10, 15]. Chaque fusion utilise une comparaison : quatre au total.
  2. Fusionne les paires en [3, 27, 38, 43] et [9, 10, 15, 82]. Chaque fusion utilise trois comparaisons : six au total.
  3. Fusionne ces moitiés en [3, 9, 10, 15, 27, 38, 43, 82]. Cette fusion utilise sept comparaisons.

Le tri complet utilise 4+6+7=17 comparaisons d’éléments. Ne compte pas seulement la fusion finale : il a d’abord fallu produire les moitiés triées. Avec cette règle de division, l’exemple de sept éléments ci-dessus est trié en [1, 2, 3, 4, 6, 7, 9] en utilisant 14 comparaisons.

Compter les niveaux et le travail par niveau

Pour huit éléments, les divisions par deux aboutissent à des éléments isolés après trois niveaux car 23=8. En général, il y a environ log⁡2n niveaux de fusion. Sur un niveau complet, les fusions traitent collectivement les n éléments. Chaque niveau effectue donc un travail proportionnel à n, ce qui conduit à une croissance en nlog⁡2n.

Pour huit éléments, nlog⁡2n=24 est une borne supérieure approximative utile pour les comparaisons, pas le nombre exact. La liste de l’exemple en a utilisé 17 ; une liste de huit éléments déjà triée ou en ordre inverse en utilise 12. L’ordre de l’entrée change le moment où une fusion épuise un côté, mais chaque liste passe tout de même par les niveaux de division et de fusion. Pour cette version, la croissance des comparaisons reste en nlog⁡n dans le meilleur comme dans le pire cas.

Pour un million d’éléments, environ 20 niveaux donnent environ 20 millions de comparaisons comme estimation supérieure de l’ordre de grandeur. Le tri par sélection en utilise environ 500 milliards. La différence augmente rapidement avec la taille de l’entrée.

Prévoir l’espace supplémentaire pour la sortie

Le tri fusion ordinaire sur des listes nécessite un espace de stockage supplémentaire proportionnel à n. Choisir l’élément de tête gauche en cas d’égalité le rend stable.

Points clés

  • Le tri fusion trie récursivement deux moitiés plus courtes, puis les fusionne.
  • Les listes de zéro ou un élément constituent le cas de base.
  • Les longueurs impaires se divisent en moitiés qui diffèrent d’un élément.
  • Environ log⁡2n niveaux effectuent chacun un travail proportionnel à n.
  • Le nombre exact de comparaisons dépend de l’ordre ; la famille de croissance est nlog⁡n.
  • La version habituelle est stable si elle prend l’élément de gauche en cas d’égalité et nécessite un espace supplémentaire proportionnel à la taille de l’entrée.
4

Compte les étapes et compare la croissance des temps d’exécution

Un chronomètre indique comment un programme s’est exécuté une fois ; compter les étapes aide à expliquer ce qui se passe lorsque l’entrée grandit. Choisis une opération à compter, transforme le travail répété en formule et compare les profils de croissance, depuis un accès unique jusqu’à l’essai de toutes les sélections. Utilise ces profils pour estimer les temps d’exécution et les budgets de temps, puis conçois des mesures permettant de vérifier si les prévisions correspondent aux exécutions réelles.

4.1 Compte les étapes effectuées par un algorithme

Un temps d’exécution mesuré dépend de la machine et du programme. Un nombre d’étapes décrit le travail de l’algorithme à l’aide d’une opération répétée choisie. La taille de l’entrée, notée n, est le nombre d’éléments traités.

Choisir l’opération avant de compter

Pour la recherche et le tri, les comparaisons entre valeurs d’éléments constituent généralement une opération élémentaire utile. Compte les échanges séparément lorsque le déplacement des données compte. Pour la recherche dichotomique, il est pratique de compter les vérifications d’un élément médian. Dans la version Python, une vérification médiane infructueuse teste à la fois l’égalité et l’inégalité stricte : elle peut donc comporter deux comparaisons d’éléments.

MéthodeUnité de comptageNombre dans le pire cas
Recherche séquentielleComparaisons entre élément et valeur recherchéen
Recherche dichotomique, entrée non videVérifications d’éléments médians⌊log⁡2n⌋+1
Tri à bullesComparaisons de voisinsn(n−1)/2
Tri par sélectionComparaisons de clésn(n−1)/2
Tri fusionComparaisons d’éléments de têteAu plus environ nlog⁡2n

Ces nombres décrivent des opérations répétées, pas des lignes de code. Une ligne dans une boucle peut s’exécuter un million de fois ; plusieurs lignes de préparation peuvent chacune ne s’exécuter qu’une fois.

Distinguer les cas pour une même taille

Le meilleur cas prend le moins d’étapes parmi les entrées valides de taille n. Le pire cas en prend le plus et fournit une garantie. Le cas moyen correspond à une moyenne calculée selon une distribution d’entrées précisée.

Pour une liste non vide, la recherche séquentielle nécessite une comparaison si la valeur recherchée est en tête et n si elle est en dernière position ou absente. Sa moyenne pour une recherche fructueuse est (n+1)/2 lorsque la première position correspondante a autant de chances d’être n’importe quelle position. Le mot « moyenne » suppose cette distribution ; il ne désigne pas le milieu entre les nombres du meilleur et du pire cas pour tout algorithme.

Traduire les boucles en nombres d’étapes

Une comparaison par élément lors d’un parcours complet donne n comparaisons. Deux boucles complètes imbriquées, chacune exécutée n fois, exécutent leur corps commun n2 fois. Une autre structure de boucles imbriquées ne compare chaque paire qu’une fois :

for i in range(n):
    for j in range(i + 1, n):
        compare(items[i], items[j])

La première itération externe compare son élément aux n−1 éléments suivants. La suivante le compare à n−2 éléments, et la dernière à aucun. Le total est

1+2+⋯+(n−1)=n(n−1)2.

Écris la somme dans les deux sens. Chaque paire de termes alignés donne n, et il y a n−1 paires de ce type. Leur total est n(n−1), soit deux fois la somme initiale. Pour cinq éléments, 4+3+2+1=10 ; pour 1 000, le nombre de paires est de 499 500.

Reconnaître les divisions successives par deux

Une boucle qui divise le travail restant par deux nécessite environ log⁡2n répétitions. Un million atteint pour la première fois 1 ou moins après 20 divisions par deux : 219=524 288 est inférieur à un million et 220=1 048 576 lui est supérieur. C’est très différent de retirer un seul élément à chaque fois.

Pour comparer les croissances, garde le terme qui augmente le plus vite. Le nombre de paires est n2/2−n/2. Pour n=1 000, ses termes valent 500 000 et 500 : le terme quadratique détermine donc la croissance. Omettre le terme plus petit et le facteur constant décrit la famille de croissance ; cela ne transforme pas le nombre exact de 499 500 en un nombre exact d’un million.

Points clés

  • Nomme l’opération comptée et exprime son nombre à l’aide de la taille de l’entrée.
  • Les nombres dans le pire cas sont des garanties ; les moyennes dépendent d’une distribution des entrées.
  • Deux parcours complets imbriqués donnent n2 exécutions du corps.
  • Comparer chaque paire distincte une fois donne n(n−1)/2 comparaisons.
  • Des divisions successives par deux produisent une croissance logarithmique.

4.2 Compare la croissance du nombre d’étapes selon la taille de l’entrée

Un ordre de croissance décrit comment la quantité de travail change lorsque l’entrée grandit. Il aide à comparer les algorithmes au-delà de la taille particulière utilisée dans un suivi d’exécution.

Lire les familles courantes
Famille de croissanceExempleEffet du doublement de la taille de l’entrée
Constante, 1Lire une position connue d’un tableauMême travail
Logarithmique, log⁡2nRecherche dichotomiqueEnviron une vérification supplémentaire
Linéaire, nParcours completDeux fois plus de travail
nlog⁡nTri fusionUn peu plus du double
Quadratique, n2Tri par sélectionEnviron quatre fois plus
Exponentielle, 2nEssayer chaque sélection d’élémentsÉlève le nombre au carré

Pour une croissance exponentielle, ajouter un seul élément double déjà le nombre : 2n+1=2×2n. Doubler l’entrée est un changement bien plus grand qu’en ajouter un.

Comparer les tailles par des nombres

Pour des entrées de 10, 100, 1 000 et un million d’éléments, log⁡2n vaut environ 3,3 ; 6,6 ; 10 et 20. Les valeurs correspondantes de nlog⁡2n sont environ 33, 664, 9 966 et 20 millions. Les valeurs quadratiques sont 100, 10 000, un million et mille milliards.

Une croissance logarithmique ne correspond pas à « la moitié de la liste ». Pour un million d’éléments, les divisions successives par deux ne demandent qu’environ 20 étapes. Lorsque l’entrée passe de 1 000 à 2 000, nlog⁡2n passe d’environ 9 966 à 21 932, soit un facteur d’environ 2,2. Le logarithme change lui aussi : le nombre augmente donc un peu plus vite que de façon linéaire.

Le travail exponentiel devient rapidement considérable. 210=1 024 et 220 vaut environ un million. À raison d’un milliard d’étapes par seconde, 250 étapes prennent tout de même environ 13 jours. Ajouter un élément de plus double ce temps.

Utiliser les notations O informelles

Les programmeurs désignent couramment ces familles par O(1), O(log⁡n), O(n), O(nlog⁡n), O(n2) et O(2n). Ici, ces notations indiquent la famille de croissance habituelle dans le pire cas. Lis O(n2) comme « de l’ordre de n au carré ». La notation omet les facteurs constants et les termes de moindre ordre : n(n−1)/2 comparaisons appartient à la famille quadratique.

Une notation O n’est ni un temps d’exécution exact ni un nombre de secondes. Elle ne prétend pas non plus que chaque entrée nécessite le nombre d’étapes du pire cas. Le tri à bulles avec arrêt anticipé a un meilleur cas linéaire mais un pire cas quadratique.

Trouver le point de croisement

Supposons que la méthode A prenne 100n étapes et la méthode B, n2. Pour 50 éléments, A prend 5 000 étapes et B en prend 2 500. Pour 100, les deux en prennent 10 000. Pour 1 000, A en prend 100 000 et B un million. La croissance plus lente de A finit par compenser son facteur constant plus élevé.

La vitesse du matériel change l’échelle sans changer la famille. Un ordinateur 100 fois plus rapide permet à une méthode quadratique de traiter seulement 10 fois plus d’éléments dans le même temps, puisque (10n)2=100n2. Une méthode linéaire pourrait en traiter 100 fois plus. Pour une petite tâche, la préparation et les constantes peuvent dominer ; pour de grandes entrées, la croissance devient décisive.

Points clés

  • Doubler l’entrée double approximativement le travail linéaire et quadruple le travail quadratique.
  • Le travail logarithmique augmente d’environ une étape lorsque l’entrée double.
  • Le tri fusion combine un travail linéaire par niveau et un nombre logarithmique de niveaux.
  • Ajouter un élément double un nombre de 2n étapes.
  • Les notations de croissance omettent les constantes ; les nombres réels déterminent les points de croisement pour les petites entrées.

4.3 Prévois et mesure des temps d’exécution

Un temps d’exécution connu et un profil de croissance permettent de prévoir comment se comportera une tâche plus grande. La prévision est une estimation, car le temps réel dépend aussi de l’implémentation, de la mémoire, du matériel et des autres tâches de la machine.

Modifier la taille de l’entrée, puis le temps

Pour un travail linéaire, multiplie le temps par le rapport des tailles d’entrée. Si une recherche dans le pire cas sur un million d’éléments prend 3 millisecondes, dix millions d’éléments prennent environ 30 millisecondes dans des conditions comparables.

Pour un travail quadratique, élève le rapport au carré. Supposons que le tri par sélection prenne 2 secondes pour 50 000 éléments. Doubler à 100 000 éléments donne

2×(100 00050 000)2=2×4=8

secondes. Passer à 500 000 éléments multiplie la taille de l’entrée par 10 : le temps estimé est donc de 2×102=200 secondes. Multiplier le temps par 10 reviendrait à traiter l’algorithme à tort comme linéaire.

Pour une croissance en nlog⁡2n, utilise le rapport des deux expressions complètes. Doubler une grande entrée coûte un peu plus de deux fois plus, car le logarithme augmente avec le nombre d’éléments.

Remonter à partir d’un budget de temps

Utilise le même temps de référence quadratique : 2 secondes pour 50 000 éléments. Un budget de 32 secondes permet de multiplier le temps par 16. L’entrée peut croître d’un facteur égal à la racine carrée de 16, soit 4, ce qui donne environ 200 000 éléments. Vérifie le sens par substitution : quadrupler l’entrée prévoit un temps 16 fois plus grand, qui passe de 2 à 32 secondes.

Comparer les algorithmes pour une grande taille

Pour un million d’éléments, le tri par sélection effectue 499 999 500 000 comparaisons, soit environ 500 milliards. Le tri fusion en nécessite au plus environ 20 millions. À raison d’un milliard hypothétique de comparaisons par seconde, ces nombres correspondent à environ 500 secondes contre 0,02 seconde, soit une différence d’un facteur proche de 25 000. Ce calcul suppose un coût égal par comparaison pour isoler l’effet de l’algorithme ; les programmes mesurés paient aussi le coût des déplacements et des accès mémoire.

Tester une prévision de croissance

Chronomètre le même programme pour plusieurs tailles qui doublent, comme 10 000, 20 000 et 40 000 éléments. Divise chaque temps par le précédent. Des rapports proches de 2 suggèrent une croissance linéaire ; un peu au-dessus de 2 suggère nlog⁡n ; près de 4 suggère une croissance quadratique.

Garde la même machine et la même méthode de mesure. Répète les exécutions et utilise des tailles assez grandes pour que le temps de démarrage ne domine pas. Compare des cas semblables : chercher en première position pour une taille et chercher sans succès pour une autre mélangerait les effets des entrées et de la croissance. Pour le tri à bulles, les listes triées et les listes en ordre inverse nécessitent des indications de cas différentes.

Si des tailles qui doublent donnent 0,04 ; 0,16 et 0,64 seconde, les deux rapports valent 4, ce qui étaye un modèle quadratique sur cet intervalle. Un rapport perturbé est un indice moins solide qu’un profil répété. Les nombres d’étapes d’un suivi précis peuvent être exacts ; une prévision en secondes doit être présentée comme approximative et vérifiée par des mesures.

Points clés

  • Un temps linéaire évolue selon le rapport des tailles d’entrée ; un temps quadratique évolue selon son carré.
  • Pour un budget de temps quadratique, utilise une racine carrée pour retrouver le rapport des tailles d’entrée.
  • Mesure plusieurs tailles avec des cas d’entrée comparables et des exécutions répétées.
  • Les rapports de temps suggèrent des profils de croissance ; les prévisions en secondes restent des estimations.
5

Justifie la correction d’un algorithme et choisis un algorithme adapté

Un suivi rapide sur une liste laisse deux questions ouvertes : l’algorithme fonctionnera-t-il toujours et convient-il à cette tâche ? Énonce ce que signifient une entrée valide et une sortie correcte, utilise un invariant de boucle pour expliquer pourquoi la méthode préserve sa progression et montre pourquoi elle s’arrête. Choisis ensuite des tests qui révèlent les bogues aux limites et compare les algorithmes selon les besoins réels de la tâche en temps, mémoire, stabilité et accès aux données.

5.1 Justifie la correction d’un algorithme

Un algorithme correct s’arrête pour toute entrée valide et produit la sortie requise. Une spécification énonce la condition sur l’entrée et le résultat promis. Pour la recherche dichotomique, la précondition est que l’entrée soit triée par ordre croissant. La postcondition est un indice correspondant, ou -1 exactement lorsque la valeur recherchée est absente.

Utiliser un invariant pour relier les étapes

Un invariant de boucle est une propriété vraie avant le début de la boucle et conservée à chaque répétition. Un argument de correction vérifie qu’elle est vraie au départ, qu’elle est conservée et ce qu’elle implique à la fin de la boucle. Un argument distinct de terminaison montre que la boucle finit par s’arrêter.

Pour le tri par sélection, utilise cet invariant : avant le passage i, les i premières positions contiennent les i plus petits éléments dans l’ordre.

  1. Départ : avant le passage 0, le préfixe est vide. Il satisfait déjà la propriété.
  2. Conservation : le passage trouve le plus petit élément restant. Le placer à la suite allonge le préfixe trié d’un élément, et cet élément est au moins aussi grand que tous ceux qui ont été placés avant lui.
  3. Fin : après au plus n−1 passages, seul le plus grand élément reste hors du préfixe. Toute la liste est triée.

Chaque déplacement est un échange : le multiensemble des éléments reste donc lui aussi inchangé. Une sortie ordonnée ne suffirait pas à satisfaire toute la spécification du tri.

Le tri à bulles utilise un invariant sur le suffixe : après k passages, les k dernières positions contiennent les k plus grands éléments dans l’ordre. Le passage suivant transporte le plus grand élément non trié jusqu’à ce suffixe. Un passage sans échange établit que toute la partie restante est ordonnée, ce qui permet un arrêt anticipé.

Expliquer les intervalles écartés par la recherche dichotomique

Utilise l’invariant suivant : si la valeur recherchée apparaît, au moins une occurrence se trouve dans l’intervalle de low à high, bornes comprises. Au départ, cet intervalle couvre toute la liste. Si la valeur médiane est trop petite, l’ordre de la liste rend trop petite toute valeur située à mid ou à sa gauche. Mettre low à mid + 1 conserve toute correspondance possible. La mise à jour high = mid - 1 suit le même raisonnement pour les valeurs trop grandes.

Lorsqu’une correspondance est trouvée, la position renvoyée satisfait directement la postcondition. Si l’intervalle devient vide, l’invariant exclut la présence de la valeur recherchée partout dans la liste. L’entrée reste triée car la recherche ne la modifie jamais.

Montrer pourquoi l’exécution s’arrête

Une mesure entière positive ou nulle qui diminue prouve que l’exécution progresse vers une fin. Dans la recherche dichotomique, le nombre de positions candidates diminue strictement après chaque absence de correspondance. L’indice médian testé est exclu : la boucle ne peut donc pas conserver indéfiniment le même intervalle. Les tris à bulles et par sélection effectuent au plus n−1 passages pour une entrée non vide et aucun passage pour une entrée vide.

Le tri fusion atteint des listes de zéro ou un élément car chaque appel récursif utilise une liste plus courte. Ces cas de base sont triés. En supposant que les appels sur des listes plus courtes renvoient des moitiés correctement triées, la fusion prend à chaque fois le plus petit élément restant et conserve tous les éléments. Cela transmet la correction jusqu’à l’appel initial.

Utiliser les tests pour une autre tâche

Un test compare un résultat réel à un résultat attendu. Réussir de nombreux tests choisis renforce la confiance, tandis qu’une seule entrée valide qui échoue est un contre-exemple qui réfute la correction. Un argument général par invariant couvre la famille non bornée d’entrées possibles qu’un ensemble fini de tests sur des exemples laisse sans vérification. Les tests sont particulièrement utiles pour vérifier que le code réel implémente la méthode utilisée dans l’argument.

Points clés

  • La correction exige le résultat spécifié et la terminaison pour toute entrée valide.
  • Un invariant doit être vrai au départ, rester vrai à chaque itération et permettre de justifier le résultat à la sortie.
  • Un argument de tri doit conserver les éléments et établir leur ordre.
  • Une mesure positive ou nulle qui diminue strictement établit la terminaison.
  • Une seule entrée valide qui échoue réfute la correction.

5.2 Teste des algorithmes avec des cas limites

Un cas limite est une entrée valide proche d’une limite, où il est facile de se tromper dans les hypothèses et les bornes des boucles. Prévois le résultat attendu à partir de la spécification avant d’exécuter le code. Sinon, la sortie erronée d’un programme peut devenir discrètement ta réponse attendue.

Choisir des listes qui mettent les limites à l’épreuve

Teste des listes vides, à un élément et à deux éléments ; des listes déjà triées et en ordre inverse ; des valeurs répétées et toutes égales ; des nombres négatifs ; et des longueurs impaires et paires. Pour les recherches, inclus la première position, la dernière position et des valeurs recherchées absentes, respectivement inférieures, supérieures et intermédiaires aux valeurs stockées.

Une recherche dichotomique dans une liste vide doit renvoyer -1 sans accéder à un élément : low = 0 et high = -1 rendent l’intervalle initial vide. Trier [3, 3, 3] doit renvoyer trois exemplaires de 3. Une sortie [3] serait ordonnée mais ne conserverait pas les éléments.

Suivre le plus petit échec

Une recherche dichotomique utilisant while low < high n’entre pas dans sa boucle pour [5] avec la valeur recherchée 5. La correction est low <= high, puisqu’un intervalle à une position contient encore un élément candidat. Ce test à un élément isole la limite plus clairement qu’une longue liste.

Avec low = mid, chercher 20 dans [10, 20] fixe l’indice médian à 0, rencontre 10 et laisse low à 0. L’intervalle reste inchangé à la répétition suivante. Utilise low = mid + 1 pour exclure une position déjà vérifiée. Une liste à deux éléments avec la valeur recherchée en dernier révèle cette boucle infinie.

Le tri à bulles compare items[j] à items[j + 1]. Au premier passage, le dernier indice gauche valide est n - 2. Continuer jusqu’à n - 1 lit au-delà de la liste et déclenche une IndexError de Python. Une telle erreur d’une position à la limite est appelée erreur de décalage d’une unité.

Vérifier les deux garanties sur la sortie

Pour un tri, vérifie l’ordre des éléments adjacents et le nombre d’occurrences de chaque élément d’origine. Utilise des enregistrements identifiés pour tester la stabilité. Ana 85, Ben 92, Cara 85 doit conserver Ana avant Cara lorsqu’un tri stable par note regroupe les notes égales. Une vérification des seules notes ne révélerait pas un échange de ces deux enregistrements.

Génère aussi des listes aléatoires. Compare leurs résultats à ceux d’une implémentation fiable comme sorted de Python. Conserve des doublons et des longueurs différentes dans les entrées générées. Lorsqu’un test échoue, réduis l’entrée tout en conservant l’échec, puis suis son exécution à la main. Garde le petit exemple comme test de non-régression pour que le bogue réparé reste détectable.

Éviter le dépassement dans le calcul de l’indice médian

Les entiers Python grandissent selon les besoins : (low + high) // 2 ne provoque donc pas de dépassement de capacité. Certains langages utilisent des entiers de taille fixe. Pour de très grands indices positifs ou nuls, leur somme peut dépasser la plage représentable. L’addition d’entiers en Java reboucle ; le dépassement de capacité d’un entier signé en C a un comportement indéfini.

Avec des indices valides et low <= high, calcule plutôt low + (high - low) // 2. La différence est positive ou nulle et le résultat reste entre les bornes. Cela calcule le même indice médian arrondi à l’entier inférieur sans former la somme qui pourrait provoquer un dépassement. Les tests aux limites et le raisonnement sur la représentation des nombres dans le langage se complètent ici.

Points clés

  • Écris les résultats attendus avant d’exécuter les tests.
  • Les petites listes révèlent les dernières vérifications manquantes, les intervalles inchangés et les accès invalides à un voisin.
  • Vérifie la conservation des éléments et leur ordre, ainsi que la stabilité lorsqu’elle est requise.
  • Réduis les entrées aléatoires qui échouent et conserve-les comme tests de non-régression.
  • Le calcul de l’indice médian par différence évite le dépassement pour des indices valides, positifs ou nuls, de taille fixe.

5.3 Choisis un algorithme adapté à la situation

Un algorithme convient à une tâche lorsque ses exigences et ses coûts correspondent aux données et au travail à effectuer. Prends en compte l’ordre de l’entrée, l’accès aux positions, le nombre d’opérations futures, la mémoire supplémentaire, la stabilité et le coût du déplacement des enregistrements.

Comparer les méthodes
MéthodeTemps ou profil des étapesEspace supplémentaireStable ?
Recherche séquentielleJusqu’à n comparaisonsFixePas une propriété de tri
Recherche dichotomiqueJusqu’à ⌊log⁡2n⌋+1 vérifications médianesFixePas une propriété de tri
Tri à bulles avec arrêt anticipén−1 comparaisons si l’entrée est triée ; pire cas quadratiqueFixeOui, avec des échanges stricts
Tri par sélectionn(n−1)/2 comparaisons ; au plus n−1 échanges qui déplacent des élémentsFixeNon, dans la forme habituelle avec échanges
Tri fusionCroissance des comparaisons en nlog⁡nProportionnel à nOui, en prenant à gauche en cas d’égalité

La recherche dichotomique nécessite aussi un ordre trié et un accès rapide au milieu. Une bonne comparaison inclut ces prérequis ; un faible nombre de recherches seul ne tient pas compte du coût de préparation de données inadaptées.

Déterminer si trier d’abord est rentable

Pour une recherche dans un million d’éléments non triés, la recherche séquentielle coûte au plus un million de comparaisons. Trier d’abord par tri fusion coûte environ 20 millions de comparaisons avant la première recherche dichotomique, qui nécessite ensuite au plus 20 vérifications médianes. La préparation dépasse largement le gain pour cette seule requête.

Pour 100 requêtes sur une liste inchangée, des recherches séquentielles répétées peuvent coûter 100 millions de comparaisons. Trier une fois puis effectuer 100 recherches dichotomiques coûte environ 20 millions de comparaisons plus 2 000 vérifications médianes. La préparation est réutilisée, ce qui rend le second plan intéressant. Avec ce modèle de coût approximatif, le seuil de rentabilité se situe autour de 20 recherches. L’estimation suppose des coûts d’opération comparables et des parcours dans le pire cas ; ce n’est pas un seuil universel de requêtes.

Évaluer l’ordre, les déplacements et la mémoire

Le tri à bulles peut finir rapidement lorsqu’une seule paire voisine est mal placée. [1, 2, 4, 3, 5] nécessite un échange au premier passage et un deuxième passage pour confirmer l’ordre : sept comparaisons. Mais « presque trié » ne garantit pas un petit nombre de passages. Une petite valeur tout à droite ne peut se déplacer que d’une position vers la gauche à chaque passage.

Le petit nombre d’échanges du tri par sélection est utile lorsque les enregistrements coûtent cher à déplacer. Le tri par sélection et le tri à bulles utilisent tous deux une quantité fixe d’espace supplémentaire. Le tri fusion traite les grandes listes avec une croissance du temps bien plus lente, mais sa forme habituelle sur des listes nécessite de la place pour environ autant d’éléments qu’une liste supplémentaire.

Si les enregistrements de même clé doivent conserver leur ordre antérieur, choisis une méthode stable. Une liste déjà alphabétique par nom peut être triée de façon stable par note tout en restant alphabétique dans chaque groupe de même note. Le tri par sélection ordinaire peut perturber cet ordre entre éléments de même clé.

Utiliser des outils de bibliothèque testés

Les programmes réels utilisent généralement le tri intégré du langage. Le tri stable de Python utilise une méthode adaptative fondée sur la fusion, couramment appelée Timsort, qui tire parti de l’ordre déjà présent dans l’entrée. sorted(items) renvoie une nouvelle liste, tandis que items.sort() modifie la liste existante. Une méthode qui modifie une liste en place du point de vue de son interface peut tout de même utiliser une mémoire de travail temporaire en interne ; elle ne satisfait pas nécessairement la définition à espace supplémentaire fixe utilisée pour les tris simples ci-dessus.

Pour une poignée d’éléments, un code simple et clair peut compter davantage que la croissance. Pour de grandes collections, compare le comportement dans le pire cas et la mémoire, ainsi que les propriétés réellement requises par la tâche.

Points clés

  • Inclus le coût de préparation lorsque tu compares des recherches sur des données non triées.
  • Des recherches répétées peuvent rentabiliser un tri effectué une seule fois.
  • Le tri par sélection limite les échanges ; le tri fusion limite la croissance du temps mais nécessite de l’espace supplémentaire.
  • Utilise un tri stable pour conserver l’ordre antérieur au sein des groupes de même clé.
  • Les tris intégrés offrent des implémentations testées ; pour les petites entrées, la simplicité peut l’emporter.

Algorithmes de tri : exemples

5 Leçons Interactives

1

Trouve une valeur sans perdre le fil des positions

13 étapes
Suis la recherche séquentielle et la recherche dichotomique, compte leur travail et vérifie les limites de chaque recherche.
  1. 1
    IntroductionTrouve une valeur et indique sa position

    Une recherche doit distinguer une valeur stockée de sa position. Dans [7, 3, 9, 3, 5], les positions vont de 0 à 4. La valeur 3 apparaît aux indices 1 et 3.

    Nous allons d’abord vérifier les positions dans l’ordre (recherche séquentielle), puis utiliser l’ordre trié pour exclure des groupes de positions (recherche dichotomique), en comptant les comparaisons pour voir le travail de chacune. Les deux méthodes renvoient un indice en cas de succès et -1 lorsque la valeur recherchée est absente.

  2. 2
    ExplicationÉcarte une position à chaque absence de correspondance

    La recherche séquentielle compare la valeur recherchée à chaque élément de gauche à droite. Une correspondance termine immédiatement la recherche ; une absence de correspondance fait passer à la position suivante.

    Une liste non triée ne donne aucune raison de rejeter les éléments ultérieurs après une première absence de correspondance. C’est pourquoi le retour « non trouvé » doit être placé après la boucle, une fois toutes les positions vérifiées.

  3. 3
    ExempleTrouve le premier 3

    Cherche 3 dans [7, 3, 9, 3, 5].

    À l’indice 0, 7 diffère de 3, donc continue. À l’indice 1, la valeur stockée est 3 : renvoie donc 1 après deux comparaisons.

    Le second 3 n’est jamais examiné. L’indice renvoyé est 1, tandis que le nombre de comparaisons est 2 ; ces nombres décrivent des aspects différents du suivi.

  4. 4
    DéfiSuis une correspondance plus loin dans la liste

    Une recherche séquentielle cherche 11 dans [19, 4, 11, 4, 8]. Quel indice renvoie-t-elle et combien de comparaisons effectue-t-elle ?

    ---reveal---

    Elle renvoie l’indice 2 après trois comparaisons : 19, 4, puis 11. Un retour indiquant l’échec après la première absence de correspondance s’arrêterait à tort à 19. L’indice 2 correspond à la troisième position car les positions commencent à zéro.

  5. 5
    Point cléLaisse la valeur recherchée déterminer le moment de l’arrêt

    Pour une liste non vide de n éléments, la recherche séquentielle utilise une comparaison dans le meilleur cas et n dans le pire. Une liste vide n’en utilise aucune.

    Si la valeur recherchée apparaît une fois et a autant de chances de se trouver à chaque position, la moyenne pour une recherche fructueuse est (n+1)/2. Compter toutes les occurrences change la tâche : même une correspondance précoce ne peut pas mettre fin à ce parcours complet.

  6. 6
    AnalogieUtilise l’ordre pour écarter un côté

    Un dictionnaire te permet de te diriger vers la moitié qui contient le mot recherché. La recherche dichotomique utilise la même idée d’ordre avec des bornes d’indices précises.

    Sa précondition est que les données soient triées. Si un nombre au milieu est trop petit, tous les nombres précédents le sont aussi. Sans ordre, une comparaison avec le milieu ne fournit pas cette information sur les autres positions.

  7. 7
    ExplicationGarde les deux bornes dans l’intervalle

    Commence avec low = 0 et high = n - 1. Tant que low <= high, calcule mid = (low + high) // 2.

    Renvoie mid si l’élément correspondant est égal à la valeur recherchée. Si sa valeur est trop petite, fixe low = mid + 1 ; si elle est trop grande, fixe high = mid - 1. L’indice médian testé est exclu dans les deux cas d’absence de correspondance : chaque mise à jour réduit donc l’intervalle de recherche.

  8. 8
    ExempleVérifie le milieu, puis la moitié droite

    Trouve 64 dans [3, 8, 12, 17, 23, 31, 42, 56, 64, 77, 85]. Les bornes initiales sont 0 et 10. Leur indice médian arrondi à l’entier inférieur est 5, qui contient 31.

    Comme 31 est inférieur à 64, fixe low = 6. Les bornes restantes 6 et 10 donnent l’indice médian 8. Sa valeur est 64 : renvoie donc 8 après deux vérifications d’éléments médians.

  9. 9
    ExempleObserve comment une valeur absente vide l’intervalle

    Dans cette même liste triée, cherche 20. Les indices et valeurs vérifiés sont 5 → 31, 2 → 12, 3 → 17 et 4 → 23.

    Les mises à jour donnent low = 4, high = 3. Il ne reste aucun élément candidat : renvoie donc -1. La dernière vérification comptait : les bornes égales juste avant indiquaient un élément candidat, et non un intervalle vide.

  10. 10
    DéfiRecalcule l’indice médian après chaque mise à jour

    Cherche 34 dans [2, 7, 13, 21, 34, 55] avec des bornes comprises et des indices médians arrondis à l’entier inférieur. Quels indices sont vérifiés ?

    ---reveal---

    Vérifie d’abord l’indice 2, qui contient 13. Fixe low = 3 tandis que high reste à 5 : l’indice médian suivant est donc 4. Il contient 34 : renvoie 4 après deux vérifications. La position suivant 2 n’était pas automatiquement le nouvel indice médian.

  11. 11
    ConseilVérifie le dernier candidat et exclus ceux déjà testés

    low <= high permet de vérifier un intervalle à une position. Une condition stricte < manque [5] lors de la recherche de 5.

    Utilise mid + 1 et mid - 1 après une absence de correspondance. Avec low = mid, une recherche de 20 dans [10, 20] peut répéter indéfiniment l’indice médian 0. Si plusieurs éléments égaux correspondent, cette version renvoie un indice correspondant, sans garantir que c’est le premier.

  12. 12
    DéfiChoisis une recherche adaptée à l’entrée réelle

    Tu disposes d’une liste non triée et tu dois effectuer une recherche, sans avoir le temps de préparer une copie triée. Quelle recherche enseignée s’applique directement et pourquoi ?

    ---reveal---

    La recherche séquentielle s’applique car chaque vérification d’égalité est valide sans aucun ordre. La recherche dichotomique nécessite un ordre trié pour justifier les intervalles qu’elle écarte. Un faible nombre de vérifications médianes ne peut pas compenser une précondition non satisfaite.

  13. 13
    RécapitulatifAppuie-toi sur les bons indices pour t’arrêter

    La recherche séquentielle s’arrête à la première correspondance ou après un parcours complet. La recherche dichotomique utilise l’ordre trié et l’accès rapide par indice pour réduire un intervalle bornes comprises.

    Note l’indice renvoyé séparément du nombre d’opérations. La recherche dichotomique nécessite au plus ⌊log⁡2n⌋+1 vérifications médianes pour une entrée non vide, mais chaque vérification peut contenir plusieurs comparaisons dans le code.

2

Construis l’ordre par des échanges voisins et à distance

16 étapes
Vérifie les exigences du tri, puis suis le tri à bulles et le tri par sélection et compare leurs coûts.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionPrécise la tâche de tri
  2. 2
    ExplicationConserve les éléments ainsi que leur ordre
  3. 3
    ExempleObserve ce que la stabilité conserve
  4. 4
    DéfiVérifie les deux conditions du tri
  5. 5
    ExplicationTransporte un grand élément vers la droite
  6. 6
    ExempleSuis trois échanges successifs
  7. 7
    ExempleCompte le passage de confirmation
  8. 8
    DéfiCompare les échanges aux comparaisons
  9. 9
    Point cléCompte les inversions pour compter les échanges
  10. 10
    ExplicationSélectionne un minimum avant de le déplacer
  11. 11
    ExemplePlace les deux premiers minima
  12. 12
    ExempleTermine sans échanger une valeur avec elle-même
  13. 13
    DéfiTrouve un minimum après le préfixe
  14. 14
    Point cléUn échange à distance peut dépasser une clé égale
  15. 15
    DéfiChoisis une méthode lorsque les déplacements coûtent cher
  16. 16
    RécapitulatifSuis la partie que chaque méthode place définitivement
3

Divise une liste et reconstruis-la par fusions

13 étapes
Suis l’opération de fusion, puis l’exécution complète d’un tri fusion récursif et compte ses niveaux.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionUtilise l’ordre déjà construit dans les petits morceaux
  2. 2
    ExplicationCompare uniquement les éléments de tête inutilisés
  3. 3
    ExempleFusionne les premières valeurs
  4. 4
    ExempleCopie la queue après la fin des comparaisons
  5. 5
    DéfiTermine une fusion et compte ses comparaisons
  6. 6
    ExplicationRends chaque problème récursif plus petit
  7. 7
    ExempleDivise huit éléments en éléments isolés
  8. 8
    ExempleReconstruis les paires et les moitiés
  9. 9
    ExempleCompte chaque niveau de fusion
  10. 10
    DéfiInclus le travail effectué dans les moitiés
  11. 11
    LienPréserve l’ordre des clés égales pendant la reconstruction
  12. 12
    DéfiApplique la méthode à un grand tri stable
  13. 13
    RécapitulatifCompte les éléments à travers les niveaux
4

Transforme un travail répété en estimation de temps

14 étapes
Compte les exécutions de boucles, compare les familles de croissance et estime des temps d’exécution et des budgets de temps.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionDemande-toi combien de travail nécessite la taille suivante
  2. 2
    ExplicationChoisis ce qui compte comme une étape
  3. 3
    ExempleNe compte chaque paire qu’une fois
  4. 4
    DéfiLis les bornes avant de nommer la croissance
  5. 5
    Point cléAssocie le cas au nombre d’étapes
  6. 6
    ExplicationEssaie le test par doublement
  7. 7
    ExempleDistingue une notation de croissance d’un nombre exact
  8. 8
    DéfiTrouve un point de croisement à partir de modèles exacts
  9. 9
    LienObserve la limite d’un matériel plus rapide
  10. 10
    ExempleExtrapole un temps quadratique mesuré
  11. 11
    DéfiRetrouve une taille d’entrée à partir d’un budget de temps
  12. 12
    ConseilMesure plusieurs fois des cas comparables
  13. 13
    DéfiUtilise les rapports observés pour une prévision
  14. 14
    RécapitulatifApplique le modèle de comptage à l’estimation
5

Montre qu’un algorithme fonctionne et convient à la tâche

15 étapes
Utilise des invariants, des arguments de terminaison, des tests aux cas limites et des comparaisons de coûts pour évaluer un algorithme.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionCherche une garantie et une méthode adaptée
  2. 2
    ExplicationÉnonce les garanties avant de les démontrer
  3. 3
    ExempleÉtends l’invariant du tri par sélection
  4. 4
    ExempleConserve une correspondance possible et réduis son intervalle
  5. 5
    DéfiDistingue la conservation de la terminaison
  6. 6
    ExplicationPrévois les résultats aux limites avant l’exécution
  7. 7
    ExempleUtilise un intervalle à deux éléments pour révéler une boucle
  8. 8
    DéfiTrouve la borne de la boucle sur les voisins
  9. 9
    ConseilConserve un test minimal qui échoue
  10. 10
    ExplicationInclus le coût de préparation
  11. 11
    ExempleRéutilise la liste triée pour plusieurs requêtes
  12. 12
    DéfiCalcule si la préparation est rentable
  13. 13
    LienChoisis selon les propriétés et la croissance du temps
  14. 14
    DéfiRelie la correction à une exigence pratique
  15. 15
    RécapitulatifUtilise ensemble les arguments, les tests et les coûts

Algorithmes de tri : QCM

40 Questions Pratiques en 4 séries

Série 1 : Trouve des valeurs et suis les algorithmes10 Questions Pratiques

Question 1 sur 10

Une recherche séquentielle cherche 7 dans [12, 7, 18, 7]. Quel indice renvoie-t-elle ?
  1. 0
  2. 1
  3. 2
  4. 3
Afficher la réponseMasquer la réponse
Réponse : B
La première correspondance est le deuxième élément, d’indice 1 car les indices commencent à zéro. La recherche séquentielle s’arrête à cet endroit et n’atteint donc jamais le second 7 à l’indice 3. Renvoyer 2 reviendrait à confondre le nombre d’éléments vérifiés avec la position renvoyée.

Question 2 sur 10

Une recherche dichotomique utilise des bornes comprises et un indice médian arrondi à l’entier inférieur sur [4, 9, 15, 22, 30, 41, 57]. Quels indices vérifie-t-elle pour chercher 41 ?
  1. 3, 4, 5
  2. 3, 6, 5
  3. 4, 5
  4. 3, 5
Afficher la réponseMasquer la réponse
Réponse : D
Le premier indice médian est 3, qui contient 22. Comme 41 est plus grand, les bornes restantes sont 4 et 6, dont l’indice médian est 5, où se trouve 41. Vérifier ensuite l’indice 4 reviendrait à parcourir l’intervalle restant depuis son début au lieu de choisir son milieu.

Question 3 sur 10

Une fonction de tri reçoit [6, 2, 6, 1]. Quelle sortie satisfait la spécification d’un tri croissant ?
  1. [1, 2, 6, 6]
  2. [1, 2, 6]
  3. [1, 2, 2, 6]
  4. [6, 6, 2, 1]
Afficher la réponseMasquer la réponse
Réponse : A
La sortie doit être non décroissante et conserver chaque occurrence d’origine, y compris les deux exemplaires de 6. La liste [1, 2, 6] contient des valeurs ordonnées mais perd un élément. Trier réorganise les données ; cela ne supprime pas les valeurs répétées.

Question 4 sur 10

Quelle liste reste après un passage complet du tri à bulles de gauche à droite sur [8, 3, 6, 2] ?
  1. [3, 6, 8, 2]
  2. [2, 3, 6, 8]
  3. [3, 6, 2, 8]
  4. [3, 8, 2, 6]
Afficher la réponseMasquer la réponse
Réponse : C
Les comparaisons conduisent à échanger 8 avec 3, puis 8 avec 6, puis 8 avec 2, ce qui donne [3, 6, 2, 8]. La plus grande valeur est maintenant à sa place définitive à droite. Un résultat entièrement trié supposerait qu’un seul passage ordonne aussi le préfixe restant, ce que ce suivi montre faux.

Question 5 sur 10

Fusionne [2, 11] avec [5, 14, 19]. Après la copie de 11, quels éléments restent à copier ?
  1. 5 et 19
  2. 14 et 19
  3. 19 seulement
  4. 11 et 14
Afficher la réponseMasquer la réponse
Réponse : B
Après la copie de 2, 5 et 11, l’entrée de gauche est épuisée et celle de droite contient encore 14 et 19. Les deux doivent être copiés pour conserver tous les éléments. Copier seulement 19 omettrait 14, même si aucune autre comparaison d’éléments de tête n’est nécessaire.

Question 6 sur 10

Un appel du tri fusion reçoit [16]. Que doit-il renvoyer ?
  1. [16] immédiatement
  2. [] immédiatement
  3. [16, 16] après fusion
  4. [] après division
Afficher la réponseMasquer la réponse
Réponse : A
Une liste à un élément satisfait déjà les conditions du tri : le cas de base renvoie donc [16] sans modification. Renvoyer une liste vide ferait perdre l’élément d’origine. Une nouvelle division récursive est inutile car le problème a déjà atteint sa taille d’arrêt.

Question 7 sur 10

Un algorithme compare une fois chaque paire de positions distinctes dans une liste de 7 éléments. Combien de comparaisons d’éléments effectue-t-il ?
  1. 49
  2. 42
  3. 28
  4. 21
Afficher la réponseMasquer la réponse
Réponse : D
Les éléments successifs nécessitent 6, 5, 4, 3, 2, 1 et 0 comparaisons avec les positions suivantes, soit 21 au total. On peut aussi utiliser 7×6/2. Un total de 42 compte chaque paire non ordonnée deux fois, une dans chaque sens.

Question 8 sur 10

Une méthode prend exactement n2 étapes. Comment ce nombre change-t-il lorsque la taille de l’entrée double ?
  1. Il double.
  2. Il triple.
  3. Il quadruple.
  4. Il reste inchangé.
Afficher la réponseMasquer la réponse
Réponse : C
Remplacer n par 2n donne (2n)2=4n2 : le nombre est donc multiplié par quatre. Doubler seulement le nombre d’étapes décrirait une croissance linéaire. Le carré s’applique au rapport des tailles comme à la taille initiale de l’entrée.

Question 9 sur 10

Le tri par sélection a placé les quatre plus petits éléments dans l’ordre aux indices 0 à 3. Pourquoi choisir le minimum à partir de l’indice 4 et l’échanger pour le placer à l’indice 4 conserve-t-il cette propriété du préfixe ?
  1. Le suffixe restant est déjà ordonné.
  2. Le cinquième élément reste inchangé à chaque parcours.
  3. Le nouvel élément est au moins aussi grand que les quatre placés.
  4. Les échanges précédents ont supprimé toutes les inversions.
Afficher la réponseMasquer la réponse
Réponse : C
Le minimum restant est au moins aussi grand que chaque élément déjà placé : l’ajouter à la suite allonge donc le préfixe ordonné des plus petits éléments. Un parcours complet du suffixe détermine ce minimum. Il n’établit pas que tout le suffixe était déjà ordonné, ce qui serait une affirmation plus forte et injustifiée.

Question 10 sur 10

Une recherche dichotomique à bornes comprises utilise par erreur while low < high. Quel est le plus petit test non vide qui révèle qu’une valeur présente est manquée ?
  1. [13], valeur recherchée 13
  2. [13], valeur recherchée 8
  3. [8, 13], valeur recherchée 8
  4. [8, 13], valeur recherchée 20
Afficher la réponseMasquer la réponse
Réponse : A
Avec un élément, les deux bornes valent 0 : la condition stricte incorrecte saute donc l’unique élément candidat et indique un échec pour la valeur recherchée 13. Une valeur absente dans cette même liste peut tout de même donner le bon résultat. Le test doit utiliser une valeur présente pour révéler l’absence de dernière vérification.
Série 2 : Compte le travail et choisis des méthodes pratiques10 Questions Pratiques

Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.

Question 1 sur 10

Une recherche séquentielle indique qu’une valeur est absente d’une liste non triée de 9 éléments. Combien de comparaisons entre un élément et la valeur recherchée effectue-t-elle ?
  1. 0
  2. 1
  3. 8
  4. 9
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 2 sur 10

Une recherche dichotomique utilise des bornes comprises et un indice médian arrondi à l’entier inférieur. Dans [6, 12, 18, 25, 33, 46], quelles sont les bornes juste après la première vérification pour la valeur recherchée 30 ?
  1. Borne basse 2, borne haute 5
  2. Borne basse 3, borne haute 5
  3. Borne basse 0, borne haute 1
  4. Borne basse 0, borne haute 2
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 3 sur 10

Un tri à bulles avec arrêt anticipé utilise des passages raccourcis sur [1, 3, 2, 4]. Combien de comparaisons effectue-t-il avant de s’arrêter ?
  1. 3
  2. 4
  3. 5
  4. 6
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 4 sur 10

Le tri par sélection standard reçoit 6 éléments déjà triés. Combien de comparaisons d’éléments effectue-t-il ?
  1. 15
  2. 5
  3. 0
  4. 30
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 5 sur 10

Une fusion de [1, 8, 13] et [4, 9] ne compte que les comparaisons entre éléments de tête. Combien en effectue-t-elle ?
  1. 2
  2. 3
  3. 4
  4. 5
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 6 sur 10

Une boucle s’exécute n fois. À chaque répétition, une seconde boucle s’exécute exactement 4 fois. Combien de fois le corps de la boucle interne s’exécute-t-il ?
  1. n+4
  2. n2
  3. 4n
  4. 4n
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 7 sur 10

Une méthode de tri quadratique prend 3 secondes pour 12 000 éléments. Environ combien de temps devrait-elle prendre pour 36 000 éléments dans des conditions comparables ?
  1. 27 secondes
  2. 9 secondes
  3. 18 secondes
  4. 81 secondes
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 8 sur 10

Un tri reçoit [4, 4, -2] et renvoie [-2, 4]. Quelle exigence a-t-il violée ?
  1. Ordonner les clés par ordre croissant
  2. Conserver chaque occurrence
  3. Renvoyer le plus petit élément en premier
  4. Placer les valeurs négatives en premier
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 9 sur 10

Pour une collection non triée et inchangée, utilise ces estimations de coût : le tri coûte 9 000 unités, chaque requête dichotomique 12 unités et chaque requête séquentielle 600 unités. Quel plan coûte le moins pour 20 requêtes, et de combien ?
  1. Requêtes séquentielles, de 2 760 unités
  2. Requêtes séquentielles, de 3 000 unités
  3. Tri puis requêtes dichotomiques, de 3 000 unités
  4. Tri puis requêtes dichotomiques, de 2 760 unités
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 10 sur 10

Une tâche ne peut utiliser qu’un espace de travail supplémentaire fixe et doit minimiser les échanges. Parmi les méthodes de tri enseignées, quel choix répond le mieux à ces priorités ?
  1. Le tri fusion, en prenant d’abord à gauche en cas d’égalité
  2. Le tri par sélection, avec un échange par passage
  3. Le tri à bulles, avec un indicateur d’arrêt anticipé
  4. Le tri fusion, avec une seule fusion finale
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Série 3 : Explique les limites et compare les compromis10 Questions Pratiques

Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.

Question 1 sur 10

Une recherche dichotomique utilise des bornes comprises et des indices médians arrondis à l’entier inférieur sur [5, 11, 16, 24, 38, 47, 59, 70]. Quels indices sont vérifiés pour la valeur absente 41 ?
  1. 3, 5, 4
  2. 3, 4, 5
  3. 4, 6, 5
  4. 3, 5, 6
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 2 sur 10

Des enregistrements arrivent dans cet ordre : Eli 72, Jo 65, Kai 72, Luz 65. Quel ordre résulte d’un tri stable par note croissante ?
  1. Luz, Jo, Eli, Kai
  2. Jo, Luz, Kai, Eli
  3. Jo, Luz, Eli, Kai
  4. Eli, Kai, Jo, Luz
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 3 sur 10

Quelle est la liste après le deuxième passage du tri par sélection sur [18, 7, 12, 4, 9] ?
  1. [4, 7, 9, 12, 18]
  2. [7, 4, 12, 18, 9]
  3. [4, 9, 12, 18, 7]
  4. [4, 7, 12, 18, 9]
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 4 sur 10

Le tri fusion divise une liste de 32 éléments en deux jusqu’à obtenir des éléments isolés. Combien de niveaux de fusion la reconstruisent ?
  1. 4
  2. 5
  3. 6
  4. 16
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 5 sur 10

La méthode P utilise 60n étapes et la méthode Q utilise n2. Pour des tailles d’entrée positives, quand P utilise-t-elle moins d’étapes ?
  1. Lorsque n>60
  2. Lorsque n<60
  3. Lorsque n≥60
  4. Lorsque n≤60
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 6 sur 10

Un processus quadratique prend 5 secondes pour 8 000 éléments. Environ combien d’éléments un budget de 45 secondes permet-il de traiter avec le même modèle ?
  1. 24 000 éléments après multiplication par 9
  2. 72 000 éléments après multiplication par 9
  3. 16 000 éléments après multiplication par 2
  4. 24 000 éléments après multiplication par 3
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 7 sur 10

Une recherche dichotomique à bornes comprises conserve toute correspondance possible dans son intervalle, mais après un élément médian de valeur trop petite, elle fixe low = mid. Quelle partie d’un argument complet de correction peut échouer ?
  1. La précondition sur l’ordre de l’entrée
  2. La garantie que l’exécution s’arrête
  3. Le test d’égalité en cas de correspondance
  4. La conservation des éléments d’origine
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 8 sur 10

Une liste est déjà ordonnée par heure d’arrivée. Elle doit maintenant être ordonnée par priorité tout en conservant l’ordre d’arrivée pour les priorités égales. Quelle propriété de tri est nécessaire ?
  1. Un espace supplémentaire fixe
  2. Peu d’échanges qui déplacent des éléments
  3. La stabilité pour les clés égales
  4. Une borne quadratique des comparaisons
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 9 sur 10

Un passage complet du tri à bulles ne fait aucun échange. Qu’établit-il pour toute la liste, y compris un éventuel suffixe déjà placé ?
  1. Elle est triée.
  2. Ses valeurs sont distinctes.
  3. Elle contient un élément.
  4. Ses clés sont égales.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 10 sur 10

Une fusion stable combine les enregistrements de gauche [2A, 6B] et ceux de droite [2C, 5D], en comparant seulement les clés numériques. Quel est l’ordre des enregistrements fusionnés ?
  1. 2C, 2A, 5D, 6B
  2. 2A, 5D, 2C, 6B
  3. 2A, 2C, 5D, 6B
  4. 2A, 2C, 6B, 5D
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Série 4 : Analyse des suivis et justifie des décisions10 Questions Pratiques

Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.

Question 1 sur 10

Une recherche séquentielle standard effectue 4 comparaisons sur [14, 6, 21, 6]. Si elle s’arrête immédiatement à la première correspondance, quelle paire valeur recherchée-résultat est possible ?
  1. Valeur recherchée 6, résultat 3
  2. Valeur recherchée 21, résultat 2
  3. Valeur recherchée 8, résultat -1
  4. Valeur recherchée 14, résultat 0
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 2 sur 10

Une recherche dichotomique à bornes comprises a pour bornes low = 6, high = 6, et l’élément restant est égal à la valeur recherchée. Que fait la boucle correcte ?
  1. Elle vérifie l’indice 6 et renvoie 6.
  2. Elle renvoie -1 sans vérifier.
  3. Elle porte la borne basse à 7 avant de vérifier.
  4. Elle vérifie l’indice 5 et renvoie 5.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 3 sur 10

Combien y a-t-il d’inversions dans [5, 3, 5, 2, 4, 1] ?
  1. 10
  2. 11
  3. 12
  4. 15
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 4 sur 10

Le tri par sélection utilise le test strict < pour trouver chaque minimum. Quel est l’ordre final des enregistrements pour [7A, 3X, 7B, 2Y, 3Z], en comparant seulement les clés numériques ?
  1. 2Y, 3Z, 3X, 7A, 7B
  2. 2Y, 3X, 3Z, 7B, 7A
  3. 2Y, 3Z, 3X, 7B, 7A
  4. 2Y, 3X, 3Z, 7A, 7B
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 5 sur 10

Utilise le tri fusion avec des divisions en deux arrondies à l’entier inférieur sur [9, 1, 7, 3]. En ne comptant que les comparaisons d’éléments dans les fusions, combien le tri complet en effectue-t-il ?
  1. 2
  2. 3
  3. 4
  4. 5
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 6 sur 10

Un algorithme compare d’abord chaque paire distincte une fois, puis parcourt une fois tous les n éléments, en comptant une comparaison par élément parcouru. Quelle formule donne le nombre total de comparaisons ?
  1. n(n−1)/2
  2. n(n+1)/2
  3. n2+n
  4. n(n−1)
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 7 sur 10

Un processus essaie toutes les sélections de n éléments indépendants, soit 2n sélections. Que devient ce nombre lorsqu’on ajoute un élément ?
  1. Il augmente d’une unité.
  2. Il est élevé au carré.
  3. Il double.
  4. Il quadruple.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 8 sur 10

Des exécutions répétées pour des tailles d’entrée qui doublent prennent environ 0,06 ; 0,24 et 0,96 seconde. Quel profil de croissance ces rapports étayent-ils ?
  1. Une croissance quadratique
  2. Une croissance linéaire
  3. Une complexité constante
  4. Une croissance logarithmique
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 9 sur 10

Une preuve montre qu’une boucle de tri s’arrête avec toutes les paires de voisins dans l’ordre. Son code écrase aussi certaines entrées sans les sauvegarder. Quelle propriété supplémentaire faut-il établir avant de qualifier le tri de correct ?
  1. Chaque passage utilise moins de comparaisons.
  2. Chaque élément d’origine conserve son nombre d’occurrences.
  3. Chaque clé égale conserve son ancienne position.
  4. Chaque exécution utilise une mémoire supplémentaire fixe.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 10 sur 10

Un test aléatoire révèle l’échec d’un tri sur une longue liste. Quelle étape suivante aide le mieux à trouver le bogue et à prévenir son retour ?
  1. Conserver toute la liste et suivre plusieurs fois chaque position.
  2. Remplacer l’entrée par une liste typique et conserver son résultat.
  3. Générer d’autres listes aléatoires avant d’examiner le premier échec.
  4. Réduire l’entrée qui échoue et la conserver comme test de non-régression.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Tu bloques sur ton propre exercice ? Aide aux Devoirs

Mots-Clés

62 Mots-Clés, chacun avec sa définition

A

Accès direct
L’accès direct consiste à atteindre un élément par son indice sans parcourir les éléments précédents, comme le permettent un tableau ou une liste Python.
Suivre les liens jusqu’au milieu d’une liste chaînée exige un parcours supplémentaire, ce qui réduit l’avantage de la recherche dichotomique.
Arrêt anticipé
Un arrêt anticipé termine un algorithme avant son travail maximal prévu dès qu’une condition vérifiée établit le résultat requis.
Un passage sans échange du tri à bulles confirme l’ordre ; les comparaisons de ce passage comptent tout de même dans le total.

B

Budget de temps
Un budget de temps est le temps d’exécution autorisé, utilisé avec un modèle de coût pour estimer la taille d’entrée qui peut être traitée.
Un processus quadratique peut traiter trois fois plus d’éléments lorsque son temps disponible est multiplié par neuf.

C

Cas de base
Un cas de base est une entrée traitée directement sans nouvel appel récursif, ce qui fournit un point d’arrêt à la récursivité.
Pour le tri fusion, une liste vide et une liste à un élément sont toutes deux renvoyées sans modification car elles sont déjà triées.
Cas limite
Un cas limite est une entrée valide située à une limite du comportement d’un algorithme, où les bornes des boucles ou le traitement particulier peuvent échouer.
Une liste vide permet de vérifier si la recherche dichotomique teste ses bornes avant de tenter d’accéder à un élément médian.
Cas moyen
Le cas moyen décrit le travail moyen pour une distribution d’entrées précisée : sa valeur dépend donc des entrées qui se présentent.
Des probabilités égales pour les positions où la valeur recherchée est trouvée donnent à la recherche séquentielle une moyenne de (n+1)/2 comparaisons.
Cas récursif
Un cas récursif ramène le problème courant à des instances plus petites et utilise leurs résultats pour construire la réponse.
Le cas récursif du tri fusion trie deux moitiés avant d’appeler la fusion sur les listes ordonnées qu’elles renvoient.
Clé de tri
Une clé de tri est la valeur ou le champ d’un enregistrement utilisé pour déterminer l’ordre ; le reste de l’enregistrement reste attaché à la clé lorsque l’élément se déplace.
Trier des enregistrements de villes par population déplace chaque nom de ville avec sa valeur de population.
Complexité constante
Une complexité constante signifie que le travail compté reste borné indépendamment de la taille de l’entrée, comme pour la lecture d’une position connue d’un tableau.
Accéder à un indice donné ne nécessite pas de parcourir tous les éléments précédents du tableau lorsque la liste grandit.
Compromis
Un compromis est un choix où l’amélioration d’une propriété utile peut se faire au détriment d’une autre, par exemple économiser des comparaisons en utilisant plus de mémoire.
Le tri fusion améliore la croissance du temps pour les grandes entrées, mais nécessite généralement plus d’espace temporaire que le tri par sélection.
Contre-exemple
Un contre-exemple est une entrée valide dont le comportement observé viole une propriété générale affirmée, réfutant ainsi cette affirmation.
Une seule liste triée de deux éléments qui provoque une recherche infinie réfute l’affirmation selon laquelle la recherche se termine toujours.
Coût de préparation
Un coût de préparation est le travail nécessaire avant l’opération principale, comme trier une liste pour que des recherches dichotomiques ultérieures soient valides.
Une seule requête peut favoriser un parcours séquentiel car son plan évite le coût important d’un tri unique.
Croissance exponentielle
Une croissance exponentielle multiplie le travail par un facteur fixe pour chaque élément supplémentaire ; un nombre de 2n double lorsqu’un élément est ajouté.
Essayer toutes les sélections de 30 éléments nécessite deux fois plus de sélections que d’essayer toutes celles de 29 éléments.
Croissance linéaire
Une croissance linéaire signifie que le travail augmente directement proportionnellement à la taille de l’entrée : doubler le nombre d’éléments double donc approximativement le travail.
Un parcours complet avec une comparaison de clé par élément effectue 2 000 comparaisons lorsque son entrée atteint 2 000 éléments.
Croissance logarithmique
Une croissance logarithmique apparaît lorsqu’une réduction répétée par un facteur fixe fait que chaque doublement de l’entrée n’ajoute qu’une quantité fixe de travail.
Les divisions successives par deux ajoutent environ une vérification médiane à la recherche dichotomique chaque fois que la taille de la liste double.
Croissance quadratique
Une croissance quadratique signifie que le travail augmente proportionnellement au carré de la taille de l’entrée, ce qui multiplie environ par quatre le travail lors d’un doublement.
Le nombre de comparaisons par paires du tri par sélection croît de façon quadratique même si son nombre d’échanges augmente bien plus lentement.
Curseur
Un curseur suit la prochaine position inutilisée dans une liste d’entrée afin qu’une fusion sache quel élément comparer ou copier ensuite.
Des curseurs gauche et droit distincts empêchent une fusion de copier deux fois un élément ou d’en sauter un après une comparaison.

D

Dépassement de capacité entière
Un dépassement de capacité entière se produit lorsqu’un calcul dépasse la plage de valeurs d’un entier de taille fixe ; l’effet dépend du langage et de l’opération.
Un calcul de l’indice médian par différence évite une somme de bornes trop grande lorsque les indices sont positifs ou nuls et valides.
Diviser pour régner
Le principe diviser pour régner résout un problème en le séparant en problèmes plus petits, en les résolvant et en combinant leurs résultats.
Le tri fusion combine les résultats triés des moitiés ; la division seule laisse l’ordre initial des valeurs inchangé.

É

Échange
Un échange permute deux éléments stockés tout en conservant les deux valeurs d’origine, à l’aide d’une valeur sauvegardée ou d’une affectation simultanée.
Sans sauvegarder une valeur, deux affectations successives peuvent transformer [2, 9] en [9, 9] au lieu d’échanger les éléments.
Élément de tête
Un élément de tête dans une fusion est le premier élément inutilisé d’une entrée triée et donc son plus petit élément restant.
Après avoir pris l’élément de tête gauche, avance seulement le curseur gauche ; l’élément de tête droit attend encore sa comparaison.
Éléments adjacents
Des éléments adjacents occupent des positions voisines dans une liste : leurs indices diffèrent donc exactement d’une unité lorsque les deux positions existent.
Le tri à bulles compare items[j] à items[j + 1] : ses déplacements dépendent donc de paires voisines.

E

Erreur de décalage d’une unité
Une erreur de décalage d’une unité fait qu’une borne de boucle ou d’indice inclut une position de trop ou de moins, ce qui provoque un élément manqué ou un accès invalide.
Utiliser low < high pour un intervalle de recherche dichotomique à bornes comprises saute un dernier élément candidat lorsque les bornes deviennent égales.

F

Fonction de tri de bibliothèque
Une fonction de tri de bibliothèque est une implémentation de tri testée d’un langage ou d’une bibliothèque, dont le comportement est documenté, notamment la stabilité et la forme de la sortie.
La fonction sorted de Python crée une nouvelle liste de résultats, tandis que list.sort() réorganise la liste existante.
Fusion
Une fusion combine deux listes triées en copiant à répétition le plus petit élément de tête inutilisé, puis en copiant toute queue restante.
Fusionner [3, 10] et [6, 12] produit [3, 6, 10, 12] sans retrier aucune des entrées.

I

Indice
Un indice est une position numérotée utilisée pour accéder à un élément de liste ; les indices Python commencent à zéro et se terminent une unité avant la longueur de la liste.
Dans [8, 13, 21], l’indice 2 contient 21, même s’il s’agit du troisième élément dans le langage courant.
Indice médian
Un indice médian est la position centrale choisie dans un intervalle de recherche, arrondie à l’entier inférieur lorsque la moyenne des bornes n’est pas entière.
Pour les bornes comprises 2 et 7, (2 + 7) // 2 choisit l’indice 4 comme indice médian suivant.
Intervalle de recherche
Un intervalle de recherche est l’intervalle des positions qui peuvent encore contenir une valeur recherchée après que les comparaisons précédentes ont écarté les autres.
Les bornes de 4 à 7 comprennent quatre positions candidates, et les bornes de 5 à 4 décrivent un intervalle vide.
Invariant de boucle
Un invariant de boucle est une propriété vraie avant le début de la boucle et conservée après chaque répétition, qui aide à justifier le résultat.
L’invariant du tri par sélection relie la longueur de son préfixe aux plus petits éléments déjà placés.
Inversion
Une inversion est une paire de positions où un élément situé avant possède une clé plus grande qu’un élément situé après ; des clés égales ne créent aucune inversion.
Dans [8, 3, 6], 8 forme une inversion avec chacune des deux valeurs suivantes, même si une seule paire est adjacente.

M

Meilleur cas
Le meilleur cas est la situation d’entrée valide qui nécessite le moins d’opérations comptées parmi les entrées de même taille.
Une recherche séquentielle qui trouve sa valeur recherchée en première position effectue une comparaison sur une liste non vide.

O

Opération élémentaire
Une opération élémentaire est l’action répétée choisie pour compter le travail, comme comparer deux clés ou vérifier un élément médian.
Une vérification médiane en recherche dichotomique peut effectuer deux comparaisons d’éléments : son nombre de vérifications doit donc être nommé séparément.
Ordre de croissance
Un ordre de croissance décrit comment le travail d’un algorithme évolue avec la taille de l’entrée, en distinguant son profil d’évolution du résultat d’une seule exécution.
Un temps faible pour une petite taille ne dit pas à quelle vitesse ce temps augmente lorsque les données deviennent beaucoup plus nombreuses.

P

Parcours complet
Un parcours complet examine chaque élément d’une collection, comme il est nécessaire de le faire pour compter toutes les correspondances ou trouver la plus grande valeur.
Compter toutes les occurrences de 7 continue après la première correspondance car les éléments suivants peuvent aussi contenir 7.
Passage
Un passage est un parcours de la partie active d’une liste, qui effectue une séquence de comparaisons ou de placements.
Un passage du tri à bulles place le plus grand élément restant, mais peut laisser les positions précédentes non triées.
Permutation
Une permutation est un réarrangement des mêmes éléments qui conserve le nombre d’occurrences de chaque valeur.
[2, 8, 2] et [2, 2, 8] sont des permutations l’une de l’autre ; [2, 8] perd une occurrence.
Pire cas
Le pire cas est la situation d’entrée valide qui nécessite le plus d’opérations comptées parmi les entrées de même taille.
Une valeur recherchée absente oblige la recherche séquentielle de base à examiner chaque position, ce qui donne son nombre d’opérations dans le pire cas.
Point de croisement
Un point de croisement est une taille d’entrée où deux modèles de coût sont égaux et au-delà de laquelle leur classement peut changer lorsque l’entrée grandit.
Les modèles 40n et n2 sont égaux pour 40 éléments ; le modèle linéaire devient moins coûteux pour des tailles positives plus grandes.
Postcondition
Une postcondition énonce ce qui doit être vrai du résultat d’un algorithme lorsqu’il se termine sur une entrée qui satisfait sa précondition.
Une postcondition de tri inclut à la fois l’ordre des clés et la conservation des occurrences d’origine.
Précondition
Une précondition est une exigence que doit satisfaire une entrée pour que le comportement promis par un algorithme soit garanti.
L’ordre croissant est une précondition de la recherche dichotomique ordinaire : une entrée non triée invalide donc son raisonnement sur les intervalles.
Préfixe trié
Un préfixe trié est une partie initiale d’une liste déjà ordonnée ; le tri par sélection y place d’abord les plus petits éléments.
Après trois passages de sélection, les trois premières positions contiennent les trois plus petits éléments dans l’ordre.
Prévision du temps d’exécution
Une prévision du temps d’exécution estime le temps pour une autre taille en appliquant un modèle de croissance à un temps de référence mesuré ou fourni.
Tripler l’entrée dans un modèle quadratique multiplie le temps de référence par environ neuf, et non par trois.

Q

Queue de liste
Une queue de liste est la partie restante d’une liste à partir d’une position choisie, copiée directement lorsque l’autre entrée de la fusion est épuisée.
Si une entrée de fusion est épuisée alors que [14, 20] reste de l’autre côté, les deux éléments de la queue sont encore nécessaires.

R

Recherche
Une recherche vérifie si une valeur recherchée apparaît dans une collection et peut indiquer sa position ou renvoyer un résultat signalant son absence.
Une recherche dans une liste d’identifiants d’enregistrements peut renvoyer la position de l’enregistrement demandé sans modifier la liste.
Recherche dichotomique
Une recherche dichotomique utilise l’ordre trié pour réduire un intervalle de recherche bornes comprises en comparant la valeur recherchée à un élément médian.
Une recherche dans un tableau trié d’environ un million d’éléments nécessite au plus 20 vérifications d’éléments médians.
Recherche séquentielle
Une recherche séquentielle vérifie les éléments dans l’ordre à partir du début, s’arrête à la première correspondance ou indique l’absence après avoir parcouru toute la liste.
Trouver le dernier élément d’une liste de neuf éléments par recherche séquentielle nécessite neuf comparaisons entre un élément et la valeur recherchée.
Récursivité
La récursivité résout un problème par des appels à la même procédure sur des instances plus petites, avec une règle d’arrêt pour les cas simples.
Le tri fusion s’appelle lui-même sur chaque moitié plus courte jusqu’à ce qu’un appel reçoive au plus un élément.

S

Spécification
Une spécification énonce les exigences relatives aux entrées valides et le résultat qu’un algorithme doit produire, ce qui permet de vérifier sa correction.
Une spécification de recherche distingue un indice correspondant d’un résultat particulier utilisé seulement lorsqu’aucune correspondance n’existe.
Suffixe non trié
Un suffixe non trié est la partie finale restante dont l’ordre interne n’a pas encore été établi par le processus de tri.
Le tri par sélection ne cherche que dans le suffixe non trié afin de ne pas sélectionner à nouveau un minimum déjà placé.

T

Taille de l’entrée
La taille de l’entrée mesure la quantité de données reçue par un algorithme ; pour les algorithmes sur les listes étudiés ici, c’est le nombre d’éléments, n.
Deux listes de même longueur ont la même taille d’entrée, même si l’une est triée et l’autre en ordre inverse.
Temps d’exécution de référence
Un temps d’exécution de référence est un temps mesuré pour une taille d’entrée connue, utilisé comme point de départ d’une estimation pour une autre taille.
Un temps de référence de 4 secondes pour 20 000 éléments peut servir à une estimation quadratique pour une exécution comparable plus grande.
Terme dominant
Un terme dominant est la partie d’une expression du nombre d’étapes qui croît le plus vite et détermine sa croissance à long terme lorsque la taille de l’entrée augmente.
Dans n2/2−n/2, le terme quadratique domine même si les deux termes influent sur le nombre exact de comparaisons.
Terminaison
La terminaison signifie que l’exécution finit par s’arrêter ; une mesure entière positive ou nulle qui diminue peut l’établir pour une boucle.
Exclure l’indice médian testé fait strictement diminuer le nombre de positions candidates de la recherche dichotomique après chaque absence de correspondance.
Test aléatoire
Le test aléatoire génère des entrées variées et vérifie les résultats par rapport à une spécification ou à une méthode fiable afin de chercher des échecs inattendus.
Comparer de nombreuses sorties de tri générées aléatoirement avec sorted peut révéler un cas manqué par des tests choisis à la main.
Test de non-régression
Un test de non-régression conserve une vérification d’un comportement auparavant correct ou corrigé afin que des modifications ultérieures révèlent le retour d’un échec.
Conserve une liste minimale qui a provoqué la perte d’un doublon pour vérifier que les modifications futures conservent tous les exemplaires.
Test par doublement
Un test par doublement compare les coûts pour des tailles d’entrée qui doublent successivement afin de rechercher les rapports associés aux familles de croissance.
Des rapports de temps répétés proches de quatre suggèrent une croissance quadratique sur l’intervalle de tailles mesuré.
Tri
Le tri réorganise les éléments selon l’ordre de leurs clés tout en conservant chaque élément initial et chaque occurrence répétée.
Un résultat croissant qui perd un doublon ne satisfait pas la correction du tri, même si tous les voisins sont dans l’ordre.
Tri en place
Un tri en place réorganise la liste existante en utilisant seulement une quantité fixe d’espace de travail supplémentaire lorsque la taille de l’entrée augmente.
Le tri à bulles nécessite quelques compteurs et un indicateur d’échange au lieu d’une autre liste proportionnelle à son entrée.
Tri fusion
Le tri fusion trie récursivement deux moitiés plus courtes et fusionne les résultats triés, ce qui donne une croissance du travail proportionnelle à nlog⁡n.
Une grande liste passe par plusieurs tailles de division avant que ses morceaux triés soient reconstruits en une seule sortie.
Tri par sélection
Le tri par sélection parcourt à répétition la partie non triée pour trouver son minimum et échange cet élément pour le placer à la position suivante d’un préfixe trié.
Un parcours du tri par sélection retient l’indice du plus petit élément avant d’effectuer son éventuel échange qui déplace des éléments.
Tri stable
Un tri stable conserve l’ordre relatif initial des enregistrements dont les clés sont égales lors de la comparaison, même lorsque d’autres enregistrements se déplacent.
Un tri stable par note conserve les noms classés alphabétiquement dans l’ordre alphabétique au sein de chaque groupe de même note.

V

Valeur recherchée
Une valeur recherchée est la valeur que l’on cherche, comparée aux éléments stockés ou à un champ choisi de chaque enregistrement stocké.
Dans une recherche de l’identifiant 630, la valeur recherchée est 630 ; la position renvoyée est un autre nombre.

À propos de cette unité

Par StudeliSignaler une erreur

Crée ton propre Matériel d'Étude

Transforme tes notes, diapos et documents en Guides d'Étude, Questions Pratiques, Flashcards et 6 autres outils.

Commencer