Algorithmes de tri, recherche et efficacité
DébutantUnité 4 sur 7 de la formation Formation : Informatique : données, algorithmes, Internet et IA
Ce que tu vas apprendre
- 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 quelconqueVé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éeUtilise 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.
- Effectue une recherche séquentielle dans une liste quelconque
- 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éeDé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érationsTrie 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érationsTrie 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.
- Décris les propriétés d’une liste correctement triée
- 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 seuleCombine 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 nTrie 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.
- Fusionne deux listes triées en une seule
- 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 algorithmeMesure 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éeReconnais 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écutionUtilise 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.
- Compte les étapes effectuées par un algorithme
- 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 limitesChoisis 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 situationCompare 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.
- Justifie la correction d’un algorithme
Algorithmes de tri : cours
1Effectue 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 :
- À l’indice 0, compare 7 à 3. Ils diffèrent, donc continue.
- À 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 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 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
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
-1qu’après avoir écarté toutes les correspondances possibles. - Une liste non vide nécessite une comparaison dans le meilleur cas et dans le pire.
- La moyenne 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érification | low | high | mid | Valeur médiane | Mise à jour |
|---|---|---|---|---|---|
| 1 | 0 | 10 | 5 | 31 | high devient 4 |
| 2 | 0 | 4 | 2 | 12 | low devient 3 |
| 3 | 3 | 4 | 3 | 17 | low devient 4 |
| 4 | 4 | 4 | 4 | 23 | high 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 . Le logarithme en base 2 décrit les divisions successives par deux : , 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
midavecmid + 1oumid - 1. - Le maximum est de vérifications d’éléments médians pour .
- 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.
2Trie 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 éléments distincts en ordre inverse en a , 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] :
- Compare 5 et 1 ; échange-les pour obtenir
[1, 5, 4, 2, 8]. - Compare 5 et 4 ; échange-les pour obtenir
[1, 4, 5, 2, 8]. - Compare 5 et 2 ; échange-les pour obtenir
[1, 4, 2, 5, 8]. - 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 comparaisons et zéro échange. Sur une liste d’éléments distincts en ordre inverse, elle effectue
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 comparaisons ; une entrée triée en nécessite .
- É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].
| Passage | Minimum restant | Liste après placement | Comparaisons | Échanges qui déplacent des éléments |
|---|---|---|---|---|
| 1 | 10 | [10, 29, 14, 37, 13] | 4 | 1 |
| 2 | 13 | [10, 13, 14, 37, 29] | 3 | 1 |
| 3 | 14 | [10, 13, 14, 37, 29] | 2 | 0 |
| 4 | 29 | [10, 13, 14, 29, 37] | 1 | 1 |
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 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 au total. Une entrée vide ne nécessite ni passage ni échange. Le tri à bulles peut nécessiter é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 .
- Pour une entrée non vide, il effectue au plus échanges qui déplacent des éléments et utilise un espace supplémentaire fixe.
- La version habituelle avec échange à distance est instable.
3Trie 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ête | Copie dans la sortie | Sortie obtenue |
|---|---|---|
| 3 et 9 | 3 | [3] |
| 27 et 9 | 9 | [3, 9] |
| 27 et 10 | 10 | [3, 9, 10] |
| 27 et 82 | 27 | [3, 9, 10, 27] |
| 38 et 82 | 38 | [3, 9, 10, 27, 38] |
| 43 et 82 | 43 | [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 et , il faut au plus 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ê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 é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 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 :
- Fusionne les éléments isolés en
[27, 38],[3, 43],[9, 82]et[10, 15]. Chaque fusion utilise une comparaison : quatre au total. - Fusionne les paires en
[3, 27, 38, 43]et[9, 10, 15, 82]. Chaque fusion utilise trois comparaisons : six au total. - Fusionne ces moitiés en
[3, 9, 10, 15, 27, 38, 43, 82]. Cette fusion utilise sept comparaisons.
Le tri complet utilise 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 . En général, il y a environ niveaux de fusion. Sur un niveau complet, les fusions traitent collectivement les éléments. Chaque niveau effectue donc un travail proportionnel à , ce qui conduit à une croissance en .
Pour huit éléments, 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 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 à . 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 niveaux effectuent chacun un travail proportionnel à .
- Le nombre exact de comparaisons dépend de l’ordre ; la famille de croissance est .
- 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.
4Compte 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 , 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éthode | Unité de comptage | Nombre dans le pire cas |
|---|---|---|
| Recherche séquentielle | Comparaisons entre élément et valeur recherchée | |
| Recherche dichotomique, entrée non vide | Vérifications d’éléments médians | |
| Tri à bulles | Comparaisons de voisins | |
| Tri par sélection | Comparaisons de clés | |
| Tri fusion | Comparaisons d’éléments de tête | Au plus environ |
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 . 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 si elle est en dernière position ou absente. Sa moyenne pour une recherche fructueuse est 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 comparaisons. Deux boucles complètes imbriquées, chacune exécutée fois, exécutent leur corps commun 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 éléments suivants. La suivante le compare à éléments, et la dernière à aucun. Le total est
Écris la somme dans les deux sens. Chaque paire de termes alignés donne , et il y a paires de ce type. Leur total est , soit deux fois la somme initiale. Pour cinq éléments, ; 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 répétitions. Un million atteint pour la première fois 1 ou moins après 20 divisions par deux : est inférieur à un million et 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 . Pour , 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 exécutions du corps.
- Comparer chaque paire distincte une fois donne 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 croissance | Exemple | Effet du doublement de la taille de l’entrée |
|---|---|---|
| Constante, | Lire une position connue d’un tableau | Même travail |
| Logarithmique, | Recherche dichotomique | Environ une vérification supplémentaire |
| Linéaire, | Parcours complet | Deux fois plus de travail |
| Tri fusion | Un peu plus du double | |
| Quadratique, | Tri par sélection | Environ quatre fois plus |
| Exponentielle, | Essayer 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 : . 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, vaut environ 3,3 ; 6,6 ; 10 et 20. Les valeurs correspondantes de 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, 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. et vaut environ un million. À raison d’un milliard d’étapes par seconde, é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 , , , , et . Ici, ces notations indiquent la famille de croissance habituelle dans le pire cas. Lis comme « de l’ordre de n au carré ». La notation omet les facteurs constants et les termes de moindre ordre : 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 étapes et la méthode B, . 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 . 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 é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
secondes. Passer à 500 000 éléments multiplie la taille de l’entrée par 10 : le temps estimé est donc de secondes. Multiplier le temps par 10 reviendrait à traiter l’algorithme à tort comme linéaire.
Pour une croissance en , 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 ; 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.
5Justifie 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.
- Départ : avant le passage 0, le préfixe est vide. Il satisfait déjà la propriété.
- 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.
- Fin : après au plus 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 passages, les dernières positions contiennent les 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 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éthode | Temps ou profil des étapes | Espace supplémentaire | Stable ? |
|---|---|---|---|
| Recherche séquentielle | Jusqu’à comparaisons | Fixe | Pas une propriété de tri |
| Recherche dichotomique | Jusqu’à vérifications médianes | Fixe | Pas une propriété de tri |
| Tri à bulles avec arrêt anticipé | comparaisons si l’entrée est triée ; pire cas quadratique | Fixe | Oui, avec des échanges stricts |
| Tri par sélection | comparaisons ; au plus échanges qui déplacent des éléments | Fixe | Non, dans la forme habituelle avec échanges |
| Tri fusion | Croissance des comparaisons en | Proportionnel à | Oui, 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
1Trouve une valeur sans perdre le fil des positions
13 étapes
- 1IntroductionTrouve 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
-1lorsque la valeur recherchée est absente. - 2ExplicationÉ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.
- 3ExempleTrouve 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.
- 4Dé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.
- 5Point cléLaisse la valeur recherchée déterminer le moment de l’arrêt
Pour une liste non vide de éléments, la recherche séquentielle utilise une comparaison dans le meilleur cas et 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 . Compter toutes les occurrences change la tâche : même une correspondance précoce ne peut pas mettre fin à ce parcours complet.
- 6AnalogieUtilise 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.
- 7ExplicationGarde les deux bornes dans l’intervalle
Commence avec
low = 0ethigh = n - 1. Tant quelow <= high, calculemid = (low + high) // 2.Renvoie
midsi l’élément correspondant est égal à la valeur recherchée. Si sa valeur est trop petite, fixelow = mid + 1; si elle est trop grande, fixehigh = 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. - 8ExempleVé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. - 9ExempleObserve 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. - 10Dé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 = 3tandis quehighreste à 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. - 11ConseilVérifie le dernier candidat et exclus ceux déjà testés
low <= highpermet de vérifier un intervalle à une position. Une condition stricte<manque[5]lors de la recherche de 5.Utilise
mid + 1etmid - 1après une absence de correspondance. Aveclow = 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. - 12Dé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.
- 13Ré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 vérifications médianes pour une entrée non vide, mais chaque vérification peut contenir plusieurs comparaisons dans le code.
2Construis l’ordre par des échanges voisins et à distance
16 étapes
Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.
- 1IntroductionPrécise la tâche de tri
- 2ExplicationConserve les éléments ainsi que leur ordre
- 3ExempleObserve ce que la stabilité conserve
- 4DéfiVérifie les deux conditions du tri
- 5ExplicationTransporte un grand élément vers la droite
- 6ExempleSuis trois échanges successifs
- 7ExempleCompte le passage de confirmation
- 8DéfiCompare les échanges aux comparaisons
- 9Point cléCompte les inversions pour compter les échanges
- 10ExplicationSélectionne un minimum avant de le déplacer
- 11ExemplePlace les deux premiers minima
- 12ExempleTermine sans échanger une valeur avec elle-même
- 13DéfiTrouve un minimum après le préfixe
- 14Point cléUn échange à distance peut dépasser une clé égale
- 15DéfiChoisis une méthode lorsque les déplacements coûtent cher
- 16RécapitulatifSuis la partie que chaque méthode place définitivement
3Divise une liste et reconstruis-la par fusions
13 étapes
Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.
- 1IntroductionUtilise l’ordre déjà construit dans les petits morceaux
- 2ExplicationCompare uniquement les éléments de tête inutilisés
- 3ExempleFusionne les premières valeurs
- 4ExempleCopie la queue après la fin des comparaisons
- 5DéfiTermine une fusion et compte ses comparaisons
- 6ExplicationRends chaque problème récursif plus petit
- 7ExempleDivise huit éléments en éléments isolés
- 8ExempleReconstruis les paires et les moitiés
- 9ExempleCompte chaque niveau de fusion
- 10DéfiInclus le travail effectué dans les moitiés
- 11LienPréserve l’ordre des clés égales pendant la reconstruction
- 12DéfiApplique la méthode à un grand tri stable
- 13RécapitulatifCompte les éléments à travers les niveaux
4Transforme un travail répété en estimation de temps
14 étapes
Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.
- 1IntroductionDemande-toi combien de travail nécessite la taille suivante
- 2ExplicationChoisis ce qui compte comme une étape
- 3ExempleNe compte chaque paire qu’une fois
- 4DéfiLis les bornes avant de nommer la croissance
- 5Point cléAssocie le cas au nombre d’étapes
- 6ExplicationEssaie le test par doublement
- 7ExempleDistingue une notation de croissance d’un nombre exact
- 8DéfiTrouve un point de croisement à partir de modèles exacts
- 9LienObserve la limite d’un matériel plus rapide
- 10ExempleExtrapole un temps quadratique mesuré
- 11DéfiRetrouve une taille d’entrée à partir d’un budget de temps
- 12ConseilMesure plusieurs fois des cas comparables
- 13DéfiUtilise les rapports observés pour une prévision
- 14RécapitulatifApplique le modèle de comptage à l’estimation
5Montre qu’un algorithme fonctionne et convient à la tâche
15 étapes
Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.
- 1IntroductionCherche une garantie et une méthode adaptée
- 2ExplicationÉnonce les garanties avant de les démontrer
- 3ExempleÉtends l’invariant du tri par sélection
- 4ExempleConserve une correspondance possible et réduis son intervalle
- 5DéfiDistingue la conservation de la terminaison
- 6ExplicationPrévois les résultats aux limites avant l’exécution
- 7ExempleUtilise un intervalle à deux éléments pour révéler une boucle
- 8DéfiTrouve la borne de la boucle sur les voisins
- 9ConseilConserve un test minimal qui échoue
- 10ExplicationInclus le coût de préparation
- 11ExempleRéutilise la liste triée pour plusieurs requêtes
- 12DéfiCalcule si la préparation est rentable
- 13LienChoisis selon les propriétés et la croissance du temps
- 14DéfiRelie la correction à une exigence pratique
- 15RécapitulatifUtilise ensemble les arguments, les tests et les coûts
Algorithmes de tri : QCM
Série 1 : Trouve des valeurs et suis les algorithmes10 Questions Pratiques
Question 1 sur 10
[12, 7, 18, 7]. Quel indice renvoie-t-elle ?Afficher la réponseMasquer la réponse
Question 2 sur 10
[4, 9, 15, 22, 30, 41, 57]. Quels indices vérifie-t-elle pour chercher 41 ?Afficher la réponseMasquer la réponse
Question 3 sur 10
[6, 2, 6, 1]. Quelle sortie satisfait la spécification d’un tri croissant ?Afficher la réponseMasquer la réponse
[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
[8, 3, 6, 2] ?Afficher la réponseMasquer la réponse
[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
[2, 11] avec [5, 14, 19]. Après la copie de 11, quels éléments restent à copier ?Afficher la réponseMasquer la réponse
Question 6 sur 10
[16]. Que doit-il renvoyer ?Afficher la réponseMasquer la réponse
[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
Afficher la réponseMasquer la réponse
Question 8 sur 10
Afficher la réponseMasquer la réponse
Question 9 sur 10
Afficher la réponseMasquer la réponse
Question 10 sur 10
while low < high. Quel est le plus petit test non vide qui révèle qu’une valeur présente est manquée ?Afficher la réponseMasquer la réponse
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
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 2 sur 10
[6, 12, 18, 25, 33, 46], quelles sont les bornes juste après la première vérification pour la valeur recherchée 30 ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 3 sur 10
[1, 3, 2, 4]. Combien de comparaisons effectue-t-il avant de s’arrêter ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 4 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 5 sur 10
[1, 8, 13] et [4, 9] ne compte que les comparaisons entre éléments de tête. Combien en effectue-t-elle ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 6 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 7 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 8 sur 10
[4, 4, -2] et renvoie [-2, 4]. Quelle exigence a-t-il violée ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 9 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 10 sur 10
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
[5, 11, 16, 24, 38, 47, 59, 70]. Quels indices sont vérifiés pour la valeur absente 41 ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 2 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 3 sur 10
[18, 7, 12, 4, 9] ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 4 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 5 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 6 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 7 sur 10
low = mid. Quelle partie d’un argument complet de correction peut échouer ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 8 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 9 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 10 sur 10
[2A, 6B] et ceux de droite [2C, 5D], en comparant seulement les clés numériques. Quel est l’ordre des enregistrements fusionnés ?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
[14, 6, 21, 6]. Si elle s’arrête immédiatement à la première correspondance, quelle paire valeur recherchée-résultat est possible ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 2 sur 10
low = 6, high = 6, et l’élément restant est égal à la valeur recherchée. Que fait la boucle correcte ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 3 sur 10
[5, 3, 5, 2, 4, 1] ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 4 sur 10
< 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 ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 5 sur 10
[9, 1, 7, 3]. En ne comptant que les comparaisons d’éléments dans les fusions, combien le tri complet en effectue-t-il ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 6 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 7 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 8 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 9 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 10 sur 10
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
A
Accès direct
Arrêt anticipé
B
Budget de temps
C
Cas de base
Cas limite
Cas moyen
Cas récursif
Clé de tri
Complexité constante
Compromis
Contre-exemple
Coût de préparation
Croissance exponentielle
Croissance linéaire
Croissance logarithmique
Croissance quadratique
Curseur
D
Dépassement de capacité entière
Diviser pour régner
É
Échange
[2, 9] en [9, 9] au lieu d’échanger les éléments.Élément de tête
Éléments adjacents
items[j] à items[j + 1] : ses déplacements dépendent donc de paires voisines.E
Erreur de décalage d’une unité
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
sorted de Python crée une nouvelle liste de résultats, tandis que list.sort() réorganise la liste existante.Fusion
[3, 10] et [6, 12] produit [3, 6, 10, 12] sans retrier aucune des entrées.I
Indice
[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
(2 + 7) // 2 choisit l’indice 4 comme indice médian suivant.Intervalle de recherche
Invariant de boucle
Inversion
[8, 3, 6], 8 forme une inversion avec chacune des deux valeurs suivantes, même si une seule paire est adjacente.M
Meilleur cas
O
Opération élémentaire
Ordre de croissance
P
Parcours complet
Passage
Permutation
[2, 8, 2] et [2, 2, 8] sont des permutations l’une de l’autre ; [2, 8] perd une occurrence.Pire cas
Point de croisement
Postcondition
Précondition
Préfixe trié
Prévision du temps d’exécution
Q
Queue de liste
[14, 20] reste de l’autre côté, les deux éléments de la queue sont encore nécessaires.R
Recherche
Recherche dichotomique
Recherche séquentielle
Récursivité
S
Spécification
Suffixe non trié
T
Taille de l’entrée
Temps d’exécution de référence
Terme dominant
Terminaison
Test aléatoire
sorted peut révéler un cas manqué par des tests choisis à la main.Test de non-régression
Test par doublement
Tri
Tri en place
Tri fusion
Tri par sélection
Tri stable
V
Valeur recherchée
À propos de cette unité
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.