Algorithmique 1 · C3 Recherche et tris · Chapitre 1 · 25 min
Recherche
Comparer deux stratégies de recherche et mesurer leur coût : 1000 contre 10.
« Cette valeur est-elle dans le tableau, et si oui, où ? » C'est le problème le plus banal de l'informatique, et le premier où deux algorithmes corrects se distinguent nettement par leur coût. C'est aussi pour cela qu'on le traite ici : à partir de maintenant, être juste ne suffit plus.
Une convention pour toute la leçon : la recherche renvoie l'indice de la valeur trouvée, ou −1 si elle est absente. On renvoie l'indice et non la valeur, parce que l'appelant sait déjà ce qu'il cherchait — ce qui l'intéresse, c'est où.
La recherche séquentielle
La stratégie évidente : regarder les cases une par une jusqu'à trouver.
Fonction RechercheSequentielle(T, n, cible) : entier Pour i de 0 à n − 1 Faire Si T[i] = cible Alors Retourner i FinSi FinPour Retourner −1FinFonctionAnimation · 6 étapes
Recherche séquentielle de la valeur 8
- Le tableau n'est pas trié — Aucune information ne permet de sauter des cases : la seule stratégie possible est de les regarder une par une, dans l'ordre.
- T[0] = 12 ≠ 8 — Une comparaison consommée, aucune information gagnée sur la suite.
- T[1] = 5 ≠ 8 — On continue. 5 est plus petit que 8, mais cela n'apprend rien : le tableau est en désordre.
- T[2] = 20 ≠ 8 — Troisième échec.
- T[3] = 8 : trouvé ! — On renvoie 3, l'INDICE, pas la valeur : l'appelant sait déjà ce qu'il cherchait, ce qui l'intéresse c'est où.
- Et si la valeur n'y était pas ? — Il aurait fallu épuiser les 7 cases avant de pouvoir renvoyer −1. Pire cas : n comparaisons, une par case.
Elle a deux qualités réelles : elle est simple, et elle fonctionne sur n'importe quel
tableau, trié ou non. Son coût, en revanche, se lit directement sur l'animation. Dans le
meilleur des cas la valeur est en case 0 et une comparaison suffit. Dans le pire, elle est
en dernière position ou absente, et il faut les n comparaisons. En moyenne, environ n/2.
Ce qui compte, c'est le pire cas : n comparaisons pour n cases. Doubler la taille du tableau double le travail.
Quiz · 1 question
Dans la recherche séquentielle sur un tableau NON trié, pourquoi ne peut-on pas s'arrêter dès qu'on rencontre une valeur plus grande que la cible ?
- Parce que la comparaison coûterait trop cher
- Parce que dans un tableau en désordre, une valeur plus grande ne dit rien sur ce qui suit
- Parce qu'on ne peut comparer que l'égalité
Réponse : Sur [12, 5, 20, 8], rencontrer 20 alors qu'on cherche 8 n'autorise aucune conclusion : 8 est juste derrière. Chaque comparaison ne renseigne que sur UNE case. C'est exactement ce que le tri va changer.
Pourquoi un tableau trié change tout
Sur un tableau trié, comparer la cible à une seule case renseigne d'un coup sur toutes
les autres. Si T[5] vaut 17 et qu'on cherche 23, alors 23 ne peut être ni en T[0], ni
en T[1]… ni en T[5] : tout ce qui est à gauche est plus petit que 17, donc plus petit
que 23.
Une comparaison, six cases éliminées. C'est cette information gratuite — offerte par le tri, pas par l'algorithme de recherche — que la dichotomie exploite jusqu'au bout.
La recherche dichotomique
L'idée : au lieu de commencer par le début, commencer par le milieu, et recommencer sur la moitié qui reste. Deux bornes délimitent la zone encore candidate.
Fonction Dichotomique(T, n, cible) : entier g ← 0 d ← n − 1 TantQue g ≤ d Faire m ← (g + d) ÷ 2 Si T[m] = cible Alors Retourner m SinonSi T[m] < cible Alors g ← m + 1 Sinon d ← m − 1 FinSi FinTantQue Retourner −1FinFonctionAnimation · 5 étapes
Recherche dichotomique de la valeur 23 (tableau trié)
- Le tableau est trié — tout change — Comparer la cible à une seule case renseigne d'un coup sur toutes celles qui sont à sa gauche et à sa droite. C'est cette information gratuite qu'on va exploiter.
- m = (0 + 10) / 2 = 5 → T[5] = 17 — 17 < 23 : la cible est forcément à droite. Les six cases de gauche sont éliminées par une seule comparaison.
- m = (6 + 10) / 2 = 8 → T[8] = 31 — 31 > 23 : cette fois on garde la gauche. d recule à 7. Il ne reste que deux candidates.
- m = (6 + 7) / 2 = 6 → T[6] = 20 — Division ENTIÈRE : 13 / 2 donne 6, pas 6,5. Un indice ne peut pas être à virgule. 20 < 23, donc g avance à 7.
- m = 7 → T[7] = 23 : trouvé — 4 comparaisons pour 11 cases. La recherche séquentielle en aurait fait 8. L'écart n'est pas encore spectaculaire ici — il le devient à 1000 cases.
Trois détails du code méritent qu'on s'y arrête, parce que chacun est une source de bug.
÷ est la division entière : (6 + 7) ÷ 2 vaut 6, pas 6,5. Un indice ne peut pas être
à virgule.
Les + 1 et − 1 dans g ← m + 1 et d ← m − 1 ne sont pas décoratifs. On vient de tester
la case m : la garder dans la zone candidate ferait retester indéfiniment la même case,
et la boucle ne s'arrêterait jamais.
Enfin, la condition g ≤ d avec un ou égal : quand il ne reste qu'une seule case
candidate, g et d sont égaux et cette case doit encore être testée. Avec <, on
manquerait toutes les valeurs situées en dernière position de l'intervalle.
Quiz · 1 question
Que se passe-t-il si on écrit g ← m au lieu de g ← m + 1 ?
- Le résultat est le même, c'est une question de style
- L'algorithme peut boucler indéfiniment sur la même case
- L'algorithme renvoie toujours −1
Réponse : Quand il reste deux cases, m vaut g, et g ← m ne fait pas avancer la borne : la zone candidate ne rétrécit plus. La boucle infinie de la leçon 4, dans un algorithme par ailleurs correct.
Compter les comparaisons
Comparons les deux stratégies sur un tableau trié de 1000 valeurs, dans le pire cas.
La recherche séquentielle fait 1000 comparaisons. La dichotomie divise la zone candidate par deux à chaque tour : 1000, puis 500, 250, 125, 63, 32, 16, 8, 4, 2, 1. Onze nombres, donc 10 comparaisons pour arriver à une seule case.
Graphique
Retrouver une valeur parmi 1000 — nombre de comparaisons (pire cas)
- Séquentielle : 10001000
- Dichotomique : 1010
Le nombre de divisions par deux nécessaires pour ramener à 1, c'est exactement le logarithme en base 2 :
Et cet écart ne se contente pas de rester : il explose.
| Taille du tableau | Séquentielle | Dichotomique |
|---|---|---|
| 100 | 100 | 7 |
| 1 000 | 1 000 | 10 |
| 1 000 000 | 1 000 000 | 20 |
| 1 000 000 000 | 1 000 000 000 | 30 |
Lisez la dernière ligne : multiplier la taille des données par un milliard n'ajoute que trente comparaisons. C'est la différence entre un algorithme qui suit la croissance des données et un algorithme qui s'en moque.
Quiz · 1 question
Un tableau trié passe de 1000 à 2000 valeurs. Combien de comparaisons supplémentaires coûte la recherche dichotomique dans le pire cas ?
- Environ 1000 de plus
- Deux fois plus, soit 20
- Une seule de plus, soit 11
Réponse : Doubler la taille ajoute exactement une division par deux, donc une comparaison. C'est la signature du logarithme : c'est le nombre de DOUBLEMENTS qui compte, pas la taille elle-même.
Le prix du tri
Un point d'honnêteté avant de conclure : la dichotomie exige un tableau trié, et trier a un coût. Pour une recherche unique sur des données en désordre, trier puis chercher revient plus cher que chercher séquentiellement.
Le calcul devient gagnant dès qu'on cherche plusieurs fois dans les mêmes données : le tri est payé une fois, les recherches profitent toutes du gain. C'est exactement ce que fait un index de base de données — et c'est la raison pour laquelle la leçon suivante porte sur le tri.
À vous
Exercice de code
Complétez le resserrement de l'intervalle, puis vérifiez le nombre de comparaisons.
Point de départ
// Complétez la dichotomie. Elle renvoie l'indice de la cible, ou -1,
// et compte ses comparaisons pour qu'on vérifie le coût annoncé en cours.
const T = [3, 5, 8, 9, 12, 17, 20, 23, 31, 42, 55];
function dichotomique(t, cible) {
let g = 0;
let d = t.length - 1;
let comparaisons = 0;
while (g <= d) {
const m = Math.floor((g + d) / 2);
comparaisons++;
if (t[m] === cible) return { indice: m, comparaisons };
// à compléter : si t[m] est trop petit, la cible est à DROITE (g bouge) ;
// sinon elle est à GAUCHE (d bouge).
break; // ← à supprimer : il n'est là que pour éviter la boucle infinie
}
return { indice: -1, comparaisons };
}
console.log(dichotomique(T, 23)); // attendu : indice 7, 4 comparaisons
console.log(dichotomique(T, 3)); // attendu : indice 0
console.log(dichotomique(T, 4)); // attendu : indice -1
Solution
const T = [3, 5, 8, 9, 12, 17, 20, 23, 31, 42, 55];
function dichotomique(t, cible) {
let g = 0;
let d = t.length - 1;
let comparaisons = 0;
while (g <= d) {
// Division ENTIÈRE : un indice ne peut pas valoir 6,5.
const m = Math.floor((g + d) / 2);
comparaisons++;
if (t[m] === cible) return { indice: m, comparaisons };
if (t[m] < cible) g = m + 1; // le + 1 évite de retester m indéfiniment
else d = m - 1;
}
return { indice: -1, comparaisons };
}
console.log(dichotomique(T, 23));
console.log(dichotomique(T, 3));
console.log(dichotomique(T, 4));
À retenir
Flashcards · 2 cartes
- Quelle hypothèse la recherche dichotomique exige-t-elle ?
- Que le tableau soit trié. Sans cette hypothèse, comparer à la case du milieu ne permet d'éliminer aucune autre case.
- Combien de comparaisons pour chercher parmi un million de valeurs triées ?
- Une vingtaine, car 2^20 dépasse un million. Contre un million pour la recherche séquentielle dans le pire cas.