Un tas maximum sans réécrire une ligne
Exercice · niveau 2 · informatique (MP2I/MPI), chapitre 11 — Arbres de recherche, tas et files de priorité
Énoncé
On dispose d'un tas minimum sur des int et l'on veut une file de priorité qui serve le plus grand d'abord. Un étudiant propose d'insérer au lieu de , et de rendre l'opposé du minimum extrait. Le procédé est-il correct ? Y a-t-il un cas où il échoue ?
Corrigé
Le procédé est correct presque toujours, et son unique défaut est instructif.
Pourquoi il marche. renverse l'ordre : . Le minimum des est donc l'opposé du maximum des , et l'invariant de tas minimum sur les opposés est exactement l'invariant de tas maximum sur les valeurs. Aucune ligne du code n'est à changer.
Où il échoue. Sur un type entier signé, l'intervalle n'est pas symétrique : mesuré, INT_MIN vaut et INT_MAX vaut . L'opposé de INT_MIN n'est pas représentable : c'est un dépassement signé, donc un comportement indéfini. Mesuré sur cette machine, -INT_MIN rend INT_MIN lui-même ; sur int8_t, -(-128) rend . Insérer INT_MIN dans le tas négatif y insérerait donc INT_MIN, la plus petite valeur au lieu de la plus grande : elle sortirait en premier au lieu de sortir en dernier.
Trois parades, par ordre de préférence.
- Paramétrer la comparaison plutôt que les valeurs : écrire le tas avec une fonction
comparepassée à la création. C'est la bonne réponse — elle ne touche pas aux données. - Interdire
INT_MINpar une précondition :assert(x > INT_MIN);. Honnête, mais on a restreint le contrat. - Renverser en écrivant
INT_MAX - x: correct pour , et faux dès que est négatif. À ne pas faire.
C'est le dépassement d'entier silencieux du chapitre chap:langage-c, reparu là où on ne le cherchait plus : une transformation qui préserve l'ordre mathématique ne préserve pas forcément l'ordre machine.
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.