CS 6.006 Lecture 9 Table Doubling, Karp-Rabin を見る
表記:
n: テーブルに入っている要素のサイズ
m: テーブルのサイズ
とする。
わかったこと
Table Shrinkingでは、縮めるタイミングとサイズの係数をずらすのが良い
テーブルの要素の追加・削除を繰り返し、n = m/2となったタイミングでテーブルを縮めるとする。 このとき、m = m/2になるように縮めてしまうと、n = mとなり、
テーブルのサイズ = テーブル内の要素数
となる。ここで、次に要素が追加された場合、Table Doublingが起こり、m = 2mのサイズをもう一度作る。このとき、O(2m)の計算量がかかり、非効率。
そもそも、テーブルのサイズ = テーブル内の要素数
はテーブルがギリギリの状態であり、よくない。これを避けるためには、
n=m/4となったタイミングでm = m/2 になるように縮めればよい。こうすると、ギリギリの状態をさけることができる。
Karp-Rabin アルゴリズム(Rolling Hash)では、modによる比較的単純なhashを使う
文字列検索のアルゴリズム。 文字列のなかから文字列があるかどうかを返す時、 以下のようなアルゴリズムを用いる。(参考: Rabin–Karp algorithm - Wikipedia)
function RabinKarp(string s[1..n], string pattern[1..m]) hpattern := hash(pattern[1..m]); for i from 1 to n-m+1 hs := hash(s[i..i+m-1]) if hs = hpattern if s[i..i+m-1] = pattern[1..m] return i return not found
hashを毎回計算するときは、sha256のような複雑なものを使うと思っていたが、実際には、 それだと計算量が高いので、文字列を数字に変換したものをつなげてmod p をとることでhashを計算する。 ここで、pを素数にしておくと、inverse prime numberによるテクニックが使えて、大きな数に対しても比較的高速にmodが計算できる。 (参考: Modular multiplicative inverse - Wikipedia)
注意点 1.
上にのせたコードについて
s[i..i+m-1]
の部分は、純粋にpythonのリストを使ってしまうとかかってしまうが、, s[i+1], ...]を数字に変換したものを横に繋げた数字を保持しておくことで、加減乗除()でが更新できる。
文字列を数字に変換するときは、文字を0~255で表現すればよい。char型の文字は 1Byte = 8bit = 256通りの文字を表すという事実を知っていれば、 普通出てくるような文字(キリル文字とか漢字は除く)は0~255のどれかで表すことができる。