C++で文字列照合のためのBitapアルゴリズムを実装する方法
これは、文字列照合のためのBitapアルゴリズムを実装したC++プログラムの解説です。Bitapアルゴリズムは、指定されたテキストの中に、与えられたパターンと「ほぼ一致」する部分文字列が含まれているかどうかを判定します。ここでの「近似一致」はレーベンシュタイン距離(編集距離)に基づいて定義されており、部分文字列とパターンとの距離が許容値k以内であれば、両者は一致しているとみなされます。
このアルゴリズムは、まずパターンの各要素に対応する1ビットからなるビットマスクの集合を事前に計算します。これにより、処理の大部分を極めて高速なビット演算だけで実行できる点が大きな特徴です。Bitapアルゴリズムは「Shift-Or法」「Baeza-Yates–Gonnet法」とも呼ばれ、あいまい検索(ファジーマッチング)の分野で広く活用されています。
アルゴリズム
Begin
テキスト文字列tとパターンpを入力として受け取る。
関数bitmap_search()を定義する。引数はテキストtとパターンp:
ビット配列Aを初期化する。
パターンビットマスクp_mask[300]を初期化する。
ビット配列を更新する。
for i = 0 to 299
p_mask[i] = ~0
for i = 0 to m-1
p_mask[p[i]] &= ~(1L << i);
for i = 0 to t.length()-1
A |= p_mask[t[i]];
A <<= 1;
if ((A & (1L << m)) == 0
return i - m + 1
return -1
End
サンプルコード
#include <string>
#include <map>
#include <iostream>
using namespace std;
int bitmap_search(string t, string p) {
int m = p.length();
long p_mask[300];
long A = ~1;
if (m == 0)
return -1;
if (m >63) {
cout<<"Pattern is too long!";//パターンが長すぎる場合
return -1;
}
for (int i = 0; i <= 299; ++i)
p_mask[i] = ~0;
for (int i = 0; i < m; ++i)
p_mask[p[i]] &= ~(1L << i);
for (int i = 0; i < t.length(); ++i) {
A |= p_mask[t[i]];
A <<= 1;
if ((A & (1L << m)) == 0)
return i - m + 1;
}
return -1;
}
void findPattern(string t, string p) {
int position = bitmap_search(t, p);//bitmap_search関数の戻り値で位置を初期化
if (position == -1)
cout << "\nNo Match\n";
else
cout << "\nPattern found at position : " << position;
}
int main(int argc, char **argv) {
cout << "Enter Text:\n";
string t;
cin >>t;
cout << "Enter Pattern:\n";
string p;
cin >>p;
findPattern(t, p);
}
実行結果
Enter Text: Tutorialspoint Enter Pattern: point Pattern found at position : 9
上記の実行例では、テキスト「Tutorialspoint」の中からパターン「point」を検索し、位置9(先頭を0として数えるインデックス)で発見できたことが出力されています。パターンがテキスト内に存在しない場合は「No Match」と表示されます。
なお、この実装では64ビットのlong型をビット配列として使用しているため、扱えるパターンの最大長は63文字までに制限されます。パターンが63文字を超えると「Pattern is too long!」と表示され、検索は失敗します。より長いパターンを扱いたい場合は、複数のワードに分割して処理するなどの拡張が必要になります。
-
C++での文字列変換のインプレースアルゴリズム:サイクルリーダー法によるO(n)実装
与えられた文字列に対して、偶数番目の要素をすべて文字列の末尾へ移動する問題を考えます。ただし、要素を移動する際には、偶数番目・奇数番目それぞれのグループ内での相対的な順序を維持しなければなりません。 例えば、入力文字列が「a1b2c3d4e5f6g7h8i9j1k2l3m4」である場合、「abcdefghijklm1234567891234」へ、追加メモリを使わないインプレース処理かつ O(n) の時間計算量で変換します。 アルゴリズムの手順 サイズが 3k + 1 の形となる最大の接頭辞部分文字列を切り出します。このステップでは、3k + 1 が n(文字列の長さ)以下となる最大の非負整
-
C++で学ぶ最適ページ置換アルゴリズム(OPT)の実装方法 ― ヒット数とミス数の求め方
ページ参照列とフレーム数が与えられたとき、最適ページ置換アルゴリズム(Optimal Page Replacement Algorithm)を用いてメモリブロックにページを割り当てた場合のヒット数とミス数を求めるのが本記事の目的です。 最適ページ置換アルゴリズムとは? ページ置換アルゴリズムとは、「どのメモリページを入れ替えるか」を決定するアルゴリズムのことです。その中でも最適ページ置換アルゴリズムは、「今後最も長い間参照されないページ」を置き換え対象として選ぶ方式です。 理論上は最もミス(ページフォールト)が少ない理想的なアルゴリズムですが、将来のページ参照を正確に予測することは現実には不可