Probleme – Le tri par sélection, prouvé et compté
Exercice · niveau 3 (difficile) · informatique (MP2I/MPI), chapitre 3 — Algorithmes, programmes et complexité
Énoncé
- Écrire le tri par sélection, avec ses deux invariants.
- Prouver la terminaison, puis la correction.
- Compter exactement les comparaisons et les échanges. Que valent-ils dans le meilleur cas, le pire cas, le cas moyen ?
- Le tri par sélection et le tri par insertion sont tous deux . Lequel choisir, et quand ?
Corrigé
1. Le code, annoté.
/* Trie les n premiers termes de t par ordre croissant, en place.
Precondition : n >= 0, et t a au moins n cases.
Postcondition : t[0..n-1] est croissant et contient exactement les
memes valeurs qu'a l'appel (c'est une PERMUTATION). */
void tri_selection(int t[], int n) {
assert(n >= 0);
for (int i = 0; i < n - 1; i = i + 1) {
/* INVARIANT EXTERIEUR : t[0..i-1] est trie, et tous ses termes
sont <= a tous ceux de t[i..n-1]. */
int mini = i;
for (int j = i + 1; j < n; j = j + 1) {
/* INVARIANT INTERIEUR : t[mini] est le plus petit de t[i..j-1]. */
if (t[j] < t[mini]) { mini = j; }
}
int tmp = t[i]; t[i] = t[mini]; t[mini] = tmp;
}
}
2. Les preuves.
Terminaison. Variant de la boucle intérieure : , entier positif décroissant de par tour. Variant de la boucle extérieure : , de même. Les deux boucles sont bornées, donc l'algorithme s'arrête après au plus tours intérieurs.
Correction de la boucle intérieure. Initialisation : et , donc est bien le minimum de la tranche . Conservation : le corps remplace mini par exactement quand est plus petit, donc reste le minimum de . Utilisation : à la sortie , donc .
Correction de la boucle extérieure. Initialisation : , la partie triée est vide, l'invariant est vrai par vacuité. Conservation : par ce qui précède, est le minimum de la partie non triée ; l'échange le place en position . La partie reste triée — le nouveau terme est à tous les précédents par l'invariant, et à tous les suivants puisque c'est leur minimum. Utilisation : à la sortie , donc est trié et tous ses termes minorent : le tableau entier est trié.
Et la permutation ? L'échange est la seule opération qui modifie , et un échange préserve le multiensemble des valeurs. C'est la moitié de la postcondition qu'on oublie systématiquement d'énoncer — le problème 4.2 montre ce qu'elle coûte quand on l'omet.
3. Le comptage exact. La boucle intérieure fait comparaisons au tour , quelles que soient les valeurs : il n'y a aucune sortie anticipée. Le total est
et il y a exactement échanges. Mesuré sur trois familles d'entrées :
n | croissant | decroissant | aleatoire | n(n-1)/2 | echanges | n-1
5 | 10 | 10 | 10 | 10 | 4 | 4
10 | 45 | 45 | 45 | 45 | 9 | 9
50 | 1225 | 1225 | 1225 | 1225 | 49 | 49
100 | 4950 | 4950 | 4950 | 4950 | 99 | 99
500 | 124750 | 124750 | 124750 | 124750 | 499 | 499
Les trois colonnes sont identiques : meilleur cas, pire cas et cas moyen coïncident. Le tri par sélection est toujours, ce qui est rare et mérite d'être remarqué — l'analyse en cas moyen n'a ici rien à dire.
4. Sélection ou insertion.
| Sélection | Insertion | |
|---|---|---|
| Comparaisons, pire cas | ||
| Comparaisons, meilleur cas | ||
| Écritures dans le tableau | jusqu'à |
Le tri par insertion est adaptatif : sur une entrée presque triée, il coûte — mesuré au problème 2.3. Le tri par sélection ne l'est jamais.
En revanche, le tri par sélection fait écritures, contre pour l'insertion. Si écrire coûte cher — mémoire flash, où chaque écriture use le support, ou éléments volumineux qu'on déplace bloc par bloc — c'est lui qui gagne. Le choix ne se lit pas dans le commun : il faut savoir quelle opération on compte.
Les autres exercices de ce chapitre Le cours du chapitre
Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.