文字列の論理構造:0個以上の文字の限定されたシーケンス。
文字列の長さ:文字列に含まれる文字数。
空の文字列:長さが0の文字列。 ""と表記されます。
空でない文字列は通常、次のように記述されます:S = "" s1 s2 ...... sn "ここで、Sは文字列名、二重引用符は区切り文字、二重引用符が原因の部分は文字列値、si(1≤i≤n)はa任意の文字。
サブストリング:ストリング内の任意の連続した文字で構成されるサブシーケンス。
メイン文字列:サブ文字列を含む文字列。
サブストリング位置:メインストリング内のサブストリングの最初の文字のシーケンス番号。文字列の
格納構造
シーケンス文字列:配列を使用して文字シーケンスを文字列に格納します。
文字列の長さを表現する方法は?
1.変数を使用して、文字列の実際の長さを表します。
2.文字列の末尾に、文字列の終端を示す文字列に表示されない特殊文字を格納します。
3.配列のユニット0を使用して文字列の長さを格納し、ユニット1から開始して文字列値を格納します。
リンクされた文字列:リンクされたストレージ構造を使用して文字列を保存します。
パターンマッチング
メイン文字列S = "s1s2 ... sn"とパターンT = "t1t2 ... tm"が与えられた場合、SでTを見つけるプロセスはパターンマッチングと呼ばれます。
BF(ブルートフォース)アルゴリズムの
基本的な考え方:メイン文字列Sの0番目の文字とパターンTの0番目の文字から開始し、それらが等しい場合は、2つの後続の文字を比較し続けます。それ以外の場合は、メイン文字列Sから最初の文字はパターンTの0番目の文字と比較され始め、Tのすべての文字が比較されて一致が成功したことを示すまで、またはSのすべての文字が比較されて一致が失敗したことを示すまで、上記のプロセスが繰り返されます。
注:パターンマッチングプロセスは複数のパスに一致する必要があり、各パスを数回比較する必要があります。1.文字列Sと文字列Tに開始添字iとjを設定します。
2. SまたはTのすべての文字が比較されるまでループします;
2.1。S [i] == T [j]の
場合、SとTの次の文字の比較を続けます; 2.2。それ以外の場合、iおよびj(i = i-j + 1、j = 0)、次の比較の準備;
3. Tのすべての文字が比較されると、一致が成功し、一致する開始比較インデックス(ij)が返されます。それ以外の場合、一致は失敗して返されます-1;
int BF(char S[ ], char T[ ])
{
i=0; j=0;
while(i<S.Length()&&j<T.length())
{
if(S[i]==T[j]) {
i++;
j++;
}
else{
i=i-j+1;
j=0;
}
}
if(j>=T.length())
return (i-j);
else
return -1;
}
文字列Sの長さがnで、文字列Tの長さがmであるとします。一致が成功した場合、2つの極端なケースが考慮されます:(
1)最良のケース:一致しないすべてが文字列Tの最初の文字で発生します。
すべての成功した一致にはn-m + 1の可能性があります。
(2)最悪の場合:文字列Tの最後の文字で一致がすべて発生します。
すべての成功した一致にはn-m + 1の可能性があります。
時間の複雑さ:O(n * m)
KMP(Knuth–Morris–Pratt)アルゴリズム
BFアルゴリズムの時間パフォーマンスが低いのはなぜですか?
各一致が失敗した場合、多くのバックトラックがあり、部分一致の結果は利用されません。
マッチが失敗したときにメイン文字列をバックトラックしないようにするにはどうすればよいですか?
メインストリングはバックトラックしません。モードは右側にスライドする必要があります。(iは移動せず、j> = 0の位置は次の比較に進みます)。
iに戻る必要はありません。パターンが右にスワイプされる新しい比較の開始点k。kはパターン文字列Tにのみ関連しています。
令k = next[j],则:
next[j]={-1 当j=0时
max {k|0<k<j且T0…Tk-1=Tj-(k-1) …Tj-1}
0 其他情况}
次[j]は、モードTでの最大かつ同じ接頭辞部分文字列と左部分文字列(真の部分文字列)の長さを表します。
next [j]のアルゴリズム分析:
k = next [j-1](next []で定義されているとおり:t0t1 ... tk-1 = tj-k ... tj-3tj-2)
1. t == [k ] t [j-1]またはk ==-1(同じ長さのプレフィックス部分文字列と左部分文字列はありません)、次にt0t1 ... tk-1tk = tj-k ... tj-3tj-2tj-1なので、次の[j ] = k + 1、next [j]計算は終了します。
それ以外の場合は、t0t1 ... tk、k = next [k]の最も長い左部分文字列を見つけ、1に移動して実行を続行します。
KMPアルゴリズムは疑似コードで記述されています
1.文字列Sと文字列Tにそれぞれ開始インデックスiとjを設定します
2. Sの残りの文字の長さがTの長さより短くなるか、Tのすべての文字が比較されるまでループします
2.1 、S [i] == T [j]の場合、SとTの次の文字の比較を続行します。それ以外の場合は、
2.2の場合、jを次の[j]の位置まで右にスライドします。つまり、j = next [j]、
jの場合は2.3 = -1、次にiとjにそれぞれ1を追加して、次の比較の準備をします;
3. Tのすべての文字を比較すると、一致する開始インデックスが返され、それ以外の場合は-1が返されます。
int KMP_FindPat(char *s, char *t,int *next) {
int i=0,j=0,k;
while(s[i]!='\0' && t[j]!='\0') {
if(j==-1||s[i]==t[j]) {
i++;
j++;
}
else
j=next[j];
}
if(t[j]=='\0')
return i-j;
else
return -1;
}
時間の複雑さ:O(n + m)