OK, also ich klinge nicht wie ein Idiot. Ich werde das Problem / die Anforderungen expliziter darlegen:
- Nadel (Muster) und Heuhaufen (zu durchsuchender Text) sind nullterminierte Zeichenfolgen im C-Stil. Es werden keine Längeninformationen bereitgestellt. Bei Bedarf muss es berechnet werden.
- Die Funktion sollte einen Zeiger auf die erste Übereinstimmung zurückgeben oder
NULL
wenn keine Übereinstimmung gefunden wird. - Fehlerfälle sind nicht zulässig. Dies bedeutet, dass jeder Algorithmus mit nicht konstanten (oder großen konstanten) Speicheranforderungen einen Fallback-Fall für einen Zuordnungsfehler haben muss (und die Leistung in der Fallback-Pflege dadurch zur Worst-Case-Leistung beiträgt).
- Die Implementierung soll in C erfolgen, obwohl eine gute Beschreibung des Algorithmus (oder der Verknüpfung mit einem solchen) ohne Code ebenfalls in Ordnung ist.
... sowie was ich mit "am schnellsten" meine:
- Deterministisch
O(n)
won
= Heuhaufenlänge. (Es kann jedoch möglich sein, Ideen von Algorithmen zu verwenden, die normalerweise verwendet werdenO(nm)
(z. B. rollierender Hash), wenn sie mit einem robusteren Algorithmus kombiniert werden, um deterministischeO(n)
Ergebnisse zu erzielen .) - Niemals
if (!needle[1])
schlechter (messbar; ein paar Uhren usw. sind in Ordnung) schlechter als der naive Brute-Force-Algorithmus, insbesondere bei sehr kurzen Nadeln, die wahrscheinlich der häufigste Fall sind. (Der bedingungslose hohe Vorverarbeitungsaufwand ist schlecht, ebenso wie der Versuch, den linearen Koeffizienten für pathologische Nadeln auf Kosten wahrscheinlicher Nadeln zu verbessern.) - Bei einer beliebigen Nadel und einem beliebigen Heuhaufen ist die Leistung vergleichbar oder besser (nicht schlechter als 50% längere Suchzeit) als bei jedem anderen weit verbreiteten Algorithmus.
- Abgesehen von diesen Bedingungen lasse ich die Definition von "schnellstem" unbefristet. Eine gute Antwort sollte erklären, warum Sie den von Ihnen vorgeschlagenen Ansatz als "am schnellsten" betrachten.
Meine aktuelle Implementierung läuft ungefähr 10% langsamer und 8-mal schneller (abhängig von der Eingabe) als die Implementierung von Two-Way von glibc.
Update: Mein aktueller optimaler Algorithmus lautet wie folgt:
- Verwenden Sie für Nadeln der Länge 1
strchr
. - Verwenden Sie für Nadeln der Länge 2-4 Maschinenwörter, um 2-4 Bytes gleichzeitig wie folgt zu vergleichen: Laden Sie die Nadel in einer 16- oder 32-Bit-Ganzzahl mit Bitverschiebungen vor und wechseln Sie bei jeder Iteration alte Bytes aus / neue Bytes aus dem Heuhaufen . Jedes Byte des Heuhaufens wird genau einmal gelesen und es wird eine Prüfung gegen 0 (Ende der Zeichenfolge) und ein 16- oder 32-Bit-Vergleich durchgeführt.
- Verwenden Sie für Nadeln mit einer Länge> 4 den Zwei-Wege-Algorithmus mit einer schlechten Verschiebungstabelle (wie Boyer-Moore), die nur auf das letzte Byte des Fensters angewendet wird. Um den Aufwand für die Initialisierung einer 1-KB-Tabelle zu vermeiden, der für viele Nadeln mittlerer Länge einen Nettoverlust darstellen würde, behalte ich ein Bit-Array (32 Byte) bei, das markiert, welche Einträge in der Verschiebungstabelle initialisiert werden. Nicht gesetzte Bits entsprechen Bytewerten, die niemals in der Nadel erscheinen, für die eine Verschiebung um die gesamte Nadellänge möglich ist.
Die großen Fragen, die mir noch im Kopf bleiben, sind:
- Gibt es eine Möglichkeit, den schlechten Schichttisch besser zu nutzen? Boyer-Moore nutzt es am besten, indem er rückwärts (von rechts nach links) scannt, für Two-Way ist jedoch ein Scan von links nach rechts erforderlich.
- Die einzigen zwei brauchbaren Kandidatenalgorithmen, die ich für den allgemeinen Fall gefunden habe (keine Speichermangel- oder quadratischen Leistungsbedingungen), sind Zweiwege- und String-Matching für geordnete Alphabete . Aber gibt es leicht erkennbare Fälle, in denen unterschiedliche Algorithmen optimal wären? Sicherlich könnten viele der
O(m)
(wom
ist die Nadellänge) im Weltraum-Algorithmen fürm<100
oder so verwendet werden. Es wäre auch möglich, Algorithmen zu verwenden, die im schlimmsten Fall quadratisch sind, wenn es einen einfachen Test für Nadeln gibt, die nachweislich nur eine lineare Zeit benötigen.
Bonuspunkte für:
- Können Sie die Leistung verbessern, indem Sie davon ausgehen, dass Nadel und Heuhaufen beide gut geformte UTF-8 sind? (Bei Zeichen mit unterschiedlichen Bytelängen stellt die Formgebung einige Anforderungen an die Ausrichtung der Zeichenfolge zwischen Nadel und Heuhaufen und ermöglicht automatische Verschiebungen von 2 bis 4 Bytes, wenn ein nicht übereinstimmendes Kopfbyte auftritt Maximale Suffixberechnungen, gute Suffixverschiebungen usw. geben Ihnen bereits verschiedene Algorithmen?)
Hinweis: Mir sind die meisten Algorithmen bekannt, nur nicht, wie gut sie in der Praxis funktionieren. Hier ist eine gute Referenz, damit mir die Leute nicht immer Referenzen zu Algorithmen als Kommentare / Antworten geben: http://www-igm.univ-mlv.fr/~lecroq/string/index.html
strstr
als etwas für später hinterlassen , sodass ich nicht wirklich dazu gekommen bin, das von Ihnen verlinkte Papier richtig zu lesen, aber es klingt sehr vielversprechend. Vielen Dank und Entschuldigung, dass Sie sich nicht bei Ihnen gemeldet haben.