Algorithme de Boyer-Moore

Algorithme de Boyer-Moore

L'algorithme de Boyer-Moore est un algorithme de recherche de sous-chaîne particulièrement efficace. Il a été développé par Bob Boyer et J Strother Moore[1] en 1977.

Sommaire

Efficacité / complexité en temps

L'algorithme de Boyer-Moore pré-traite la sous-chaîne (c'est-à-dire la chaîne recherchée), et non pas le texte (c'est-à-dire la chaîne dans laquelle la recherche est effectuée), à l'inverse de certains algorithmes, qui amortissent le coût du prétraitement du texte en effectuant de très nombreuses recherches répétitives. Le coût d'exécution de l'algorithme de Boyer-Moore peut être sub-linéaire, c'est-à-dire qu'il n'a pas besoin de vérifier chacun des caractères du texte, mais peut au contraire sauter certains d'entre eux. En général, l'algorithme devient plus rapide lorsque la longueur de la sous-chaîne s'allonge. Cette efficacité provient du fait que, pour chaque tentative infructueuse de correspondance entre les deux chaînes (texte et sous-chaîne), il utilise les informations déduites de cet échec pour éliminer le plus grand nombre possible de positions à vérifier.

En comparaison des méthodes de recherches basiques par la méthode de « force brute » (qui recherche la sous-chaîne en commençant par chercher partout dans le texte une correspondance du premier caractère de la sous-chaîne, puis en vérifiant si les caractères suivants correspondent) et dont la complexité en temps (calculée par exemple selon le nombre de paires de caractères à comparer) croit en O(L · K) K est la longueur de la sous-chaîne clé recherchée, et L la longueur lon recherche sil existe au moins une occurrences de la clé, lalgorithme de Boyer-Moore peut trouver les occurrences en un temps :

  • De lordre de O(L / K) dans le cas le plus favorable : dans ce meilleur cas, seul un caractère sur M doit être vérifié. Ainsi, plus la sous-chaîne est longue, et plus lalgorithme est efficace pour la trouver ;
  • de lordre de O(L + K) dans le pire cas (en utilisant la variante améliorée de lalgorithme avec la seconde table de vérification des occurrences).
  • et très souvent en un temps à peine supérieur au meilleur cas (qui devient de plus en plus probable quand la longueur K de la clé saccroit). Le pire cas est obtenu quand le texte contient de très nombreuses occurrences dun même caractère, et quand la clé cherchée contient ce caractère fréquent de nombreuses fois en fin de chaine sauf pour le premier caractère qui est différent.

Le cas moyen pour établir sil y a correspondance ou non requiert environ (3 · K) comparaisons. La preuve est due à Richard Cole[2].

Dans le pire cas, les performances de l'algorithme de base (sans la variante avec la seconde table de vérification des occurrences) pour trouver toutes les correspondances est de l'ordre de O(K · L). Le pire cas se produit quand la sous-chaîne consiste en une répétition dun unique caractère, et que le texte correspond à la répétition de (K - 1) fois ce même caractère, précédé par un seul autre caractère différent. Dans ce cas de figure, lalgorithme doit vérifier (L - K+ 1) décalages différents dans le texte pour chaque correspondance. Or, chacune de ces vérifications nécessite K comparaisons.

En raison de lintérêt de la variante avec la seconde table qui permet un comportement sous-linéaire même dans le pire cas, cette variante est décrite ici (et est celle aujourd'hui intégrée dans de nombreuses librairies de traitement du texte pour C/C++, Java, etc.).

Fonctionnement

Beaucoup de personnes sont surprises par l'algorithme de Boyer-Moore lorsqu'elles le découvrent pour la première fois, car il effectue la vérification, c'est-à-dire qu'il tente d'établir la correspondance de la sous-chaîne à une certaine position, à l'envers. Par exemple, s'il commence la recherche de la sous-chaîne WIKIPEDIA au début d'un texte, il vérifie d'abord la neuvième position en regardant si elle contient un A. Ensuite, s'il a trouvé un A, il vérifie la huitième position pour regarder si elle contient le dernier I de la sous-chaîne, et ainsi de suite jusqu'à ce qu'il ait vérifié la première position du texte pour y trouver un W.

La raison pour laquelle l'algorithme de Boyer-Moore utilise cette approche à rebours est plus claire si l'on considère ce qui se produit quand la vérification échoue, par exemple si au lieu de trouver un A en neuvième position, un X est lu. Le X n'apparaît nulle part dans la sous-chaîne WIKIPEDIA, ce qui signifie qu'aucune correspondance avec la sous-chaîne n'existe au tout début du texte, ainsi que dans les huit positions qui la suivent. Après la vérification d'un seul caractère, l'algorithme est capable de passer ces huit caractères et de rechercher le début d'une correspondance à partir de la dixième position dans le texte, juste après le X.

Ce principe de fonctionnement à rebours explique la quelque peu contre-intuitive affirmation disant que plus la sous-chaîne est longue, et plus l'algorithme est efficace pour la trouver.

Prenons un exemple plus significatif : on veut rechercher les occurrences de la clé de K=6 caractèresstringdans le texte de L=20 caractèresstupid_spring_string".

Avec un algorithme classique utilisant une méthode de force brute, on devrait rechercher le s dans tout le texte sauf les 5 derniers caractères, et donc faire toutes les 15 comparaisons. Et on trouverait 3 occurrences du s au début de chaque mot du texte ; pour chacune de ces occurrences on devrait vérifier la suite de la clé tant qu'elle correspond : on détecterait le p une fois pour rejeter loccurrence commençant par spring, mais le t serait détecté 2 fois dans stupid et string ; on doit alors tester la présence du r après st pour éliminer loccurrence dans stupid ; il reste encore à vérifier chacun des 3 autres caractères de la clé string, on il faudra donc 23 comparaisons (ce serait pire si le texte contenait de nombreuses occurrences de la quasi-totalité du début de la clé).

Avec lalgorithme de Boyer-Moore, on recherchera aussi les occurrences depuis le début du texte (en affichant ci-dessous la clé cherchée en dessous du texte balayé, les points notés avant la clé indiquant les positions déjà éliminées, le surlignage indique les comparaisons effectuées), mais on commencera en comparant le dernier caractère de la clé cherchée :

stupid_spring_string
string

Les deux caractères d et g ne correspondent pas, on a trouvé à la place un d dans le texte, alors quil ny a aucun d dans la clé. On peut sauter directement dans le texte les 6 caractères de la clé :

stupid_spring_string
······string

Le g de la clé ne correspond pas au n du texte. Cependant, la clé contient un n, 1 caractère avant, on peut donc décaler d1 position, et vérifier à nouveau en commençant par la fin de clé :

stupid_spring_string
·······string

On a trouvé successivement la correspondance du g, puis du n, puis du i, puis du r, mais pas du t de la clé. Au lieu de cela on a trouvé un p dans le texte, qui ne figure pas dans la clé, ce qui permet de sauter directement dans le texte les 6 caractères de la clé :

stupid_spring_string
·············string

Le g de la clé ne correspond pas au n du texte. Cependant, la clé contient un n, 1 caractère avant, on peut donc décaler d1 position, et vérifier à nouveau en commençant par la fin de clé :

stupid_spring_string
··············string

On trouve successivement les correspondances du g, puis du n, du i, du r, du t et du s. Il n'y a plus dautre caractère dans la clé, on a bien trouvé une occurrence en seulement 9 comparaisons (au lieu de 23 avec lalgorithme classique). Si on devait chercher les occurrences suivantes, il suffit de reprendre lalgorithme dans le texte à partir de la position qui suit la position trouvée.

Contraintes dimplémentation

Il faut noter que, pour que lalgorithme de Boyer-Moore puisse fonctionner de façon efficace, il est nécessaire de pouvoir parcourir le texte (ainsi que la clé cherchée) en le parcourant linéairement en sens inverse, et de pouvoir sauter directement à une position ultérieure du texte sans avoir à le lire intégralement entre les deux positions, ni à devoir le relire le texte ou la clé depuis le début, et sans avoir à utiliser de couteux tampons mémoire compliqués à gérer. Ce nest pas toujours le cas de tous les flux de fichiers texte à lecture unidirectionelle.

Et dans le cas la recherche doit utiliser des comparaisons basées sur la collation de chaînes conformes à des règles linguistiques dans lesquelles certaines différences sont ignorées dans la recherche des correspondances, les éléments à comparer ne seront pas les caractères eux-mêmes mais les éléments de collation précalculés sur la clé et ceux obtenus au fil de leau dans le texte, dans lequel il doit être nécessaire de déterminer si les positions sont celles marquant la séparation des éléments de collation (afin de ne pas trouver de faux positifs ni oublier des correspondances lorsquon saute directement certaines positions ou quand on lit le texte ou la clé en sens inverse: cela pose certaines difficultés dans les collations linguistiques comprenant des contractions et expansions, ou encore dans des textes Unicode non normalisés pour lesquels plusieurs codages sont possibles. Mais des algorithmes complémentaires ont été développés pour traiter efficacement cette difficulté (et quelques autres liées à létendue du jeu de caractères Unicode (ou létendue numérique encore plus grande des poids de collation multiniveau)[3].

Pré-traitement

L'algorithme précalcule deux tableaux pour traiter l'information qu'il obtient pour chaque vérification ayant échoué. La première indique le nombre de positions à sauter avant de reprendre la recherche, en se basant sur l'index du caractère qui a provoqué l'échec de la vérification. La seconde donne une information similaire, basée sur le nombre de caractères vérifiés avec succès avant que la vérification échoue. Comme ces deux tableaux indiquent le nombre de positions qu'il faut sauter dans le texte avant de poursuivre la recherche, ils sont parfois appelés "tables de sauts".

Première table de sauts (non-concordance du dernier caractère de clé)

Le premier tableau contenant le nombre de caractères suivants à ignorer en cas de non-concordance du dernier caractère de la clé est facile à remplir ; il correspond à la distance, mesurée depuis la fin de la clé, de la dernière occurrence dans la sous-chaîne clé de chaque caractère de lalphabet (alphabet commun à la clé et au texte:

  • préremplir toutes les positions du tableau des caractères avec la longueur de la sous-chaîne clé ;
  • démarrer par le dernier caractère de la sous-chaîne clé avec le compteur à 0, et aller en direction du premier caractère :
  • pour chaque déplacement vers la gauche, incrémenter le compteur, et si le caractère à la position courante nest pas déjà dans le tableau, lajouter avec la valeur actuelle du compteur.

Exemple : avec la sous-chaîne WIKIPEDIA, le premier tableau est rempli comme suit (pour plus de clarté, les entrées sont données dans l'ordre elles sont ajoutées dans le tableau:

Indice
(caractère de lalphabet)
Dernière correspondance
(depuis la fin de clé)
I 1
D 2
E 3
P 4
K 6
W 8
Autres caractères 9

Le lecteur attentif remarquera que le A, le dernier caractère de la sous-chaîne, na pas été ajouté dans le tableau.

La raison est que lalgorithme utilise le tableau après avoir trouvé un caractère qui ne correspond pas. Le tableau lui indique le nombre de positions vers lavant que l'algorithme doit sauter avant que ce caractère puisse théoriquement correspondre dans le texte. Par exemple, si en vérifiant la neuvième position du texte, lalgorithme trouve un I plutôt quun A, cela indiquerait que la prochaine correspondance potentielle pourrait être trouvée une position plus loin vers lavant, et que la dixième position doit être vérifiée pour y chercher un A. Sil s'agit dun A, soit lalgorithme le trouve dans la dernière position, et dans ce cas, la vérification est un succès, soit la dernière position a déjà été vérifiée ; dans ce second cas, il n'existe aucun endroit dans le reste de la sous-chaîne clé le A peut correspondre. De ce fait, aucune correspondance nest possible jusqu'à ce que lalgorithme cherche complètement au-delà de la position du A.

Notes de performance :

  1. On doit remarquer que ce tableau a une taille (nombre total dentrées) indépendante de la longueur de la clé, mais dépendante de la taille de lalphabet des caractères possibles.
    • Si lalphabet est très grand (par exemple le répertoire universel UCS dUnicode et ISO/IEC 10646 dont lalphabet comprend plus dun million de points de code possibles) sa taille pourrait devenir prohibitive, alors que la plus grande partie de ce tableau contiendrait la valeur par défaut (la longueur de clé), et son préremplissage peut prendre du temps.
    • De même les longueurs de saut stockées dans le tableau ne pourront pas être supérieures à la taille A de lalphabet avec lalgorithme de remplissage ci-dessus, et il est donc inutile de traiter la totalité de la clé en dehors des A derniers caractères de celle-ci.
      Cette optimisation sera utile si la longueur K de la clé cherchée est suffisamment longue (K A), tout en étant ne dépassant pas la longueur L du texte à parcourir, K < L.
      En effet, lorsque K L la réponse est immédiate et ne nécessite pas cet algorithme, puisqualors :
      • soit on a K > L, et aucune occurrence de la clé nexiste dans le texte ;
      • sinon on a K = L, et un simple test dégalité des deux chaînes (lues chacune du début à la fin) détermine si le texte est lui-même la seule occurrence de la clé cherchée.
    • On doit noter cependant que lalgorithme de Boyer-Moore doit son efficacité à sa capacité de sauter des longueurs de texte suffisantes. Quand lalphabet est bien plus grand que la longueur de clé, lalgorithme restera efficace si on réduit lalphabet à des classes de caractères (lalgorithme de Boyer-Moore continuera à comparer les caractères, mais il nest pas nécessaire de sauter le nombre maximum de caractères mais seulement un nombre raisonnable (par rapport à la longueur de clé) quand on peut aussi sauter (au prix de quelques pas supplémentaires si la clé contient des caractères distincts mais appartenant à la même classe).
    • Dans ce cas, le tableau ne sera pas indexé sur tous les caractères possibles mais sur tous les numéros de classes de caractère possibles : une fonction de hachage simple réduisant ce grand alphabet à (par exemple) un ensemble réduit à 256 classes de caractères convenablement distribués (ou 256 classes de poids de collation) sera suffisant et fonctionnera de façon très efficace pour des longueurs de clés pouvant aller jusqu'à plusieurs milliers de caractères (ou éléments de collation), la table permettant alors deffectuer des sauts de 1 à 256 caractères (ou éléments de collation).
    • Le saut maximum (256) ne sera en fait possible que pour les caractères inexistants dans la clé et correspond dans la table ci-dessus aux index des « Autres caractères ». Comme la table ne contient aucune valeur nulle, ce saut maximum pour les caractères (ou classes de caractères) inexistants dans la clé peut aussi être codé 0 (et il nest pas nécessaire dinitialiser le tableau à autre chose que 0, si le tableau alloué est déjà prérempli à zéro).
  2. En revanche, si lalphabet est extrêmement réduit (par exemple, un alphabet binaire), lefficacité de lalgorithme sera totalement nulle (par rapport à un algorithme de recherche brute) avec cette table de sauts, qui ne contiendra quune seule ligne « Autres caractères » pour le caractère autre que celui en dernière position de la clé : lastuce consistera à lire le texte ou la clé non pas caractère par caractère, mais par groupe successifs de caractères afin daugmenter lalphabet à un cardinal suffisant : par exemple on pourra lire le texte ou la clé par paquet de 8 caractères, si lalphabet effectivement utilisé dans la clé et le texte est binaire, en fixant un caractère de bourrage arbitraire (ou moins probable) pour les caractères (du petit alphabet) qui manquent au début de la clé ou au début du texte mais qui sont nécessaires à la formation de groupes complets de lettres convertis en lettres équivalentes du nouvel alphabet augmenté. On tiendra ensuite compte, lorsque des correspondances sont trouvées entre des groupes de caractères, du nombre de caractères de bourrage utilisés en début de clé ou de fichier pour ajuster la position du groupe trouvé.

Seconde table de saut (non-concordance des caractères de la clé autres que le dernier)

Le second tableau est sensiblement plus compliqué à calculer : pour chaque valeur de N inférieure à la longueur K de la sous-chaîne clé, il faut calculer le motif composé des N derniers caractères de la sous-chaîne K, précédé d'un caractère qui ne correspond pas. Puis, il faut trouver le plus petit nombre de caractères pour lequel le motif partiel peut être décalé vers la gauche avant que les deux motifs ne correspondent. Par exemple, pour la sous-chaîne clé ANPANMAN longue de 8 caractères, le tableau de 8 lignes est rempli de cette manière (les motifs déjà trouvés dans le texte sont montrés alignés dans des colonnes correspondant à léventuel motif suivant possible, pour montrer comment sobtient la valeur de décalage qui est la seule réellement calculée et stockée dans la seconde table de saut:

Indice   Motif suivant Décalage
obtenu
A N P A N M A N
0                         N   1
1         A N                 8
2                 M A N       3
3         N M A N             6
4       A N M A N             6
5     P A N M A N             6
6   N P A N M A N             6
7 A N P A N M A N             6

Notes relatives à la complexité de calcul cette table :

  • On remarque que cette table contient autant de lignes que la longueur de clé. Si la clé est longue, les valeurs de décalage dans la table peuvent être elles aussi assez importantes, ce qui va nécessiter une allocation de mémoire de travail peut-être importante, souvent plus grande en taille elle-même que la chaîne clé qui utilise un alphabet plus réduit (par exemple 1 octet par caractère) que les entiers alors quen fin de compte les longueurs de clé seront importantes (typiquement des entiers codés sur 4 octets).
  • La constitution de cette table nécessite aussi de rechercher des sous-chaînes (toutes les sous-chaînes possibles de la fin de clé) pour en trouver pour chacune la dernière occurrence dans la clé, et lalgorithme de Boyer-Moore pourrait être utilisé récursivement (mais en utilisant une recherche sur des textes et clés de direction inversée).
  • Au delà dune certaine longueur raisonnable (par exemple jusquaux 256 derniers caractères de la clé), il peut être inutile daugmenter la taille de cette table puisque le seul but sera de savoir si des décalages plus grands peuvent être obtenus pour sauter plus vite dans le texte principal. En ne pré-traitant que les 256 derniers caractères en fin de clé, on obtiendra une longueur déjà suffisante pour accélérer la majorité des recherches (mais si on veut aller au delà, on pourra, lorsque cette table contient déjà la longueur maximale retenue pour le saut et dans les rares cas cette longueur serait atteinte, et si lalphabet est assez discriminant, ce que peut indiquer le taux de remplissage de la première table, employer lalgorithme pour rechercher par récursion (plutôt que par précalcul dans cette table) les sous-chaînes dans la clé.
  • Mais le plus simple est de borner les décalages à une valeur raisonnable comme 256 et ne pas chercher à aller au delà. Dans ce cas, cette table aura une taille prédéfinie et ne coûtera rien en termes de complexité pour les clés très longues, puisque son remplissage prendra lui aussi un temps fini.
  • Différentes stratégies sont possibles selon un compromis espace/temps (des stratégies dites « avec cache », ne font aucun précalcul des tables, même si elles en utilisent, mais remplissent cette table à la demande en fonction des longueurs de concordances effectivement trouvées à rebours lors de la vérification des occurrences finales déjà trouvées par la première table ci-dessus).

Voir aussi

Sur les autres projets Wikimedia :

Articles connexes

Liens externes

Référence

  1. Le prénom de « J Strother Moore » est bien la lettre J et non labréviation « J. » dun prénom
  2. Tight bounds on the complexity of the Boyer-Moore algorithm, Proceedings of the 2nd Annual ACM-SIAM Symposium on Discrete Algorithms, (1991)
  3. (en) Efficient text searching in Java, par Laura Werner, paru dans Java Report en 1999 (document présenté dans le projet ICU).

Wikimedia Foundation. 2010.

Contenu soumis à la licence CC-BY-SA. Source : Article Algorithme de Boyer-Moore de Wikipédia en français (auteurs)

Игры ⚽ Поможем написать курсовую

Regardez d'autres dictionnaires:

  • Algorithme De Boyer-Moore — L algorithme de Boyer Moore est un algorithme de recherche de sous chaîne particulièrement efficace. Il a été développé par Bob Boyer et J. Strother Moore en 1977. Sommaire 1 Présentation 2 Fonctionnement de l algorithme 2.1 Pré traitement …   Wikipédia en Français

  • Algorithme de boyer-moore — L algorithme de Boyer Moore est un algorithme de recherche de sous chaîne particulièrement efficace. Il a été développé par Bob Boyer et J. Strother Moore en 1977. Sommaire 1 Présentation 2 Fonctionnement de l algorithme 2.1 Pré traitement …   Wikipédia en Français

  • Algorithme de recherche de chaîne de caractères de Boyer-Moore — Algorithme de Boyer Moore L algorithme de Boyer Moore est un algorithme de recherche de sous chaîne particulièrement efficace. Il a été développé par Bob Boyer et J. Strother Moore en 1977. Sommaire 1 Présentation 2 Fonctionnement de l algorithme …   Wikipédia en Français

  • Algorithme de recherche de sous-chaîne de Boyer-Moore — Algorithme de Boyer Moore L algorithme de Boyer Moore est un algorithme de recherche de sous chaîne particulièrement efficace. Il a été développé par Bob Boyer et J. Strother Moore en 1977. Sommaire 1 Présentation 2 Fonctionnement de l algorithme …   Wikipédia en Français

  • Algorithme De Recherche De Sous-chaîne — Un algorithme de recherche de sous chaine est un type d algorithme de recherche qui a pour objectif de trouver une chaîne de caractères à l intérieur d une autre. Un tel algorithme fournit la position du premier caractère de la sous chaîne… …   Wikipédia en Français

  • Algorithme de recherche de sous-chaine — Algorithme de recherche de sous chaîne Un algorithme de recherche de sous chaine est un type d algorithme de recherche qui a pour objectif de trouver une chaîne de caractères à l intérieur d une autre. Un tel algorithme fournit la position du… …   Wikipédia en Français

  • Algorithme De Knuth-Morris-Pratt — L algorithme de Knuth Morris Pratt (souvent abrégé par algorithme KMP) est un algorithme de recherche de sous chaîne, permettant de trouver les occurrences d une chaîne P dans un texte S. Sa particularité réside en un pré traitement de la chaîne …   Wikipédia en Français

  • Algorithme KMP — Algorithme de Knuth Morris Pratt L algorithme de Knuth Morris Pratt (souvent abrégé par algorithme KMP) est un algorithme de recherche de sous chaîne, permettant de trouver les occurrences d une chaîne P dans un texte S. Sa particularité réside… …   Wikipédia en Français

  • Algorithme de Knuth-Pratt-Morris — Algorithme de Knuth Morris Pratt L algorithme de Knuth Morris Pratt (souvent abrégé par algorithme KMP) est un algorithme de recherche de sous chaîne, permettant de trouver les occurrences d une chaîne P dans un texte S. Sa particularité réside… …   Wikipédia en Français

  • Algorithme de knuth-morris-pratt — L algorithme de Knuth Morris Pratt (souvent abrégé par algorithme KMP) est un algorithme de recherche de sous chaîne, permettant de trouver les occurrences d une chaîne P dans un texte S. Sa particularité réside en un pré traitement de la chaîne …   Wikipédia en Français

Share the article and excerpts

Direct link
https://fr-academic.com/dic.nsf/frwiki/81543 Do a right-click on the link above
and select “Copy Link”