Adloun

Recherche dichotomique récursive, prouvée

Exercice · niveau 2 · informatique (MP2I/MPI), chapitre 5 — Récursivité

Énoncé

Écrire une recherche dichotomique récursive dans un tableau trié, avec spécification, terminaison, correction et complexité.

Corrigé


(* cherche t x renvoie un indice i tel que t.(i) = x, ou -1 si x est absent.
   Precondition : t est trie par ordre croissant.
   La fonction auxiliaire travaille sur la tranche t.(g .. d-1). *)
let cherche t x =
  let rec aux g d =
    if g >= d then -1
    else
      let m = g + (d - g) / 2 in
      if t.(m) = x then m
      else if t.(m) < x then aux (m + 1) d
      else aux g m
  in aux 0 (Array.length t)

Terminaison. Variant : , entier positif (l'appel n'a lieu que si ). Comme , la tranche a pour largeur , et la tranche a pour largeur . Le variant décroît strictement, et il est minoré par : la récursion s'arrête.

Correction. Invariant, au sens de la récurrence sur le variant : si figure dans , alors il figure dans la tranche . Il tient à l'appel initial (la tranche est le tableau entier). Il se conserve : le tableau étant trié, si tout indice porte une valeur , donc ne peut être qu'à droite ; symétriquement à gauche. À l'arrêt, ou bien on a trouvé en , ou bien la tranche est vide et l'invariant dit alors que n'est nulle part.

Complexité. La largeur est au moins divisée par deux à chaque appel : , deuxième récurrence du cours avec , donc comparaisons. Mesuré : le nombre maximal d'appels vaut exactement .


n :                     1    7   15   1000   1000000
appels au pire :        2    4    5     11        21
floor(log2 n) + 2 :     2    4    5     11        21

En espace, la profondeur de pile est — soit blocs pour un million d'éléments. C'est l'exemple annoncé par la mise en garde du cours : une récursion sur éléments un par un coûte en pile, la même en dichotomie coûte .

Deux fautes classiques que la preuve écarte. Écrire aux m d au lieu de aux (m+1) d : le variant ne décroît plus quand , et la fonction boucle. Écrire (g + d) / 2 : correct en OCaml, où les entiers font bits, mais générateur de dépassement en C sur de grands indices — on y écrit g + (d - g) / 2, comme au chapitre chap:langage-c.

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.