Там в обширном обсуждение большого числа алгоритмов строкового поиска по http://www-igm.univ-mlv.fr/~lecroq/string/ с иллюстративным кодом C и ссылкой.
Существует обсуждение одного набора комментариев о стоимости алгоритмов. Один из моментов, который следует учитывать, заключается в том, что если вы можете амортизировать затраты на установку по многим вызовам функции поиска, то высокопроизводительные алгоритмы могут принести вам огромную пользу. Если вы все время будете искать разные строки, это сложнее выиграть.
У меня есть версия алгоритма KMP (Knuth-Morris-Pratt), упакованная для многократного повторного использования одной и той же строки поиска.Заголовок:
/*
@(#)File: $RCSfile: kmp.h,v $
@(#)Version: $Revision: 1.4 $
@(#)Last changed: $Date: 2008/02/02 05:49:34 $
@(#)Purpose: Knuth-Morris-Pratt Search Algorithm
@(#)Author: J Leffler
@(#)Copyright: (C) JLSS 2005,2008
@(#)Product: :PRODUCT:
*/
#ifndef KMP_H
#define KMP_H
#include <stddef.h> /* size_t */
typedef struct kmp_control kmp_control;
/*
** To set up a search (to repeatedly look for the same search string in
** multiple scan strings), use kmp_setsearch(). To start a search on a
** new scan string, use kmp_settarget(). To find the next match of a
** given search string in a given target string, use kmp_search(). Note
** that kmp_setsearch() and kmp_settarget() do not copy the data in the
** source and target strings; the pointers must remain valid You can
** copy kmp_control structures for reuse if desired.
*/
typedef void *(*kmp_malloc)(size_t nbytes);
typedef void (*kmp_free)(void *data);
extern kmp_control *kmp_setsearch(const char *search, size_t schlen);
extern void kmp_settarget(kmp_control *ctrl, const char *target, size_t tgtlen);
extern const char *kmp_search(kmp_control *ctrl);
extern void kmp_release(kmp_control *ctrl);
extern void kmp_setalloc(kmp_malloc mem_alloc, kmp_free mem_free);
#endif /* KMP_H */
Будучи в состоянии определить функции распределения памяти является немного необычным - но мой код часто работает в среде, где распределение памяти не делается с помощью стандартного malloc()
и так далее, и вы должны быть в состоянии для переключения распределителя памяти по требованию. Вы можете игнорировать два typedefs и соответствующую функцию; по умолчанию, конечно, использовать malloc()
и free()
.
Основной код алгоритма KMP приведен с сайта выше, но был изменен, чтобы я мог задать строку поиска один раз, а затем выполнить поиск нескольких целевых строк и т. Д. Свяжитесь со мной (см. Мой профиль) для исходного кода. У меня есть аналогичная структура для кода Бойер-Мура тоже (тот же исходный источник), а также нечувствительный к регистру код Бойер-Мура.
Есть хорошая история войны о strstr()
и исполнении в отличной книге Кернигана и Пайка «The Practice of Programming».
Я сделал некоторые эксперименты - используя копию Библии короля Джеймса (4,8 MB) как обычный текст, и память отображения этого. Для многих поисков (MacOS X 10.6.2/BSD) strstr()
был быстрее, чем KMP или BM. Когда строки росли достаточно долго (примерно 12+ символов), тогда алгоритм BM, наконец, опережал strstr()
. Алгоритм KMP всегда казался намного медленнее.
Мораль?
- Трудно выйти из хорошей библиотеки.
- KMP намного медленнее BM на правдоподобных строках английского языка.
И инфраструктура, которую я устанавливаю вокруг алгоритмов, может быть слишком тяжелой, но альтернатива в исходном коде является механизмом обратного вызова, что создает некоторые проблемы для определения контекста совпадений.
И, strstr() - POSIX - да! http://www.opengroup.org/onlinepubs/9699919799/ –
@Kevin: не находится ли в стандартной библиотеке C, в значительной степени означает, что это также в POSIX? (POSIX заявляет, что одной из целей является «согласование со стандартом ISO/IEC 9899: 1999, включая ISO/IEC 9899: 1999/Cor.2: 2004 (E)») –
@ Майкл: Я думаю, вы правы, что касается содержания «string.h». Я просто пытался укрепить концепцию «стандартной функции библиотеки», которую Джефоми мягко подталкивал, а приветствие для POSIX - это 20-летняя привычка, которую трудно сломать! :) –