OK, quindi non sembro un idiota, dichiarerò il problema / i requisiti in modo più esplicito:
- L'ago (motivo) e il pagliaio (testo da cercare) sono entrambi stringhe con terminazione null in stile C. Non vengono fornite informazioni sulla lunghezza; se necessario, deve essere calcolato.
- La funzione dovrebbe restituire un puntatore alla prima corrispondenza o
NULLse non viene trovata alcuna corrispondenza. - I casi di errore non sono ammessi. Ciò significa che qualsiasi algoritmo con requisiti di archiviazione non costanti (o costanti di grandi dimensioni) dovrà disporre di un caso di fallback per errore di allocazione (e le prestazioni nella cura del fallback contribuiscono quindi alle prestazioni del caso peggiore).
- L'implementazione deve essere in C, anche se una buona descrizione dell'algoritmo (o collegamento a tale) senza codice va bene.
... oltre a ciò che intendo per "più veloce":
- Deterministico
O(n)doven= lunghezza del pagliaio. (Ma potrebbe essere possibile usare idee di algoritmi che sono normalmenteO(nm)(ad esempio rolling hash) se combinati con un algoritmo più robusto per dareO(n)risultati deterministici ). - Non esegue mai (misurabile; un paio di orologi per
if (!needle[1])ecc. Vanno bene) peggio dell'algoritmo ingenuo di forza bruta, specialmente su aghi molto corti che sono probabilmente il caso più comune. (Le spese generali per la preelaborazione pesante incondizionata sono cattive, poiché sta cercando di migliorare il coefficiente lineare per gli aghi patologici a spese dei probabili aghi.) - Dato un ago e un pagliaio arbitrari, prestazioni comparabili o migliori (non meno del 50% di tempo di ricerca più lungo) rispetto a qualsiasi altro algoritmo ampiamente implementato.
- A parte queste condizioni, lascio la definizione di "più veloce" a tempo indeterminato. Una buona risposta dovrebbe spiegare perché consideri l'approccio che stai suggerendo "più veloce".
La mia attuale implementazione è approssimativamente tra il 10% più lenta e 8 volte più veloce (a seconda dell'input) rispetto all'implementazione di glibc di Two-Way.
Aggiornamento: il mio attuale algoritmo ottimale è il seguente:
- Per aghi di lunghezza 1, utilizzare
strchr. - Per aghi di lunghezza 2-4, utilizzare le parole automatiche per confrontare 2-4 byte contemporaneamente come segue: Precaricare l'ago in un numero intero a 16 o 32 bit con spostamenti di bit e far uscire il vecchio byte / nuovi byte dal pagliaio ad ogni iterazione . Ogni byte del pagliaio viene letto esattamente una volta e comporta un controllo rispetto a 0 (fine della stringa) e un confronto a 16 o 32 bit.
- Per aghi di lunghezza> 4, utilizzare l'algoritmo bidirezionale con una tabella di spostamento errata (come Boyer-Moore) che viene applicata solo all'ultimo byte della finestra. Per evitare il sovraccarico di inizializzazione di una tabella da 1kb, che sarebbe una perdita netta per molti aghi di lunghezza moderata, tengo un array di bit (32 byte) che indica quali voci nella tabella di spostamento sono inizializzate. I bit non impostati corrispondono ai valori di byte che non compaiono mai nell'ago, per i quali è possibile uno spostamento della lunghezza dell'ago completo.
Le grandi domande che mi restano in mente sono:
- C'è un modo per utilizzare meglio la tabella dei turni? Boyer-Moore lo sfrutta al meglio scansionando all'indietro (da destra a sinistra) ma Two-Way richiede una scansione da sinistra a destra.
- Gli unici due algoritmi candidati validi che ho trovato per il caso generale (nessuna condizione di memoria esaurita o quadratica) sono la corrispondenza a due vie e stringa sugli alfabeti ordinati . Ma ci sono casi facilmente rilevabili in cui algoritmi diversi sarebbero ottimali? Certamente molti degli algoritmi spaziali
O(m)(dov'è lamlunghezza dell'ago) potrebbero essere usati perm<100circa. Sarebbe anche possibile utilizzare algoritmi che sono quadratici nel caso peggiore se esiste un test facile per aghi che dimostrano chiaramente solo un tempo lineare.
Punti bonus per:
- Puoi migliorare le prestazioni supponendo che l'ago e il pagliaio siano entrambi UTF-8 ben formati? (Con caratteri di diverse lunghezze di byte, la ben formata impone alcuni requisiti di allineamento delle stringhe tra l'ago e il pagliaio e consente spostamenti automatici di 2-4 byte quando si incontra un byte di testa non corrispondente. Ma questi vincoli ti comprano molto / qualunque cosa oltre calcoli del suffisso massimo, buoni spostamenti del suffisso, ecc. ti danno già con vari algoritmi?)
Nota: sono ben consapevole della maggior parte degli algoritmi là fuori, ma non di quanto bene si comportino nella pratica. Ecco un buon riferimento in modo che le persone non continuino a darmi riferimenti sugli algoritmi come commenti / risposte: http://www-igm.univ-mlv.fr/~lecroq/string/index.html
strstrcome qualcosa per dopo, quindi non sono davvero riuscito a leggere correttamente il documento che hai collegato, ma sembra molto promettente. Grazie e scusa per non averti contattato.