Adloun

Probleme – Le tri par insertion, prouvé entièrement par induction structurelle

Exercice · niveau 3 (difficile) · informatique (MP2I/MPI), chapitre 9 — Ordres bien fondés et induction structurelle

Énoncé

Corrigé

1. Les deux fonctions.


(* Insere x dans l. Precondition : l est triee par ordre croissant.
   Postcondition : le resultat est trie et est une permutation de x :: l. *)
let rec insere x = function
  | [] -> [x]
  | y :: r -> if x <= y then x :: y :: r else y :: insere x r

(* Renvoie une permutation triee de l. Precondition : aucune. *)
let rec tri = function
  | [] -> []
  | x :: r -> insere x (tri r)

Les prédicats de la spécification s'écrivent eux aussi par induction, et c'est ce qui rend les preuves mécaniques :


let rec trie = function
  | [] | [_] -> true
  | x :: (y :: _ as r) -> x <= y && trie r

2. Les deux propriétés de insere, par induction structurelle sur .

Terminaison. L'appel récursif porte sur , argument du constructeur :: : l'ordre induit décroît, il est bien fondé, la fonction termine. Aucun entier n'a été invoqué — c'est tout l'apport du chapitre.

(a) Le résultat est trié. Cas : est triée. Cas , avec triée — donc triée et minorant de .

(b) C'est une permutation de . Cas : immédiat. Cas : ou bien le résultat est , ou bien , qui contient et — par hypothèse d'induction — les éléments de . Les multiplicités sont préservées dans les deux branches.

3. Correction de tri, par induction structurelle sur .

Cas : la liste vide est triée et est sa propre permutation.

Cas : par hypothèse d'induction, est triée et permute . Par la propriété (a), est triée ; par (b), elle permute , qui permute . La composition de deux permutations en est une.

Deux cas de preuve, deux motifs de filtrage : la démonstration a exactement la forme du code. C'est ce que le cours annonçait, et c'est ici littéral.

Vérification mesurée : sur listes tirées au hasard, de longueur jusqu'à et à valeurs dans — donc avec des doublons, le cas où un tri fautif se trahit — le résultat est trié et permutation de l'entrée à chaque fois.

4. Le nombre de comparaisons, compté.

liste déjà triéeliste à l'envers

Le meilleur cas est , le pire est , et les mesures collent exactement.

Pourquoi, et attention au sens. tri trie d'abord la queue, puis insère la tête. Sur une liste croissante, chaque élément inséré est plus petit que tout ce qui a déjà été trié : il s'arrête à la première comparaison, d'où au total. Sur une liste décroissante, chaque élément est plus grand que tous les autres et traverse toute la liste triée : .

Le fait à retenir, contre-intuitif : c'est la liste déjà triée qui est le meilleur cas, et la liste à l'envers le pire — l'inverse de ce que produirait la version qui insère dans le résultat construit de gauche à droite. Le coût dépend de l'écriture, pas seulement de l'algorithme, et il se mesure.

Complexité en mémoire. La récursion n'est pas terminale : la pile atteint la profondeur . Sur une liste de éléments, cela dépasse la limite mesurée au chapitre chap:memoire. Le tri par insertion sur listes est donc un excellent objet de preuve et un mauvais outil de production — le chapitre chap:diviser en donnera un qui est les deux.

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.