また「KMP」に会いました
3619 ワード
同じ http://blog.csdn.net/shanshanpt/article/details/8679459 ,全部思い出版です
>:KMPのいくつかの概念の紹介は大丈夫です.ネット上は至るところにあります.ここは整理のためだけです.
>:ネットで見た文章は全部「next」配列とi、jポインタの移動から言ったものです.ここも同じですが、違うのは、もっとはっきり言いたいことです.
>: 従来のBFアルゴリズムとKMPの違いは何ですか?
BF:元の列:B A B A B ...
サブストリップ: B A B A D この時点でマッチしません.次の文字から開始します. 元の列:A B A B…
--------------------------------------------------------------子串: A B A D---------------------------------------------------------
そしてまた探し続けます.そうすると、私たちの前期のマッチングは無駄になります.KMPはすでにやった仕事を最大限に利用します.
KMP:元の列:B A B A_D_A…
サブ串:B A B A D.
よくないです.合っていないことが分かりました.どうすればいいですか?KMPはBFのようにバカではなく、最初からやり直すのです.--->前の文字列に対して、境界を見つけたいです.何ができますか?一番前のmの長さの文字列(前から数えてmのchar)と一番後ろのmの文字列を作ることができます.(後ろから数mのcharを数えます.ここで言っているのは前に成功した部分ですよ~^_^)同じです.何になりますか?
直列:B A B A B A D A…
サブストリップ: B A B A D じゃ、次のB Aを見られます. 前にマッチした文字列が等しい場合です.
前は文字列のDが合っていなかったということを知っていますので、頭のmの長さの文字列と尾のmの長さの文字列が等しいと見つけたら、頭のmの長さが分かります.
元の尾部mの長さに移動すると、元の列に対応するmの長さが必ず一致します.これはKmpとBFの違いの鍵です.
もう一つの例を見ます.
直列:B A C B A B A D A…
サブ串:B A C B A D .
KMP処理後、次のようになります.
直列:B A C B A B A D A…
サブストリップ: B A C B A D 赤い色 BとDは前の不一致のところで、緑色の3つのB Aは上のKMPの処理の結果です.
>: こんなに多く話して、みんなはすべてむだ話だと思うことができて、ほほほ、下は重要なnext配列が解を求めます.
>: next[0]=-1を定義し、next[j]=kを仮定して、 すなわち、M[0...k-1]==M[j-k...j-1]である.
>: その後、下にスキャンします.M[j]==M[k]なら、M[0.k]==M[j-k,j]があります.明らかに、next[j+1]=next[j]==k、next[j]=kがあります.
>: もしM[j]!=M[k]にマッチして失敗したら、k=next[k]というように書いていますが、なぜですか?私たちはよく考えてみてもいいです.上のM[j]==M[k]に直接+1
私のnextを得ることができます.ここでは同じではないです.Mの前の文字列から処理できます.つまり、M[next[k]から可能です.
コードを書きます.
>:KMPのいくつかの概念の紹介は大丈夫です.ネット上は至るところにあります.ここは整理のためだけです.
>:ネットで見た文章は全部「next」配列とi、jポインタの移動から言ったものです.ここも同じですが、違うのは、もっとはっきり言いたいことです.
>: 従来のBFアルゴリズムとKMPの違いは何ですか?
BF:元の列:B A B A B ...
サブストリップ: B A B A D この時点でマッチしません.次の文字から開始します. 元の列:A B A B…
--------------------------------------------------------------子串: A B A D---------------------------------------------------------
そしてまた探し続けます.そうすると、私たちの前期のマッチングは無駄になります.KMPはすでにやった仕事を最大限に利用します.
KMP:元の列:B A B A_D_A…
サブ串:B A B A D.
よくないです.合っていないことが分かりました.どうすればいいですか?KMPはBFのようにバカではなく、最初からやり直すのです.--->前の文字列に対して、境界を見つけたいです.何ができますか?一番前のmの長さの文字列(前から数えてmのchar)と一番後ろのmの文字列を作ることができます.(後ろから数mのcharを数えます.ここで言っているのは前に成功した部分ですよ~^_^)同じです.何になりますか?
直列:B A B A B A D A…
サブストリップ: B A B A D じゃ、次のB Aを見られます. 前にマッチした文字列が等しい場合です.
前は文字列のDが合っていなかったということを知っていますので、頭のmの長さの文字列と尾のmの長さの文字列が等しいと見つけたら、頭のmの長さが分かります.
元の尾部mの長さに移動すると、元の列に対応するmの長さが必ず一致します.これはKmpとBFの違いの鍵です.
もう一つの例を見ます.
直列:B A C B A B A D A…
サブ串:B A C B A D .
KMP処理後、次のようになります.
直列:B A C B A B A D A…
サブストリップ: B A C B A D 赤い色 BとDは前の不一致のところで、緑色の3つのB Aは上のKMPの処理の結果です.
>: こんなに多く話して、みんなはすべてむだ話だと思うことができて、ほほほ、下は重要なnext配列が解を求めます.
>: next[0]=-1を定義し、next[j]=kを仮定して、 すなわち、M[0...k-1]==M[j-k...j-1]である.
>: その後、下にスキャンします.M[j]==M[k]なら、M[0.k]==M[j-k,j]があります.明らかに、next[j+1]=next[j]==k、next[j]=kがあります.
>: もしM[j]!=M[k]にマッチして失敗したら、k=next[k]というように書いていますが、なぜですか?私たちはよく考えてみてもいいです.上のM[j]==M[k]に直接+1
私のnextを得ることができます.ここでは同じではないです.Mの前の文字列から処理できます.つまり、M[next[k]から可能です.
コードを書きます.
#include <stdio.h>
#include <string.h>
void get_next( char *tmp,int *next )
{
int j,k;
int len = strlen( tmp );
next[0] = -1; //
j = 0;
k = -1;
while( j < len - 1 )
{
if( k == -1 || tmp[j] == tmp[k] ) // tmp[j]==tmp[k]
{
j++;
k++;
if( tmp[j] == tmp[k] ) // if , next
{
next[j] = next[k];
}
else
{
next[j] = k;
}
}
else
{
k = next[k]; // , !
}
}
}
int KMP( char *s,char *tmp, int next[] )
{
int i = 0,j = 0, len_s = strlen( s ), len_p = strlen( tmp );
while( i < len_s )
{
if( j == -1 || s[i] == tmp[j] ) // || char
{
i++;
j++;
}
else
{
j = next[j]; // i ( BF )
}
if( j == len_p ) //
{
return i - len_p; //
}
}
return -1; //
}
int main()
{
char str[80], sub_str[20];
int next[100], first_at;
while( gets( str ) )
{
gets( sub_str );
get_next( sub_str,next ); // next
first_at = KMP( str, sub_str, next ); //
if( first_at != -1 )
{
printf("At: %d
", first_at);
}
else
{
printf("No cmp...
");
}
}
return 0;
}