グラフィックKMPアルゴリズム

はじめに:私はあなたがすでにKMPアルゴリズムのいくつかの知識を持っているかもしれ開くためにポイントと信じてこの記事では、当然のことながら、私たちは今日KMPアルゴリズムが何であるかについて詳しく説明しなければならないものを理解していなかったので、あなたが本当の意味で、このアルゴリズムの動作を理解していることアプリケーション;

まず、KMPアルゴリズムとは何か

  • KMPアルゴリズムは、(クヌース - モリス - プラット)と呼ばれる改良された文字列照合アルゴリズムであり、最初の外観は間違いなく、文字列マッチングにスプリングをもたらす、DEKnuth、JHMorrisとVRPrattによって提案されました。
  • 実際には、KMPアルゴリズムの本質は、リンクの不一致の場合には、すぐに頭を開始していないだろう、マッチング処理である最大の公共の現在のサブ文字列マッチング部からパターン文字列マッチングしますが、文字列のパターン文字列からそう破棄、我々は情報の使用が既に一致したようにしたいされ始め、不要なプロセス、最小一致時刻と一致します。道は少し不明瞭スピーチで、または以下の説明を参照してください。
  • すべてのアルゴリズムの誕生は、私たちのニーズを満たすように設計され、KMPはKMPアルゴリズムは、古典的なシナリオであるように、次の要件としても例外は、ではありません。
    現在、私は、文字列str、および別の文字列のパターンを持っている(私たちはモードと呼びましょう文字列のこと)
    私がお願いしたいのは、str内のパターンがあるかどうか、またはパターンがstrの中で何度も登場しました。

第二に、暴力的な試合

需要の顔が最初にこのアルゴリズム(BF)マッチ暴力を思うだろうもKMPアルゴリズムのジュニアパートナーと接触していなかった最も確かに上記の提起しました。何が、このアイデアは、何よりも暴力的な試合である定義し
、各サイクルの過程で再びPattern.length - 。、それは私が、その後str.lengthに0からトラバースされ、I番目の文字を指すをstr私は0 =なお、変数jは、jの値は各層J発現STR [I + J]は、このサイクル場合、それは、pattern.lengthに0であり、パターンのj番目の要素の点によって表される定義さ==それが成功したマッチがあるように、すべてが終わっ横断全体の外側のループは、彼らはSTRにはパターンが存在しないと判断され、成功を一致しませんでしまでのパターン[j]は、設定されています。
ほとんどの人が最初に考える方法でなければなりませんコード、を見てください:

bool BF(string str,string pattern){
    int i=0,j=0;
    while(i < str.length() && j < pattern.length()){
        if(str[i] == pattern[j]){
            i++;
            j++;
        }else{
            i = i-j+1;
            j=0;
        }
    }
    return j == pattern.length();
}

このアルゴリズムの実装は、以下の図を示すために使用することができます:
ここに画像を挿入説明
それは簡単、そして粗で、このアルゴリズムの利点は簡単ですが、そこに可能性が間違って漏れないですが、それは最も致命的な一時費用の欠点である高すぎ、A直ちにO(M * N)は、Mの時間複雑さを得ることができるコード解析を見て、 nは長さ及びSTR、STRのパターンとパターンの長さが大きい場合、このアルゴリズムの使用は、間違いなく災害では今日のヒーローKMPアルゴリズムであるパワーでビッグデータ今日、我々は、よりエレガントかつ効率的なアルゴリズムを探求したいです、。

三、KMPアルゴリズム

  • :KMPアルゴリズムのアルゴリズムを理解するために、我々はまず、次の例を見て、私はスマート、あなたがすぐに理解していることを信じて、何時間文字列の接頭辞と接尾辞、接頭辞と接尾辞の文字列の概念を有効にする必要があります
    。例:文字列=「ABAB」を
接頭辞 サフィックス 長さ
A B 1
から から 2
ABA 3

