đ Cours : La Recherche Dichotomique
1. đ ProblĂšme de dĂ©part : chercher dans une liste
Imaginez que vous avez une liste de 1 000 prénoms triés par ordre alphabétique, et on vous demande de retrouver le prénom "Zoé". Comment procéderiez-vous ?
Deux stratégies s'opposent :
- Stratégie 1 : Commencer depuis le début et lire chaque prénom un par un jusqu'à trouver
"ZoĂ©". - StratĂ©gie 2 : Ouvrir directement au milieu, voir si vous ĂȘtes avant ou aprĂšs
"Zoé", puis réduire de moitié la zone de recherche.
L'informatique a formalisé ces deux idées sous la forme d'algorithmes de recherche.
2. đ Recherche SĂ©quentielle (ou LinĂ©aire)
Principe
La recherche séquentielle consiste à parcourir la liste élément par élément, du premier au dernier, jusqu'à trouver la valeur cherchée (ou arriver à la fin sans l'avoir trouvée).
Illustration
On cherche 9 dans la liste [4, 7, 2, 9, 1, 5] :
- On regarde
4â non - On regarde
7â non - On regarde
2â non - On regarde
9â trouvĂ© ! (Ă l'index 3)
Implémentation Python
def recherche_sequentielle(liste, valeur):
"""
Recherche une valeur dans une liste de maniÚre séquentielle.
Retourne l'indice de la valeur si trouvée, -1 sinon.
"""
for i in range(len(liste)):
if liste[i] == valeur:
return i
return -1
Caractéristiques
- Fonctionne sur toute liste, qu'elle soit triée ou non.
- Simple à comprendre et à implémenter.
3. â±ïž La Notion de ComplexitĂ©
Pourquoi s'intéresser à la complexité ?
Deux algorithmes qui rĂ©souslvent le mĂȘme problĂšme peuvent avoir des performances trĂšs diffĂ©rentes selon la taille des donnĂ©es.
En informatique, on mesure l'efficacité d'un algorithme grùce à sa complexité temporelle : on évalue le nombre d'opérations que l'algorithme doit effectuer en fonction de la taille n de la liste.
Notion clé : la notation O()
On utilise la notation O(...) (lire « grand O ») pour décrire la complexité dans le pire des cas :
- O(1) : complexitĂ© constante â le temps ne dĂ©pend pas de n
- O(n) : complexitĂ© linĂ©aire â le temps est proportionnel Ă n
- O(log n) : complexitĂ© logarithmique â le temps croĂźt trĂšs lentement
- O(nÂČ) : complexitĂ© quadratique â le temps croĂźt trĂšs vite
Complexité de la recherche séquentielle
Analysons le pire cas de la recherche séquentielle : la valeur cherchée n'est pas dans la liste.
Dans ce cas, on doit parcourir tous les n éléments de la liste.
đ La complexitĂ© de la recherche sĂ©quentielle est O(n).
Illustration concrĂšte
Voici combien d'opérations sont nécessaires selon la taille de la liste :
| Taille de la liste (n) | Recherche séquentielle (O(n)) |
|---|---|
| 10 | 10 opérations |
| 100 | 100 opérations |
| 1 000 | 1 000 opérations |
| 1 000 000 | 1 000 000 opérations |
| 1 000 000 000 | 1 000 000 000 opĂ©rations đ± |
Sur une liste d'un milliard d'éléments, la recherche séquentielle peut prendre plusieurs secondes voire minutes !
4. đŻ Recherche Dichotomique
PrĂ©-requis indispensable â ïž
Attention
La recherche dichotomique ne fonctionne que sur une liste triée !
Principe
La recherche dichotomique (du grec dikha = en deux parties) consiste Ă :
- Regarder l'élément au milieu de la liste.
- Si c'est la valeur cherchĂ©e â trouvĂ© !
- Si la valeur cherchĂ©e est plus petite â continuer la recherche dans la moitiĂ© gauche.
- Si la valeur cherchĂ©e est plus grande â continuer la recherche dans la moitiĂ© droite.
- Répéter jusqu'à trouver l'élément ou jusqu'à ce que la zone de recherche soit vide.
đ Ă chaque Ă©tape, on divise par 2 la zone de recherche.
đ Exemple dĂ©taillĂ©
On cherche la valeur 37 dans la liste triée suivante (14 éléments) :
[2, 5, 8, 12, 16, 23, 37, 42, 56, 72, 84, 91, 95, 99]
0 1 2 3 4 5 6 7 8 9 10 11 12 13
†Ătape 1
gauche = 0 droite = 13
milieu = (0 + 13) // 2 = 6
liste[6] = 37
đ TrouvĂ© immĂ©diatement Ă l'index 6 !
Essayons maintenant de chercher 56 :
†Ătape 1
gauche = 0 droite = 13
milieu = 6
liste[6] = 37
37 < 56 â on cherche dans la moitiĂ© DROITE
†Ătape 2
gauche = 7 droite = 13
milieu = (7 + 13) // 2 = 10
liste[10] = 84
84 > 56 â on cherche dans la moitiĂ© GAUCHE
†Ătape 3
gauche = 7 droite = 9
milieu = (7 + 9) // 2 = 8
liste[8] = 56
đ TrouvĂ© Ă l'index 8 en seulement 3 Ă©tapes !
Avec une recherche séquentielle, on aurait parcouru 9 éléments (de l'index 0 à 8).
𧩠Schéma de la démarche
[2, 5, 8, 12, 16, 23, 37, 42, 56, 72, 84, 91, 95, 99]
âââââââââââââââââ[milieu=37]âââââââââââââââââ
56 > 37
ââââââââ [milieu=84] ââââââââ
56 < 84
ââ[milieu=56]ââ
â
Trouvé !
5. â±ïž ComplexitĂ© de la recherche dichotomique
Analyse du pire cas
à chaque étape, on divise la zone de recherche par 2.
- Départ : n éléments
- AprÚs 1 étape : n/2 éléments
- AprÚs 2 étapes : n/4 éléments
- AprÚs k étapes : n/2ᔠéléments
On s'arrĂȘte quand il ne reste plus qu'1 Ă©lĂ©ment : n/2á” = 1, soit k = logâ(n).
đ La complexitĂ© de la recherche dichotomique est O(log n).
Comparaison des complexités
| Taille de la liste (n) | Recherche sĂ©quentielle O(n) | Recherche dichotomique O(logâ n) |
|---|---|---|
| 10 | 10 opérations | 4 opérations |
| 100 | 100 opérations | 7 opérations |
| 1 000 | 1 000 opérations | 10 opérations |
| 1 000 000 | 1 000 000 opérations | 20 opérations |
| 1 000 000 000 | 1 000 000 000 opĂ©rations | 30 opĂ©rations đ |
Bilan
Sur un milliard d'éléments, la recherche dichotomique ne nécessite que 30 comparaisons ! Contre 1 milliard pour la recherche séquentielle.
C'est la puissance du logarithme : doubler la taille de la liste ne coûte qu'une seule étape de plus.
6. đ» ImplĂ©mentation Python
Version itérative
def recherche_dichotomique(liste, valeur):
"""
Recherche une valeur dans une liste TRIĂE par dichotomie.
Retourne l'indice de la valeur si trouvée, -1 sinon.
PrĂ©condition : la liste doit ĂȘtre triĂ©e par ordre croissant.
"""
gauche = 0
droite = len(liste) - 1
while gauche <= droite:
milieu = (gauche + droite) // 2 # indice du milieu
if liste[milieu] == valeur:
return milieu # valeur trouvée
elif liste[milieu] < valeur:
gauche = milieu + 1 # on cherche dans la moitié droite
else:
droite = milieu - 1 # on cherche dans la moitié gauche
return -1 # valeur non trouvée
Trace d'exécution
Pour recherche_dichotomique([1, 3, 5, 7, 9, 11, 13], 7) :
| Ătape | gauche | droite | milieu | liste[milieu] | Action |
|---|---|---|---|---|---|
| 1 | 0 | 6 | 3 | 7 | TrouvĂ© ! â 3 |
Pour recherche_dichotomique([1, 3, 5, 7, 9, 11, 13], 11) :
| Ătape | gauche | droite | milieu | liste[milieu] | Action |
|---|---|---|---|---|---|
| 1 | 0 | 6 | 3 | 7 | 11 > 7 â gauche = 4 |
| 2 | 4 | 6 | 5 | 11 | TrouvĂ© ! â 5 |
7. â Bilan et comparaison
Tableau récapitulatif
| CritÚre | Recherche séquentielle | Recherche dichotomique |
|---|---|---|
| Liste doit ĂȘtre triĂ©e ? | â Non | â Oui |
| Complexité (pire cas) | O(n) | O(log n) |
| Efficacité sur grande liste | Lente | TrÚs rapide |
| SimplicitĂ© de code | âââ | ââ |
Quand utiliser quoi ?
- â Recherche sĂ©quentielle : liste non triĂ©e, petite liste, cas simple.
- â Recherche dichotomique : liste triĂ©e, grande liste, performance critique.
Ă retenir
La recherche dichotomique est un exemple classique d'algorithme dit « diviser pour régner » (divide and conquer) : on résout un grand problÚme en le divisant en sous-problÚmes plus petits.
La notation O(log n) traduit une croissance extrĂȘmement lente : c'est l'une des meilleures complexitĂ©s qu'un algorithme de recherche puisse avoir.