Dichotomie

publicité
Dichotomie
9 mars 2007
static int dicho(int[] t, int i)
int bas=0, haut=t.length-1;
while (bas <= haut) {
int centre = (haut+bas)/2;
if (i==t[centre])
return centre;
//(1)
if (i < t[centre])
haut=centre-1;
else
bas=centre+1;
}
return -1;
}
De façon générale, il faut être très attentif sur ce qui se passe lorsque l’intervalle devient très
petit.
Terminaison : si on note l=haut − bas, l décroit au moins de 1 à chaque passage dans la boucle
où i! = t[centre] (en général il est même plus que divisé par 2, mais attention à ce qui peut se
passer pour les petites valeurs. . .).
Nécessairement, si on n’a jamais i == t[centre], l va donc finir par vérifier l < 0, ce qui est la
condition d’arrêt.
Invariant de boucle : «si i est dans le tableau, il est à un indice compris entre bas et haut». En
effet, cette propriété est vraie avant la boucle. Si elle est vraie au début de la boucle (i est dans
[bas, haut]), et si on a par exemple i < t[centre] (strictement !), nécessairement, si i est dans
le tableau, il est dans [bas, centre − 1] par monotonie du tableau (le seul cas problématique est
celui où t[centre − 1] < i < t[centre]. Dans ce cas, i n’apparait pas dans le tableau, et notre
propriété reste vraie).
On peut donc maintenant prouver simplement l’algorithme : on voit déjà que s’il retourne, il
retourne une valeur correcte. Reste à voir qu’il ne rate pas i. Si i est dans le tableau, on a à
tout moment que i apparaît entre bas et haut. On commence par regarder ce qu’il se passe
lorsque l == 0 ou l == 1. Une petite étude de cas permet de voir que l’on trouve bien i dans
ces cas là. Dans le cas général, on remarque juste que si l’algorithme de retourne pas, il passe
1
forcément par les cas l == 0 ou l == 1 (là aussi, une petite étude de cas est nécessaire :
regarder ce qui se passe pour l == 2, l == 3, l == 4 et l > 4), ce qui permet de conclure.
On a ainsi : «la boucle retourne via (1) si et seulement si i est dans le tableau, et la valeur
retournée est correcte». On en déduit «l’algorithme retourne -1 si et seulement si i n’est pas
dans le tableau», et le comportement de l’algorithme est entièrement prouvé.
Complexité : notons n la longueur du tableau passé en argument.On a vu que l’on passait nécessairement à l == 0 ou l == 1. Une fois que l’on est à l == 0 ou l == 1, l’algorithme
termine en un temps constant (< t0 , indépendant de n). la question est de savoir au bout de
combien de temps on arrive à 0 ou 1. Au début, on a l0 = n, puis trivialement li+1 ≤ li /2
pour li ! = 0 ou 1. Notons k = ceil(log(n)) où ceil désigne la partie entière +1. On a alors
2k ≥ n, soit n/2k ≤ 1. Donc au plus au bout k itérations, on aura l ≤ 1 (et l’algorithme finit
alors en temps constant). La complexité est donc inférieure à O(log(n)). Resterait à montrer
qu’il y a des cas où cette borne est atteinte pour voir que la complexité au pire est exactement
O(log(n)) (ce qui est le cas).
2
Téléchargement