私たち人間の脳は、この図の下に見、2つの文字列を一致させるためにどのように処理するには、一目何時に接頭辞と接尾辞文字列の結果の例を見て、今、私たちは、人々が何を考えているシミュレートしたい:
ここに画像を挿入説明
私たちがすることができます私たちは現象と一致するように失敗したとき、それは右、そして我々はモードにできるようになりますではありませんが、我々は接頭辞文字列が既にマッチングパターン文字列のABAに成功している参照、Cの試合で初めて見ます接頭ABA移動あなたはコアが情報の使用は、すでに以前に一致したされて参照して、次の最良を見つけるためにそれを使用することができ、時間のような無駄を動作させるための必要性を排除するゼロではない一致する文字列のABAのペアリング、へ開始位置、
我々は島式をプッシュするために見ることができ、Pは最初のコミュニティストリングパターンは、文字列マッチングがTである、私は現在のインデックスのために、jは現在の添字Pは、T:
不一致が発生した場合:

1は、私たちはそのP [0 jまでを- 1]知っ== T [I - J 1 -私へ]この表現は、それが確立されている
ここに画像を挿入説明
理解していなかった式を見てもよいが、あなたはクリアするには、以下の図を空想する必要があります。

2、その後、我々は再び、この分析が正常に一致した文字列(緑の期間)に行くの構造:
:私たちは、それは非常に奇妙な現象があることがわかります
ここに画像を挿入説明
接頭辞文字列の接尾辞の後、あるここに同じ場所を持っている必要があります最大の公共の文字列の概念を導入

接頭辞 サフィックス 共通接頭辞と接尾辞の最大長
A ^ ^ 0
AA A A 1
ABA これはあります これはあります 2
ABCABC ABC ABC 3

私たちが式を導くことができるので、今、私たちは、文字列がある前部Pが正常に一致したことを、文字列を知っている
私たちは、共通の接頭辞と接尾辞の文字列の最大長はk個あると仮定した場合、その後、 - [1 jに0] Pない
P [J == - [1 kに0] P - K J-1];
図は:
ここに画像を挿入説明

図3は、トップと2は、私たちが来るだろう、見て、それらを一緒に置くことができる式を押し出さ:

(1)P [0 jへ- 1]以来[I == T - J Iに- 1]
(2)及びP以来[0 kに- 1] == P [J - K -1 Jへ]
( 3)(1)(2)である:T - == P [K-1に0] [I I -1 K]は

まだ見ることができます理解していない:
ここに画像を挿入説明
4を、導出原理の最初の3つのステップを通じてどのように我々はコンピュータプログラムでそれを達成するか、法律を見つけ、その後、知ってもらうためにすべきですか?ではない、実際には、この方法では、我々はスタート地点からユニークで異なっている私は今戻って、あなたを知らない、それは暴力法に来るiとjが同じではありませんリンクを不整合の変化であり、
どのように異なる方法:我々は失われたBF(暴力)ゼロ処理はターンjの中で実施されると装備した場合、私は彼らが部分文字列を一致した頭に戻って行きました。
そして実際、ここKMPアルゴリズムのミスマッチで、彼はjがゼロに設定されますが、Kとなり、kはP [0 J-1へ]共通接頭辞と接尾辞のこのセグメントの最大の長さですないです。私たちならばK缶P(パターン・モード・ストリング)の全ての位置がまだライン上にないという文字列に必要であること?私たちは、kの各値に対して、この位置を保持するという名前の次の容器を使用できるように
[I]次の値がKのj番目の位置P(パターン文字列パターン)のように表すことができる。
その後、我々は最初に缶読んでプログラムを書きます:

bool BF(string str,string pattern){
    int i=0,j=0;
    while(i < str.length() && j < pattern.length()){
        if(str[i] == pattern[j]){
            i++;
            j++;
        }else{
        	j = next[j]				// j变next的值,而i不变
        }
    }
    return j == pattern.length();
}

いくつかは、これは接尾語長の前に国民の最大のセクションである[J-1に0]次のP [jまで0]この時期からではなく、それはPを表し、私はkの値を強調したい、小さなパートナーめまいを恐れます注意を払う必要があります!

さて、それは限り、次のアレイは、そのすべてが解決されて見つけることとして、次の配列を見つけることが不可欠となります。

第四に、次のアレイのための外観

