informatique (MP2I/MPI) · Chapitre 23 · Exercice de TD
La faute qui sépare au lieu d'unir
Unir & trouver, arbres couvrants · niveau 2
Énoncé
Un étudiant écrit l'union de la seconde naïve ainsi :
let unir p x y = p.(x) <- y (* FAUX *)
au lieu de p.(trouver p x) <- trouver p y. Construire la plus petite suite d'opérations qui montre que c'est faux, et dire ce qui se casse exactement.
Corrigé
Trois unions suffisent, sur quatre éléments. Partons de p = [| 0; 1; 2; 3 |].
unir 0 1 --> p = [| 1; 1; 2; 3 |] (* correct par hasard : 0 est une racine *)
unir 2 3 --> p = [| 1; 1; 3; 3 |] (* correct par hasard *)
unir 0 2 --> p = [| 2; 1; 3; 3 |] (* la faute *)
La troisième ligne écrase p[0], qui pointait vers . Résultat mesuré : trouver 0 rend et trouver 1 rend . L'élément a été expulsé de sa classe — l'opération a séparé là où on lui demandait d'unir.
Pourquoi la faute ne se voit pas tout de suite. Les deux premières unions donnent le bon résultat, parce que et étaient encore leurs propres racines. La faute ne se manifeste qu'à partir du moment où l'on unit un élément qui n'est plus une racine — c'est-à-dire, sur un jeu de tests trop petit, jamais.
La leçon de spécification. Le contrat de unir porte sur des classes, pas sur des éléments. Un code qui écrit dans p[x] parle d'un élément ; il faut donc, avant toute écriture, remonter aux deux racines. C'est exactement la discipline du chapitre chap:discipline : le jeu de tests doit contenir un cas où l'argument n'est pas une racine.
Exercices semblables
- Ce que la structure refuse de faire corrigé
- Les deux naïves, chiffrées corrigé
- La borne est atteinte corrigé
- Le rang ment, et c'est voulu corrigé
- Combien d'arbres couvrants minimaux ? corrigé