http://www-igm.univ-mlv.fr/~lecroq/string/には、多数の文字列検索アルゴリズムに関する広範な説明があり、Cコードとリファレンスが示されています。
アルゴリズムのコストについてのコメントのセットで議論があります。覚えておくべきポイントの1つは、検索関数の多くの呼び出しでセットアップのコストを償却できれば、高性能アルゴリズムが大きなメリットをもたらす可能性があるということです。常にさまざまな文字列を検索する場合、勝つことは困難です。
同じ検索文字列を複数回再利用するためにパッケージ化されたバージョンの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()
などで行われない環境で機能することが多く、必要に応じてメモリアロケータを切り替えることができる必要があります。2つのtypedefと対応する関数は無視してかまいません。もちろん、デフォルト設定はとを使用malloc()
しfree()
ます。
基本的なKMPアルゴリズムコードは上記のサイトからのものですが、検索文字列を一度設定してから複数のターゲット文字列などを検索できるように変更されました。ソースコードについては私に連絡してください(私のプロファイルを参照)。ボイヤームーアコード(同じ元のソース)にも同様の構造があり、大文字と小文字を区別しないボイヤームーアコードもあります。
strstr()
カーニハンとパイクの優れた本「プログラミング作法」には、優れた戦争物語とパフォーマンスがあります。
私はいくつかの実験を行いました-プレーンテキストとして欽定訳聖書(4.8 MB)のコピーを使用し、それをメモリマッピングしました。多くの検索では、(MacOS X 10.6.2 / BSD)strstr()
はKMPまたはBMよりも高速でした。文字列が十分に長くなると(約12文字以上)、BMアルゴリズムは最終的にペースを上回りstrstr()
ました。KMPアルゴリズムは常にはるかに遅いように見えました。
道徳?
- 優れたライブラリを追い越すことは困難です。
- KMPは、もっともらしい英語の文字列ではBMよりもはるかに低速です。
また、アルゴリズムの周りに配置したインフラストラクチャは重すぎる可能性がありますが、元のコードの代替手段はコールバックメカニズムであり、一致のコンテキストを決定するためのいくつかの問題があります。