法律を見つけるためにする次の第1の配列、配列の次の次の例を見つけるために最初に、探し:
ここに画像を挿入説明
私たち人間の目によると、簡単に次の配列内の値を参照してくださいが、プログラムのために、あなたがアルゴリズムを必要とすることができ、それであってもよいです動的なプログラミングの問題は、つまるところ、私は以下の分析を見てみましょう、動的プログラミングでも問題ありません理解していない、私たちは次の配列を求めて、私はこのプロセスを入れて、次の値の配列を探索するために人間の脳のプロセスを分析してみましょう:
学んだことがないダイナミックあなたのプログラミング:数学的帰納法の視点は、ときに使用することができます
ので、想定しています。私たちは次のjビット列の前に値を計算しているし、次の[J]その後、私たちは今、配列を持っているK =:
ここに画像を挿入説明
今は+ Jをお願いしたいと思いますそれを見つけるためにどのように1は、文字列を表し、次の[J] = K、(jへの0から1)、我々のすべての知っているので、
サフィックスkの前に公共の最大長は、次の図があります:
ここに画像を挿入説明
私たちは、jに求めるよう+ 1
の最初のステップは、これは+ 1に等しい文字kのストリングに過ぎない計算することである(J + 1) - 1つの文字として理解することができる次
ここに画像を挿入説明
の文字のk + 1ビット列は、ビットjに等しい場合次いで、文字がある次の[J + 1] = K + 1 (これは文字列の黄色と緑色の部分の長さという数字である)
、次の[J + 1]どのように我々はそれを求めるべきは、私たちが植えケースについて話している心配していない場合に一致しない場合、同等よりよく理解した場合に下記の最初の画像が読みとき:
ここに画像を挿入説明
まあ、我々はチャート図をフォローについて導出することができますがあります。

1.セットモードシーケンスはPであり、次のアレイは、その初期化完了を有し
2.次に、K = NEX [j]は、kの長さに図ストリング長A1に見ることができるがあり、
配列Pの次の値[0のためJ -最大長プレフィックスとサフィックス1]、そこA1(接頭辞)= A2(接尾辞)と同じ;
3. Kある「=次の[K]、そう同様に利用できるB2 = B1、
4 2と3点と次の使用可能な長さC1と原則[K「]、およびC2 = C1;
5、次いで2,3,4-点式の導入を求めることができる。
∵B1 = B2、C2 = C1 ;
∴C1 = C2 = C3 = C4;
及びA1 = A2∵;
∴b1= B2 = B3 = B4;
∴C1 = C2 = C3 = C4 = C5 = C6 = C7 = C8、
次のような結果を得ることがきちんと:
(。A2 = A1; 1)
(2)= B1〜B4、
C1 = C8(3);
...... ......
(N)N1 = NN(P [0、N1]これまで前共通接尾辞になくなるまでつまり(次の[N] = 0かつn = 0))は
、まだ次のアニメーションがもう一度考え従うことを望んでいない、
ここに画像を挿入説明
次のように我々は、これらの法律に基づいて予備的な要求次の配列方法を描くことができます。

vector<int> initNext(string pattern){
    vector<int> next(pattern.length());
    int k;
    next[0] = 0;

    for(int j=0;j<pattern.length()-1;j++){
        k = next[j];
        
        while((k != 0 || next[k] != 0) && pattern[k] != pattern[j]){ // k不能到达0,且两个下标对应的字符不相等时才能循环
            k = next[k];
        }

        if(pattern[k] == pattern[j] && j != k){  // 两个下标指向的字符相等 且 下标不能一样
            next[j+1] = k+1;
        }else{
            next[j+1] = 0;
        }
    }
    return next;
}

このコードは書かれた混乱で、私は上記に我々の分析のロジックを満たすために試してみたいので、それはパッチワークですが、この順序は、より良い次の配列を見つけるための方法を理解するためにダウン読まれるべきです。
以上のように明確にnexe言葉を求めているならば、我々は、コードに続く上記のアイデアの予備的分析から導出されたコードで読み取り、ので、我々はいくつかの単純化を行うために上記のコードを分析することを、エレガントではありません:
この段落の最初に見て:

ここに画像を挿入説明
前のサイクルをk = 0 ||次の[K] = 0である状態は、明確な図に急いで、それの意味するものです!:

