OK, donc je n'ai pas l'air d'un idiot, je vais énoncer le problème / les exigences plus explicitement:
- L'aiguille (motif) et la botte de foin (texte à rechercher) sont toutes deux des chaînes de style C à terminaison nulle. Aucune information de longueur n'est fournie; si nécessaire, il doit être calculé.
- La fonction doit renvoyer un pointeur sur la première correspondance ou
NULL
si aucune correspondance n'est trouvée. - Les cas d'échec ne sont pas autorisés. Cela signifie que tout algorithme avec des exigences de stockage non constantes (ou grandes constantes) devra avoir un cas de secours en cas d'échec d'allocation (et les performances dans le traitement de secours contribuent ainsi aux performances les plus défavorables).
- L'implémentation doit être en C, bien qu'une bonne description de l'algorithme (ou un lien vers un tel algorithme) sans code convienne également.
... ainsi que ce que j'entends par «plus rapide»:
- Déterministe
O(n)
oùn
= longueur de la botte de foin. (Mais il peut être possible d'utiliser des idées d'algorithmes qui sont normalementO(nm)
(par exemple, le hachage roulant) s'ils sont combinés avec un algorithme plus robuste pour donner desO(n)
résultats déterministes ). - Ne fonctionne jamais (de manière mesurable; quelques horloges pour
if (!needle[1])
etc. sont bien) pire que l'algorithme de force brute naïve, en particulier sur des aiguilles très courtes qui sont probablement le cas le plus courant. (Les frais généraux de prétraitement lourds inconditionnels sont mauvais, tout comme essayer d'améliorer le coefficient linéaire pour les aiguilles pathologiques au détriment des aiguilles probables.) - Avec une aiguille et une botte de foin arbitraires, des performances comparables ou meilleures (pas moins de 50% de temps de recherche plus long) par rapport à tout autre algorithme largement implémenté.
- En dehors de ces conditions, je laisse ouverte la définition de «plus rapide». Une bonne réponse devrait expliquer pourquoi vous considérez l'approche que vous suggérez comme «la plus rapide».
Mon implémentation actuelle est à peu près 10% plus lente et 8 fois plus rapide (selon l'entrée) que l'implémentation de la glibc de Two-Way.
Mise à jour: Mon algorithme optimal actuel est le suivant:
- Pour les aiguilles de longueur 1, utilisez
strchr
. - Pour les aiguilles d'une longueur de 2 à 4, utilisez des mots machine pour comparer 2 à 4 octets à la fois comme suit: préchargez l'aiguille dans un entier de 16 ou 32 bits avec décalages de bits et faites défiler l'ancien octet / les nouveaux octets à partir de la botte de foin à chaque itération . Chaque octet de la meule de foin est lu exactement une fois et subit une vérification par rapport à 0 (fin de chaîne) et une comparaison 16 ou 32 bits.
- Pour les aiguilles de longueur> 4, utilisez l'algorithme bidirectionnel avec une mauvaise table de décalage (comme Boyer-Moore) qui n'est appliquée qu'au dernier octet de la fenêtre. Pour éviter la surcharge de l'initialisation d'une table de 1 ko, ce qui serait une perte nette pour de nombreuses aiguilles de longueur moyenne, je garde un tableau de bits (32 octets) marquant les entrées de la table de décalage qui sont initialisées. Les bits non définis correspondent à des valeurs d'octets qui n'apparaissent jamais dans l'aiguille, pour lesquelles un décalage complet de la longueur de l'aiguille est possible.
Les grandes questions qui restent dans mon esprit sont:
- Existe-t-il un moyen de mieux utiliser la mauvaise table de travail? Boyer-Moore en fait le meilleur usage en balayant vers l'arrière (de droite à gauche), mais bidirectionnel nécessite un balayage de gauche à droite.
- Les deux seuls algorithmes candidats viables que j'ai trouvés pour le cas général (pas de mémoire insuffisante ou de conditions de performances quadratiques) sont la correspondance bidirectionnelle et de chaîne sur les alphabets ordonnés . Mais existe-t-il des cas facilement détectables où différents algorithmes seraient optimaux? Il est certain que beaucoup d' algorithmes spatiaux
O(m)
(oùm
est la longueur de l'aiguille) pourraient être utilisés pourm<100
environ. Il serait également possible d'utiliser des algorithmes qui sont quadratiques dans le pire des cas s'il existe un test facile pour les aiguilles qui ne nécessitent que du temps linéaire.
Points bonus pour:
- Pouvez-vous améliorer les performances en supposant que l'aiguille et la botte de foin sont toutes deux bien formées en UTF-8? (Avec des caractères de longueurs d'octets variables, la bonne forme impose certaines exigences d'alignement des chaînes entre l'aiguille et la botte de foin et permet des décalages automatiques de 2 à 4 octets lorsqu'un octet de tête incompatible est rencontré. Mais ces contraintes vous achètent-elles beaucoup / rien au-delà de ce les calculs de suffixes maximaux, les bons décalages de suffixes, etc. vous donnent déjà divers algorithmes?)
Remarque: je connais bien la plupart des algorithmes, mais pas leur performance dans la pratique. Voici une bonne référence pour que les gens ne continuent pas à me donner des références sur les algorithmes sous forme de commentaires / réponses: http://www-igm.univ-mlv.fr/~lecroq/string/index.html
strstr
chose et j'ai laissé de nouvelles améliorations pour plus tard, donc je n'ai pas vraiment lu le papier que vous avez lié, mais cela semble très prometteur. Merci et désolé de ne pas vous avoir répondu.