Adloun

Écrire une variante qui, lorsque v est absente, renvoie l'indice où il…

Exercice de TD · niveau 3 (difficile) · NSI (première), chapitre 8 — Dichotomie, voisins et gloutons · La recherche dichotomique

Énoncé

Écrire une variante qui, lorsque est absente, renvoie l'indice où il faudrait l'insérer pour conserver le tri. Quelle postcondition écrire ? La vérifier sur trois mille tableaux aléatoires.

Corrigé


def rang_insertion(t, v):
    """Indice ou inserer v dans le tableau trie t pour le garder trie.

    Postcondition : t[:r] + [v] + t[r:] est trie, et r est le PREMIER
                    indice tel que t[r] >= v.
    """
    gauche, droite = 0, len(t)
    while gauche < droite:
        milieu = (gauche + droite) // 2
        if t[milieu] < v:
            gauche = milieu + 1
        else:
            droite = milieu
    return gauche

Trois différences avec la version du cours, et chacune compte. D'abord droite = len(t) et non len(t) - 1 : il faut pouvoir renvoyer l'indice , c'est-à-dire « après le dernier ». Ensuite while gauche &lt; droite et non &lt;= : l'intervalle est maintenant semi-ouvert, et la boucle s'arrête quand il est réduit à un point — qui est la réponse. Enfin droite = milieu et non milieu - 1 : le milieu peut lui-même être la bonne position, on n'a pas le droit de l'écarter.

Le variant reste le même — la largeur — et il décroît toujours strictement : si t[milieu] &lt; v, gauche passe au-delà de milieu ; sinon droite descend à milieu, ce qui est bien une diminution stricte puisque par construction de la division entière. C'est précisément ce dernier point qui interdit d'écrire gauche = milieu dans l'autre branche : la boucle ne terminerait plus.

Vérification.


t = [1, 3, 5, 7, 9]
assert rang_insertion(t, 4) == 2
assert rang_insertion(t, 0) == 0
assert rang_insertion(t, 10) == 5      # apres le dernier
assert rang_insertion(t, 5) == 2       # AVANT l'occurrence existante
assert rang_insertion([], 1) == 0

for _ in range(3000):
    t = sorted(random.randint(0, 20) for _ in range(random.randint(0, 12)))
    v = random.randint(-2, 22)
    r = rang_insertion(t, v)
    nouveau = t[:r] + [v] + t[r:]
    assert nouveau == sorted(nouveau)
    assert all(x < v for x in t[:r]) and all(x >= v for x in t[r:])

Le test aléatoire vérifie la postcondition telle qu'elle est écrite, en deux morceaux : le tableau reconstruit est trié, et la coupure est bien au premier élément . Les tirages comportent des doublons — c'est voulu, car c'est le cas qui distingue « le premier indice » de « un indice quelconque ».

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.