Zアルゴリズムとは?仕組みとC++実装例をわかりやすく解説
Zアルゴリズム(Z Algorithm)は、その名の通り「Z配列(Z Array)」を作成することで文字列検索を実現するアルゴリズムです。Z配列のサイズは主文字列(テキスト)と同じであり、各位置から始まる部分文字列のうち、文字列の先頭と一致する最長の長さを格納します。
処理の最初に、パターンと主テキストを、両者に含まれない特殊な記号で連結します。パターンをP、主テキストをTとすると、連結後の文字列は P$T のようになります(ここでは $ がPにもTにも含まれていないものと仮定します)。
このアルゴリズムの計算量は O(m+n) です。m はパターンの長さ、n は主文字列の長さを表します。
入力と出力
Input: Main String: "ABAAABCDBBABCDDEBCABC", Pattern: "ABC" Output: Pattern found at position: 4 Pattern found at position: 10 Pattern found at position: 18
アルゴリズム
fillZArray(conStr, ZArray)
入力 − conStr はパターンと主テキストを連結した文字列です。ZArray には、先頭と一致する最長部分文字列の長さを格納します。
出力 − 値が埋められた ZArray
Begin
n := length of conStr
windLeft := 0 and windRight := 0
for i := 1 to n, do
if i > windRight, then
windLeft := i and windRight := i
while windRight < n AND conStr[windRight-windLeft] =
conStr[windRight], do
increase windRight by 1
done
ZArray[i] := windRight – windLeft
decrease windRight by 1
else
k := i – windLeft
if ZArray[k] < windRight – i +1, then
ZArray[i] := ZArray[k]
else
windLeft := i
while windRight < n AND conStr[windRight-windLeft] =
conStr[windRight], do
increase windRight by 1
done
ZArray[i] := windRight – windLeft
decrease windRight by 1
done
EndzAlgorithm(text, pattern)
入力 − 主テキストと検索対象のパターン
出力 − パターンが見つかった位置
Begin
conStr = concatenate pattern + "$" + text
patLen := length of pattern
len := conStr length
fillZArray(conStr, ZArray)
for i := 0 to len – 1, do
if ZArray[i] = patLen, then
print the location i – patLen – 1
done
EndC++による実装例
#include<iostream>
using namespace std;
void fillZArray(string conStr, int zArr[]) {
int n = conStr.size();
int windLeft, windRight, k;
windLeft = windRight = 0; //initially window size is 0
for(int i = 1; i < n; i++) {
if(i > windRight) {
windLeft = windRight = i; //window size is 0 but position to i
while(windRight < n && conStr[windRight-windLeft] == conStr[windRight]) {
windRight++; //extend the right bound of window
}
zArr[i] = windRight-windLeft;
windRight--;
}else {
k = i-windLeft;
if(zArr[k] < windRight-i+1)
zArr[i] = zArr[k]; //when kth item less than remaining interval
else {
windLeft = i;
while(windRight < n && conStr[windRight - windLeft] == conStr[windRight]) {
windRight++;
}
zArr[i] = windRight - windLeft;
windRight--;
}
}
}
}
void zAlgorithm(string mainString, string pattern, int array[], int *index) {
string concatedStr = pattern + "$" + mainString; //concat with special character
int patLen = pattern.size();
int len = concatedStr.size();
int zArr[len];
fillZArray(concatedStr, zArr);
for(int i = 0; i<len; i++) {
if(zArr[i] == patLen) {
(*index)++;
array[(*index)] = i - patLen -1;
}
}
}
int main() {
string mainString = "ABAAABCDBBABCDDEBCABC";
string pattern = "ABC";
int locArray[mainString.size()];
int index = -1;
zAlgorithm(mainString, pattern, locArray, &index);
for(int i = 0; i <= index; i++) {
cout << "Pattern found at position: " << locArray[i]<<endl;
}
}実行結果
Pattern found at position: 4 Pattern found at position: 10 Pattern found at position: 18
-
フォード・ファルカーソン法とは?グラフの最大流を求めるアルゴリズムを解説
フォード・ファルカーソン(Ford-Fulkerson)アルゴリズムは、与えられたグラフにおいて、始点(ソース)から終点(シンク)までの最大フロー(最大流)を求めるために用いられる古典的なアルゴリズムです。このグラフでは、すべての辺に「容量」が設定されており、ソースとシンクという2つの頂点が指定されます。ソース頂点は外向きの辺のみを持ち、シンク頂点は内向きの辺のみを持つという特徴があります。アルゴリズムが満たすべき制約条件各辺に流れるフローは、その辺に設定された容量を超えてはならない。ソースとシンクを除くすべての頂点において、流入するフローの合計と流出するフローの合計は等しくなければならない。
-
フロイド・ワーシャル法(Floyd–Warshall)とは?全ペア最短経路を求めるアルゴリズムを解説
フロイド・ワーシャル法(Floyd–Warshall algorithm)は、重み付きグラフに対する「全ペア最短経路問題」を解くための代表的なアルゴリズムです。グラフ上のすべての頂点の組み合わせについて最短距離を一括で求め、その結果を「任意のノードから他のすべてのノードへの最小距離」を表す行列(距離行列)として出力します。 アルゴリズムの基本的な考え方 処理の流れは非常にシンプルです。 初期化: 出力用の行列を、グラフのコスト行列(隣接行列)と同じものにします。直接つながっていない頂点間の距離は ∞(無限大)として扱います。 更新: 各頂点 k を「中継地点」として仮定し、「i → k →