Information, Communication, Calcul Ce videoclip produit par l’Ecole Polytechnique Fédérale de Lausanne fait partie du cours d’introduction à l’information, à la communication, et au calcul. Il est le 5e de 7 videoclips portant sur les notions de calcul et d’information. Information, Communication, Calcul Module 1: Calcul & Information – Leçon 1: Algorithmes – Clip 5: Recherche par Dichotomie R. Guerraoui, J. Sam, J-C. Chappelier, R. Boulic, commentaire: P. Janson
Plan de la leçon Qu’est-ce qu’un algorithme? Quelles structures existent pour contrôler un algorithme? Quelques grandes familles d’algorithms Recherche Exemple: recherche par dichotomie Comment quantifier et exprimer la complexité d’un algorithme Tri Plus court chemin Les 4 premiers clips ayant introduit la notion d’algorithme, leurs principales structures de contrôle, et les algorithmes de recherche en général. ce 5e clip se penche sur un algorithme de recherche particulier, dit par dichotomie.
Recherche par dichotomie - Algorithme Appartient_D entrée: x, E ordonné sortie: x∈ E ? Si E est vide sortir: x ∉ E Si E est réduit à 1 seul élément e sortir: x = e ? Découper E en deux parties E1 et E2 Si x ≤ max(E1) sortir: Appartient_D(x,E1) Sinon sortir: Appartient_D(x,E2) Sort VRAI ou FAUX selon que x∈E ou x∉E Sort FAUX Sort VRAI ou FAUX selon que x=E ou x≠E … de tailles quasiment égales Invocation récursive de Appartient_D sur la moitié de E où x pourrait se trouver Cet algorithme que nous appellerons Appartient_D prend comme entrée une entité x et un ensemble d’éléments E qui doit être ordonné en une liste, c’est-à-dire dont les éléments sont pré-classés selon un critère d’ordre quelconque. Une recherche par dichotomie ne peut pas fonctionner sans cette condition d’ordre. - L’algorithme produit comme sortie un booléen VRAI ou FAUX qui indique si l’entité x figure parmi les éléments de E. En prévision du cas où E serait vide, l’algorithme commence par tester cette hypothèse et si elle est vérifiée se termine en sortant évidemment un résultat négatif. Ensuite l’algorithme teste l’hypothèse où E ne contiendrait qu’un seul élément et dans ce cas il se termine en sortant un résultat positif ou négatif selon que ce seul élément de E est égal à l’entité x recherchée ou pas. Ayant éliminé les deux cas particuliers où E contiendrait 0 ou 1 élément, l’algorithme procède par une partition de E en deux moitiés (elles-mêmes ordonnées) et de tailles aussi égales que possible, d’où son nom de dichotomie. Les tailles des 2 moitiés sont égales si E contient un nombre pair d’éléments et différent de 1 unité (peu importe dans quel sens) si E contient un nombre impair d’éléments. Enfin l’algorithme compare l’entité recherchée x à max(E1), c’est-à-dire le plus grand des éléments de la moitié inférieure de E. Si x est inférieur ou égal cet élément, l’algorithme lance une recherche de x dans cette moitié inférieure de E. Sinon il lance une recherche de x dans la moitié supérieure de E. Dans un cas comme dans l’autre la recherche est relancée en ré-invoquant le même algorithme de recherche par dichotomie mais seulement sur la moitié désignée de l’ensemble original E. Une telle ré-invocation d’un algorithme par lui-même est ce qu’on appelle récursion. Ce sujet sera abordé plus en détail dans un des videoclips de la 2e leçon du présent module.
Recherche par dichotomie - Exemple Appartient_D entrée: x, E ordonné sortie: x∈ E ? Si E est vide sortir: x ∉ E Si E est réduit à 1 seul élément e sortir: x = e ? Découper E en deux parties E1 et E2 Si x ≤ max(E1) sortir: Appartient_D(x,E1) Sinon sortir: Appartient_D(x,E2) x = bleu E = abaque abasourdi babouin baobab blanc bleu zoulou Pour illustrer et vérifier le fonctionnement de cet algorithme, simulons son comportement par un exemple. - Imaginons vouloir rechercher un mot x égal à «bleu» dans une ensemble E comprenant les mots abaque, abasourdi, babouin, baobab, blanc, bleu, et zoulou pré-classés par ordre alphabétique.
Recherche par dichotomie - Exemple Appartient_D entrée: x, E ordonné sortie: x∈ E ? Si E est vide sortir: x ∉ E Si E est réduit à 1 seul élément e sortir: x = e ? Découper E en deux parties E1 et E2 Si x ≤ max(E1) sortir: Appartient_D(x,E1) Sinon sortir: Appartient_D(x,E2) Appartient_D(x,E) x = bleu E = abaque abasourdi babouin baobab blanc bleu zoulou E n’est ni vide ni réduit à un seul élément - L’algorithme commence par vérifier que E n’est ni vide ni réduit à un seul élément.
Recherche par dichotomie - Exemple Appartient_D entrée: x, E ordonné sortie: x∈ E ? Si E est vide sortir: x ∉ E Si E est réduit à 1 seul élément e sortir: x = e ? Découper E en deux parties E1 et E2 Si x ≤ max(E1) sortir: Appartient_D(x,E1) Sinon sortir: Appartient_D(x,E2) Appartient_D(x,E) x = bleu E = abaque abasourdi babouin baobab blanc bleu zoulou Donc on découpe E en 2 moitiés ~ égales x = bleu E1 = abaque abasourdi babouin baobab E2 = blanc bleu zoulou - Il procède donc par une partition de E en 2 moitiés, E1 et E2.
Recherche par dichotomie - Exemple Appartient_D entrée: x, E ordonné sortie: x∈ E ? Si E est vide sortir: x ∉ E Si E est réduit à 1 seul élément e sortir: x = e ? Découper E en deux parties E1 et E2 Si x ≤ max(E1) sortir: Appartient_D(x,E1) Sinon sortir: Appartient_D(x,E2) Appartient_D(x,E) x = bleu E1 = abaque abasourdi babouin baobab E2 = blanc bleu zoulou bleu vient-il avant baobab? Non! Il compare ensuite x (c.à.d. le mot «bleu») au plus grand élément de E1 (c.à.d. le mot «baobab»). - «bleu» n’étant pas alphabétiquement inférieur ou égal à «baobab» le test est négatif.
Recherche par dichotomie - Exemple Appartient_D entrée: x, E ordonné sortie: x∈ E ? Si E est vide sortir: x ∉ E Si E est réduit à 1 seul élément e sortir: x = e ? Découper E en deux parties E1 et E2 Si x ≤ max(E1) sortir: Appartient_D(x,E1) Sinon sortir: Appartient_D(x,E2) Appartient_D(x,E) x = bleu E1 = abaque abasourdi babouin baobab E2 = blanc bleu zoulou bleu vient-il avant baobab? Non! Donc on recherche bleu dans E2 - L’algorithme décide donc de relancer une recherche du mot «bleu» dans E2, la moitié supérieure de E.
Recherche par dichotomie - Exemple Appartient_D entrée: x, E ordonné sortie: x∈ E ? Si E est vide sortir: x ∉ E Si E est réduit à 1 seul élément e sortir: x = e ? Découper E en deux parties E1 et E2 Si x ≤ max(E1) sortir: Appartient_D(x,E1) Sinon sortir: Appartient_D(x,E2) Appartient_D(x,E2) x = bleu E1 = abaque abasourdi babouin baobab E2 = blanc bleu zoulou E2 n’est ni vide ni réduit à un élément Donc on le découpe en 2 moitiés ~ égales x = bleu E1 = abaque abasourdi babouin baobab E2.1 = blanc E2.2 = zoulou bleu Il s’invoque donc récursivement mais uniquement sur E2, la moitié supérieure de E. - Il vérifie rapidement que E2 n’est ni vide ni réduit à un seul élément, et le re-divise donc en 2 moitiés, E2.1 et E2.2
Recherche par dichotomie - Exemple Appartient_D entrée: x, E ordonné sortie: x∈ E ? Si E est vide sortir: x ∉ E Si E est réduit à 1 seul élément e sortir: x = e ? Découper E en deux parties E1 et E2 Si x ≤ max(E1) sortir: Appartient_D(x,E1) Sinon sortir: Appartient_D(x,E2) Appartient_D(x,E2) x = bleu E1 = abaque abasourdi babouin baobab E2.1 = blanc E2.2 = zoulou bleu bleu est-il ≤ bleu ? Oui! Donc on recherche bleu dans E2.1 Il compare alors x (c.à.d. toujours le mot «bleu») au plus grand élément de E2.1 (c.à.d. le mot «bleu»). - «bleu» étant alphabétiquement inférieur ou égal à lui-même, le test est positif et l’algorithme relance une 3e invocation de lui-même, cette fois uniquement sur E2.1, la moitié inférieure de E2.
Recherche par dichotomie - Exemple Appartient_D entrée: x, E ordonné sortie: x∈ E ? Si E est vide sortir: x ∉ E Si E est réduit à 1 seul élément e sortir: x = e ? Découper E en deux parties E1 et E2 Si x ≤ max(E1) sortir: Appartient_D(x,E1) Sinon sortir: Appartient_D(x,E2) Appartient_D(x,E2.1) x = bleu E1 = abaque abasourdi babouin baobab E2.1 = blanc E2.2 = zoulou bleu E2.1 n’est ni vide ni réduit à un élément Donc on le découpe en 2 moitiés ~ égales x = bleu E1 = abaque abasourdi babouin baobab E2.1.1 = blanc E2.2 = zoulou E2.1.2 = bleu Cette troisième invocation de l’algorithme … - … commence comme toujours par vérifier que l’ensemble en question, cette fois E2.1, n’est ni vide ni réduit à un seul élément … … et donc découpe une fois de plus E2.1 en deux moitiés, … … E2.1.1 et E2.1.2.
Recherche par dichotomie - Exemple Appartient_D entrée: x, E ordonné sortie: x∈ E ? Si E est vide sortir: x ∉ E Si E est réduit à 1 seul élément e sortir: x = e ? Découper E en deux parties E1 et E2 Si x ≤ max(E1) sortir: Appartient_D(x,E1) Sinon sortir: Appartient_D(x,E2) Appartient_D(x,E2.1) x = bleu E1 = abaque abasourdi babouin baobab E2.1.1 = blanc E2.2 = zoulou E2.1.2 = bleu bleu est-il ≤ blanc ? Non! Donc on recherche bleu dans E2.1.2 Cette 3e invocation de l’algorithme compare une fois de plus le mot x = bleu … - … au plus grand mot de E2.1.1, la moitié inférieure de la dernière partition. «bleu» n’étant pas alphabétiquement inférieur ou égal à «blanc» le test est négatif et l’algorithme s’invoque donc une 4e fois, uniquement sur la liste E2.1.2
Recherche par dichotomie - Exemple Appartient_D entrée: x, E ordonné sortie: x∈ E ? Si E est vide sortir: x ∉ E Si E est réduit à 1 seul élément e sortir: x = e ? Découper E en deux parties E1 et E2 Si x ≤ max(E1) sortir: Appartient_D(x,E1) Sinon sortir: Appartient_D(x,E2) Appartient_D(x,E2.1.2) x = bleu E1 = abaque abasourdi babouin baobab E2.1.1 = blanc E2.2 = zoulou E2.1.2 = bleu E2.1.2 n’est pas vide Cette 4e invocation commence comme toujours par le test de vide sur E2.1.2. - E2.1.2. n’étant en effet as vide …
Recherche par dichotomie - Exemple Appartient_D entrée: x, E ordonné sortie: x∈ E ? Si E est vide sortir: x ∉ E Si E est réduit à 1 seul élément e sortir: x = e ? Découper E en deux parties E1 et E2 Si x ≤ max(E1) sortir: Appartient_D(x,E1) Sinon sortir: Appartient_D(x,E2) Appartient_D(x,E2.1.2) x = bleu E1 = abaque abasourdi babouin baobab E2.1.1 = blanc E2.2 = zoulou E2.1.2 = bleu E2.1.2 n’est pas vide mais il ne contient qu’un élément qui se trouve être égal à bleu La 4e invocation de l’algorithme teste si E2.1.2 est réduit à un seul élément. Comme c’est le cas et que ce seul élément se trouve être égal au mot «bleu» recherché cette 4e invocation de l’algorithme se termine sur un résultat positif.
Recherche par dichotomie - Exemple Appartient_D entrée: x, E ordonné sortie: x∈ E ? Si E est vide sortir: x ∉ E Si E est réduit à 1 seul élément e sortir: x = e ? Découper E en deux parties E1 et E2 Si x ≤ max(E1) sortir: Appartient_D(x,E1) Sinon sortir: Appartient_D(x,E2) Appartient_D(x,E2.1.2) x = bleu E1 = abaque abasourdi babouin baobab E2.1.1 = blanc E2.2 = zoulou E2.1.2 = bleu E2.1.2 n’est pas vide mais il ne contient qu’un élément qui se trouve être égal à bleu Donc Appartient_D(x,E) = Appartient_D(x,E2.1.2) = VRAI ! Ce résultat met fin à toutes les invocations précédentes de l’algorithme en leur renvoyant le résultat VRAI qui déroule toutes ces invocations récursives.
Complexité de l’algorithme de recherche par dichotomie Rappel: complexité = nombre d’opérations nécessaires dans le pire des cas Dans le pire des cas l’élément recherché se trouverait (ou pas) au « milieu » du « milieu » du « milieu » du « milieu » du « milieu » du « milieu » … => il faudrait réitérer l’opération de découpage autant de fois qu’on peut diviser E en 2. Or combien de fois qu’on peut diviser un ensemble de n éléments en 2 ? => log2 n => la complexité de cet algorithme est log2 n comme démontré dans ce vidéoclip http://wandida.com/fr/archives/511 (Rappel: si 2y = x alors y = log2x ou log2x = log10x / log102) NB: on verra plus tard comme la notion de dichotomie est lié à celle du codage de l’information ! Comme suggéré à la fin du videoclip précédant l’intérêt de cette recherche par dichotomie est sa complexité inférieure à celle de tous les algorithmes de recherche sur des ensembles non-ordonnés. Alors voyons que cette propriété est bien vérifiée. - Pour rappel, la complexité d’un algorithme est le nombre d’opérations élémentaires nécessaires à son exécution dans le pire des cas. Dans le cas de l’algorithme de recherche par dichotomie, le pire des cas serait celui dans lequel l’élément x recherché devrait se trouver au milieu du milieu du milieu du milieu … de l’ensemble ordonné E. Dans ce cas l’algorithme devrait se ré-invoquer autant de fois qu’il est possible de diviser E en 2. Or combien de fois peut-on diviser en 2 un ensemble de n éléments? La réponse est log2n, le logarithme de n en base 2. (Pour rappel le logarithme d’un nombre x en base 2 est la puissance y à laquelle il faut élever 2 pour obtenir ce nombre x.) (Ce logarithme peut se calculer en divisant le logarithme du même nombre en base 10 par le logarithme de 2 en base 10.) Nous verrons plus tard que cette notion de dichotomie est intimement liée au codage de l’information en binaire.