web-dev-qa-db-fra.com

Quel algorithme de recherche de chaînes est le plus rapide?

Je suis coincé depuis un certain temps sur lequel est l'algorithme de recherche de chaînes le plus rapide, j'ai entendu de nombreuses opinions, mais à la fin je ne suis pas sûr.

J'ai entendu des gens dire que l'algorithme le plus rapide est Boyer-Moore et d'autres dire que Knuth-Morris-Pratt est en fait plus rapide.

J'ai recherché la complexité de chacun d'eux, mais ils ont généralement la même apparence O(n+m). J'ai trouvé que dans le pire des cas, Boyer-Moore a une complexité O(nm) par rapport à Knuth-Morris-Pratt qui a O (m + 2 * n). Où n = longueur du texte et m = longueur du motif.

Pour autant que je sache, Boyer-Moore a un pire temps linéaire si j'utilisais la règle de Galil.

Ma question, Sur tout ce qui est en fait l'algorithme de recherche de chaîne le plus rapide (Cette question comprend tous les algorithmes de piqûre possibles, pas seulement Boyer-Moore et Knuth-Morris-Pratt).

Modifier: En raison de cette réponse

Ce que je recherche exactement, c'est:

Étant donné un texte T et un motif P je dois trouver toutes les apparences de P dans T.

De plus, la longueur de P et T est de [1,2 000 000] et le programme doit s'exécuter sous 0,15 sec.

Je sais que KMP et Rabin-Karp suffisent pour obtenir un score de 100% sur le problème, mais pour ma part, je voulais essayer d'implémenter Boyer-Moore. Laquelle serait la meilleure pour ce type de recherche de modèle?

27
vandamon taigi

Cela dépend du type de recherche que vous souhaitez effectuer. Chacun des algorithmes fonctionne particulièrement bien pour certains types de recherche, mais vous n'avez pas précisé le contexte de vos recherches.

Voici quelques réflexions typiques sur les types de recherche:

  • Boyer-Moore: fonctionne en pré-analysant le motif et en comparant de droite à gauche. En cas de non-concordance, l'analyse initiale est utilisée pour déterminer dans quelle mesure le modèle peut être décalé par rapport à la valeur réelle. le texte recherché. Cela fonctionne particulièrement bien pour les longs modèles de recherche. En particulier, il peut être sous-linéaire, car vous n'avez pas besoin de lire chaque caractère de votre texte.

  • Knuth-Morris-Pratt: pré-analyse également le modèle, mais essaie de réutiliser tout ce qui était déjà apparié dans la partie initiale du modèle pour éviter d'avoir à le faire correspondre. Cela peut très bien fonctionner si votre alphabet est petit (par exemple, les bases d'ADN), car vous avez plus de chances que vos modèles de recherche contiennent des sous-modèles réutilisables.

  • Aho-Corasick: nécessite beaucoup de prétraitement, mais le fait pour un certain nombre de modèles. Si vous savez que vous rechercherez les mêmes modèles de recherche encore et encore, c'est bien mieux que l'autre, car vous devez analyser les modèles une seule fois, pas une fois par recherche.

Par conséquent, comme d'habitude dans CS, il n'y a pas de réponse définitive au globalement meilleur. Il s'agit plutôt de choisir le bon outil pour le travail à accomplir.

Une autre note sur votre raisonnement dans le pire des cas: considérez les types de recherches nécessaires pour créer ce pire cas et réfléchissez bien à la pertinence de celles-ci dans votre cas. Par exemple, la complexité la plus défavorable de l'algorithme Boyer-Moore O(mn) découle d'un modèle de recherche et d'un texte qui n'utilisent chacun qu'un seul caractère (comme trouver aaa dans aaaaaaaaaaaaaaaaaaaaa) - avez-vous vraiment besoin d'être rapide pour de telles recherches?

38
Frank

Bien que je sois un peu en retard pour répondre à cette question, mais je pense que Z-Algorithm Est beaucoup plus rapide que tous ses homologues. Sa complexité la plus défavorable est O (m + n) et elle ne nécessite aucun prétraitement du motif/texte. Il est également très facile à coder par rapport aux autres algorithmes.

Cela fonctionne de la manière suivante.

Par exemple, il existe une chaîne S ='abaaba'. Nous devons trouver les valeurs de z(i) pour i=0 to len(S)-1. Avant d'entrer dans l'explication, permettez-moi de commencer par établir quelques définitions.

z(i) = non. de caractères du préfixe de S qui correspond au préfixe de s(i).

s(i) = ith suffixe de S.

Voici les valeurs de s(i) pour s = 'abaaba'.

s(0) = 'abaaba' = S
s(1) = 'baaba'
s(2) = 'aaba'
s(3) = 'aba'
s(4) = 'ba'
s(5) = 'a'

Les valeurs z sont respectivement

z(0) = 6 = length(S)
z(1) = 0
z(2) = 1
z(3) = 3
z(4) = 0
z(5) = 1

Pour une compréhension détaillée de l'algorithme, reportez-vous aux liens suivants.

http://codeforces.com/blog/entry/3107

https://www.youtube.com/watch?v=MFK0WYeVEag

Il faut maintenant O(N) pour trouver toutes les valeurs de z sans surcharge de prétraitement. On se demanderait maintenant comment utiliser cette logique pour faire correspondre le modèle dans un chaîne donnée?

Voyons voir avec un exemple. Motif (P): aba, Texte (T): aacbabcabaad.

Mettez ceci sous la forme P $ T. ($ - tout caractère qui n'apparaît ni dans le motif ni dans le texte. J'arriverai à l'importance de $ Dans un petit moment.)

P$T = aba$aacbabcabaad

Nous connaissons len(P) = 3.

Toutes les valeurs z de P$T Sont

z(0) = 16 = len(P$T)
z(1) = 0
z(2) = 1
z(3) = 0
z(4) = 1
z(5) = 1
z(6) = 0
z(7) = 0
z(8) = 2
z(9) = 0
z(10) = 0
z(11) = 3
z(12) = 0
z(13) = 1
Z(14) = 1
Z(15) = 0

Maintenant, quelle z(i) = len(P). Ans = 11. Notre modèle est donc présent dans Ans-len(P)-1 = 7. -1 Est pour le caractère $.

Maintenant, pourquoi $ Ou tout autre caractère spécial est important. Considérez P = 'aaa' Et T = 'aaaaaaa'. Sans le caractère spécial, toutes les z(i) auront des valeurs incrémentielles. On peut toujours trouver la position du motif dans le texte avec les formules ci-dessous:

Condition: z(i)> = len(P) et Position: Ans-len(P). Mais la condition dans ce cas devient un peu délicate et déroutante. Personnellement, je préfère utiliser la technique des caractères spéciaux.

1
SohamC