Adloun

Probleme – La dichotomie, jusqu'au nombre exact de tours

Exercice · niveau 3 (difficile) · informatique (MP2I/MPI), chapitre 3 — Algorithmes, programmes et complexité

Énoncé

Corrigé

1. Le code.


/* Renvoie un indice i tel que t[i] == v, ou -1 si v ne figure pas dans
   t[0..n-1].
   Precondition  : n >= 0 et t[0..n-1] est croissant (au sens large).
   Postcondition : soit le resultat vaut -1 et v est absent de t[0..n-1],
                   soit 0 <= resultat < n et t[resultat] == v. */
int cherche(const int t[], int n, int v) {
    assert(n >= 0);
    int g = 0, d = n - 1;
    /* INVARIANT : si v figure dans t[0..n-1], alors il figure dans
       t[g..d].            VARIANT : d - g + 1. */
    while (g <= d) {
        int m = g + (d - g) / 2;
        if (t[m] == v) { return m; }
        if (t[m] < v) { g = m + 1; } else { d = m - 1; }
    }
    return -1;
}

2. Les preuves.

Terminaison. Variant , le nombre de cases encore candidates. Il est entier, et positif tant que . À chaque tour où l'on ne retourne pas, ou bien passe à , ou bien passe à : dans les deux cas décroît d'au moins . La boucle s'arrête.

Correction. Initialisation : , , donc est tout le tableau : l'invariant est trivialement vrai. Conservation : supposons-le vrai et . Si , alors par croissance pour tout : ne peut figurer dans , donc s'il figure quelque part dans c'est dans — ce qui est exactement le nouvel intervalle. Le cas est symétrique. Utilisation : deux sorties possibles. Ou bien on retourne avec , et la postcondition est vérifiée. Ou bien on sort par : l'intervalle est vide, et l'invariant dit alors que ne figure nulle part — on rend .

3. Le nombre exact de tours. Notons la valeur du variant après tours, avec . Le tour retire la case et garde l'un des deux côtés, dont la taille est au plus . Donc , et la boucle s'arrête dès que , c'est-à-dire au plus tard pour , soit .

Cette borne est atteinte : en cherchant une valeur absente, on ne retourne jamais par le return m, et le pire cas est réalisé. Vérification, en essayant toutes les valeurs présentes et absentes pour chaque :


   n |    1 |    2 |    3 |    4 |    7 |    8 |   15 |   16 |  100 | 1000 | 10^6
tours|    1 |    2 |    2 |    3 |    3 |    4 |    4 |    5 |    7 |   10 |   20
log2 |    1 |    2 |    2 |    3 |    3 |    4 |    4 |    5 |    7 |   10 |   20

Le maximum mesuré vaut pour les onze tailles. Noter le saut à chaque puissance de deux : de à , un tour de plus ; de à , aucun. Un million de cases se fouillent en vingt comparaisons.

4. La première occurrence. La postcondition dit « un indice tel que », pas « le plus petit ». Sur et , le premier milieu est et la fonction rend : ni la première occurrence, ni la dernière.

Ce n'est pas un défaut, c'est la spécification. La corriger a un coût qu'il faut connaître : pour obtenir la première occurrence, on ne s'arrête pas sur l'égalité, on continue de chercher à gauche.


/* Renvoie le plus petit i tel que t[i] >= v, ou n si v majore t.
   Precondition : t[0..n-1] croissant. */
int borne_inferieure(const int t[], int n, int v) {
    int g = 0, d = n;                   /* d est EXCLU : l'invariant change */
    /* INVARIANT : tous les t[k] pour k < g sont < v, et tous les t[k]
       pour k >= d sont >= v. */
    while (g < d) {
        int m = g + (d - g) / 2;
        if (t[m] < v) { g = m + 1; } else { d = m; }
    }
    return g;
}

Elle n'a aucune sortie anticipée : le nombre de tours ne dépend pas de la valeur cherchée, seulement du chemin suivi, et il vaut au plus . Mesuré sur toutes les valeurs, présentes et absentes : entre et tours pour , et borne_inferieure rend bien sur , là où cherche rendait .

Le changement de convention sur — exclu au lieu d'inclus — est ce qui rend l'invariant énonçable : avec inclus, il faudrait parler de , indice qui peut valoir . Un intervalle mal choisi rend une preuve pénible ; c'est souvent le signe qu'il faut changer de convention, pas de code.

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.