ここに画像を挿入説明
明らかに、この図は、ミスマッチ現象が浮上しているが、まだ状態が標識されるように、K = 0のこの時、次の[K]でkは依然として、パターンの先頭に既に点をK、すなわち、ゼロに等しいです:私たちは同様に次のアレイ0 -1タグ付けが終わりに近づい持つかもしれないので、それの前には代表を持っていない、コードは次のように単純化することができ
ここに画像を挿入説明
、彼らはこの1つを簡素化することができればその数字で母はまだ混乱、一見:K == -1即ち他のトリガされたとき、次の[jが+1] = 0の場合ため、
に等しくない場合、この文は、次の[J + 1] = K + 1( K -1追加され、この場合、とにかく)1つのISが0に等しいていた。
そして、このようになります。
ここに画像を挿入説明
残念ながらか、ここでは2つのサイクルがあり、私たちは仕事に圧縮彼を入れて、私たちは、内側のループは非常に奇妙なを有していることがわかりましたjが変更されていない、すなわち、私たちは一致していない場合、それがされて反復K値を持つことが、プロセスに私たちがしている、なぜ我々は、手動でjの値を制御するために所有していませんか?ここに画像を挿入説明
私は(ここで、J- -ので、強制的にそれは変化しないこと、サイクルjの各部分の終わりからjの値を増加を相殺するために)、これは少し愚かですが、またプロセスと手順を知っています、あなたが見ることができます我々はのサイクルに最適化し、する必要があることを、上記のコード
が、それでも非常にきれいな、そして最終的に整理し、次のコード:

vector<int> initNext(string pattern){
    vector<int> next(pattern.length());
    int k=-1,j=0;
    next[0] = -1;

    while(j < pattern.length() - 1){
        if(k == -1 || pattern[k] == pattern[j]){
            next[++j] = ++k;
        }
        else{
            k = next[k];
        }
    }
    return next;
}

これは実際には、私たちが愛したバージョンであり、そして否定(すなわち、反転して取引を行って、他の場合は、その数字が変化するためであることは、しばらくなり;

第五に、最終処理

前回説明した後、あなたはすでに原則を知っているとKMPアルゴリズムの次の配列を解決する、卓越性の精神のために、私たちは、私は以下を参照させ、致命的ではないバグがある上記のコードので、彼らは最終処理を実行する必要がありますが、この場合にマッチ:
ここに画像を挿入説明
この場合は、マップ上で見ることは難しいことではありません、我々は不一致、パターン[J] =パターン[ i]は、 以下のこの特定のパターン文字列マッチングで、はっきりAA-文字列に属しています! :、これが発生前半と同様の後半であり、
そのような状況パターン[次の[J] =パターン[J]:
証明:
!の∵pattern[J] =パターン[I]
K =次いで[J]、
次の利用可能なの性質:パターン[0:K] ==パターン[JK、J]
とパターン∵[K] =パターン[J]
∴パターン[K] =パターン[I]!

それは、このケースでは、我々は(すぐにフォールバック位置をk個が、成功と一致しませんでした)有用な作業のロールバックを行っているが、我々は次のアレイを構築する場合、パッチに頼らなければならないことは明らかです。

vector<int> initNext(string pattern){
    vector<int> next(pattern.length());
    int k=-1,j=0;
    next[0] = -1;

    while(j < pattern.length() - 1){
        if(k == -1 || pattern[k] == pattern[j]){
            if(pattern[++j] == pattern[++k]){
                next[j] = next[k];
            }else{
                next[j] = k;
            }
        }
        else{
            k = next[k];
        }
    }
    return next;
}

bool serarch(string pattern,string text){
    vector<int> next = initNext(pattern);
    int i=0,j=0;
    const int pLen = pattern.length();
    const int tLen = text.length();

    while((j < pLen) && (i < tLen)){
        if(j == -1 || text[i] == pattern[j]){
            i++;
            j++;
        }
        else{
            j = next[j];
        }
    }
    return j == pLen;
}
  • 結論:
    (N + M)KMPアルゴリズムはOに次回アレイ構成、ロード時間と精度を除去参照、技術暴力と著しく対照的であり、実際には、マッチングアルゴリズムの千だけでなく、海洋の低下KMPアルゴリズムのうち、アルゴリズムは、ポイントのみで良いか悪いか、善悪ではありません、あなたは文字列照合アルゴリズムに興味がある場合は、異なるシナリオを使用して、異なるアルゴリズムが、アルゴリズムは日曜日を見て行くかもしれない、とにかく、学習は、ボートのそれのための無限の苦しみですショーでそれを埋め、多くのことを学ぶために!

ねえ〜プロットは、あなたが賞賛の聖歌の散歩を指している場合、小さなパートナーにする問題があるゲストブックの議論をささやくか、コメントすることができます簡単に、この記事では役に立ちません。

公開された27元の記事 ウォン称賛62 ビュー10000 +

おすすめ

転載: blog.csdn.net/qq_42359956/article/details/105242127