Le principe de dichotomie
Le principe de dichotomie est au programme de l'ISN.
Le principe est le suivant :
- On recherche une valeur x dans une liste L triée (dans l'ordre croissant par exemple).
- On vérifie l'élément y du milieu de liste :
- S'il a pour valeur x, c'est terminé (on retourne son rang).
- Si y < x, alors x est maintenant à chercher dans la partie de liste se trouvant à droite de l'élément y (c'est à dire dans les éléments d'indice plus grand que l'indice de y).
- Si y > x, alors x est maintenant à chercher dans la partie de liste se trouvant à gauche de l'élément y.
Question
Écrire une fonction python récursive utilisant le principe de dichotomie :
Entrée | Une liste L de nombres, triée en ordre croissant. Un nombre x. |
---|---|
Sortie | -1 si x n'est pas dans la liste, le rang de l'une de ses occurrences s'il est présent dans L. |
- élément milieu
- un code
On clarifie ici ce que l'on peut appeler élément milieu d'une liste.
Dans tous les cas, dans une liste de n éléments, on peut facilement définir un élément tel que les deux sous-listes à gauche et à droite de cet élément contiennent chacune au plus \( \lfloor \frac{n}{2} \rfloor \) éléments. Il est facile de s'en convaincre avec quelques exemples. On explicite ici une formule donnant l'indice d'un tel élément.
On dispose d'une liste, ou plutôt d'une sous-liste de liste :
[ L[a], L[a+1], L[a+2], ..., L[b] ], contenant
\( n = b-a+1 \) éléments.
On nomme élément milieu de la liste, l'élément d'indice (a+b)//2 -- où (notation python) (a+b)//2 est le quotient de la division euclidienne de a+b par 2.
On note q ce quotient (c'est à dire \( q = \lfloor \frac{a+b}{2} \rfloor \) ).
- La sous-liste gauche est [L[a], L[a+1], ..., L[q-1] ]. Elle contient (q-1)-a+1 = q-a éléments.
- La sous-liste droite est [L[q+1], L[q+2], ..., L[b] ]. Elle contient b - (q+1) +1 = b-q éléments.
Explicitons le nombre d'éléments de chacune de ces sous-listes.
- Cas 1. a+b = 2q.
Dans ce cas, b-q = (2q-a)-q = q-a. Les deux sous-listes contiennent le même nombre d'éléments.
Ce nombre d'éléments est bien sûr le quotient de la division entière par 2 du nombre d'éléments initial dans la sous-liste : b-a+1 = 2(q-a) +1, soit \( q-a = \lfloor \frac{n}{2} \rfloor \). - Cas 2. a+b = 2q+1. Dans ce cas, b-q = (2q+1-a)-q = q-a+1.
L'une des deux sous-listes contient un élément de plus que l'autre.
On a b-a+1 = 2(q-a+1). L'une des sous-listes contient donc \( \lfloor \frac{n}{2} \rfloor \) éléments, et l'autre en contient un de moins.
def recherche(element, liste):
def dichotomie(mini, maxi):
if mini > maxi : return -1
m = (mini+maxi)//2
if liste[m] == element : return m
elif liste[m] < element : return dichotomie(m+1, maxi)
else : return dichotomie(mini, m-1)
return dichotomie(0, len(liste)-1)
L = [2,4,9,15,41]
print( recherche(16, L) )
print( recherche(15, L) )