RKによる文字列照合


関数名
rkMatch  ラビン-カープによる文字列照合アルゴリズム
rkHash   照合パターンのハッシュ関数値
形式
文字列照合
    char *rkMatch(char *text, int len, int patlen,
          unsigned long patHash, unsigned long dm);

照合パターンのハッシュ関数値
    unsigned long rkHash(unsigned long *dm, char *pattern, int patlen);
引数
文字列照合関数において
    text     (入力)テキスト
    len      (入力)テキストの長さ
    patlen   (入力)照合パターンの長さ
    patHash  (入力)照合パターンのハッシュ関数値
    dm       (入力)256m-1 % q の値

照合パターンのハッシュ関数値の関数において
    dm       (入出力)256m-1 % q の値
    pattern  (入力)照合パターン
    patlen   (入力)照合パターンの長さ
関数値
文字列照合関数について
    照合パターンがテキストから見つかった場合はそのポインタ、
    見つからなかった場合は 0 (NULL)。

照合パターンのハッシュ関数値の関数において
    照合パターンのハッシュ関数値
注意事項
rkPattern() を呼び出して照合パターンのハッシュ関数値を算出した後、
文字列照合関数 rkMatch() を利用すること。
用例(rkMatch-test.c

プログラム(rkMatch.c
#define Q     33554393L   /* prime number */
#define LOG2D 8           /* 2^8 = 256 */

unsigned long rkHash(unsigned long *dm, char *pattern, int patlen)
{
    int      i;
    unsigned long h1;

    for (i = 1, *dm = 1; i < patlen; i++)
        *dm = (*dm << LOG2D) % Q;
    for (i = 0, h1 = 0; i < patlen; i++)
        h1 = ((h1 << LOG2D) + pattern[i]) % Q;
    return h1;
}

char *rkMatch(char *text, int len, int patlen,
     unsigned long patHash, unsigned long dm)
{
    int      i;
    char     *textEnd;
    unsigned long h2;

    if (patlen == 0)  return text;
    if (len < patlen) return NULL;

    for (i = 0, h2 = 0; i < patlen; i++)
        h2 = ((h2 << LOG2D) + text[i]) % Q;

    textEnd = text + (len - patlen) + 1;
    while (text != textEnd) {
        if (h2 == patHash) return text;
        h2 = (h2 + (Q << LOG2D) - *text * dm) % Q;
        h2 = ((h2 << LOG2D) + *(text + patlen)) % Q;
        text++;
    }
    return NULL;
}
説明
テキストに現れる、長さ m (mは照合パターンの長さ)の文字列す べてに対してハッシュ関数の値を計算し、その値が照合パターンのそれ と一致するかどうかを調べることで文字列照合を行う方法である。ラビ ンとカープによる。ハッシュ関数に h(k) = k mod q を使う。ここに、 q(ハッシュ表の大きさ)は大きな素数である。ハッシュ表は実際に用意 する必要がないことから q として非常に大きな素数を選ぶことができる。

この方法ではまず照合パターンのハッシュ関数値 h1 を、つぎにテキスト 最初の m 文字分のハッシュ関数値 h2 を計算する。そのあとテキスト上 の照合開始位置を右にずらしながら、ハッシュ関数値を漸化式によって計 算し、その値と h1 との比較を繰り返す。

この方法の計算量 O(m+n) である。違う文字列が同じハッシュ関数値をもつ ことは理論的には否定できないが、大きな素数 q を選べば実用上その問題 を無視してよい。

関連関数
素朴法による文字列照合KMP法による文字列照合BM法による文字列照合正規表現による文字列照合