アイデア
従来の文字列照合では、文字が一致しなかった場合、一致の開始後に文字に戻ります。これにより、効率が低下します。KMPアルゴリズムでは、一致が失敗してもiは移動せず、Jのみが移動します。
照合プロセス中に、文字が同じである場合、次の文字のペアが照合されます。同一でない場合、次のようになります。
一致が失敗した場合、jをロールバックする必要がありますが、どこでロールバックする必要がありますか?下付き文字が2の場所にフォールバックします。
理由は次のとおり
です。iの前の文字はすべて正常に一致し、jの前の文字も正常に一致します。通常の状況では、jは最初から一致する必要があります.jの前の部分文字列に2つの同一の真の部分文字列があることがわかった場合(下付き文字0で始まり、下付き文字j-1で終わる)、jはの位置に戻ります。真の部分文字列の長さ。次のように:
さらに説明すると、iの前の文字列はjの前の文字列と等しく、一致は下付き文字が0の位置から一致する必要があります。これは、下付き文字0で始まり、下付き文字j-1の文字列。これらの2つの文字列がある場合、iの前に下付き文字0で始まり、下付き文字j-1で終わる文字列が必要であることを意味します。これにより、Jが戻ったときに最初からマッチングが保存されます。
この文字列の各文字はバックトラックされる場合があります。フォールバック位置は配列に格納され、次の配列を形成します
次の配列
デフォルト:ビット0は-1にフォールバックします(コードで処理され、配列の範囲外の問題は発生しません)
ビット1は一致せず、0にフォールバックします。
ここでの主な問題は、次のアレイを実装する方法です。
戻り位置の添え字をKで表し、pは文字列、jは添え字です。
next [j] = kが確立されていると仮定すると(jで一致が失敗した後、式はkを添え字として位置に戻ります)、
p [0] .... p [k-1] == p [x ] ...··p[j-1]
(kの位置は新しい一致が行われる場所であり、その前の部分文字列はjの前の部分文字列と同じである必要があります)
上記の式から、k-1-0 =j-1-xはx=jkであることがわかります;
式はp[0]・・・ p [k-1] == p [jk] ・・・ p [j- 1]-> next [j]=kが確立されたとき
1️⃣p[j]=p [k]
のとき、上記の式はp [0] ・・・ p [k-1] p [k]==pになります。 [jk] ・・・・p [j-1] p [i]-> next [j + 1] = k +
12️⃣p[j]、p [k]が等しくない場合、kにフォールバックします、この時点でkがk1に対応する場合、p [k1] = p [j]
、次にnext [j + 1] = k1 + 1、それ以外の場合は、等しくなるか-1で停止するまでロールバックを続けます。
このプロセスの後、次の配列を取得します
以下はさらに説明するための写真です
コード
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
void my_next(int* next,int n,const char* p)
{
int j = 1,k=0;
next[0] = -1;
next[1] = 0;
while(j<n)
{
if (k == -1 || p[j] == p[k])
{
next[j + 1] = k + 1;
j++;
k++;
}
else
{
k = next[k];
}
}
}
int kmp(const char* str1, const char* str2)
{
int i = 0, j = 0;
int len = (int)strlen(str2);
//next数组
int* next = (int*)malloc(len * sizeof(int));
assert(next);
my_next(next,len,str2);
while (str2[j])
{
if(j==-1||str1[i] == str2[j])
//j为-1时该位置下的i不会匹配成功,进入下一次匹配
{
i++;
j++;
}
else
{
j = next[j];//j进行回退
}
if (str1[i] == '\0')
{
free(next);
next = NULL;
return -1;
}
}
free(next);
next = NULL;
return i;
}
int main()
{
char arr[] = "abaabcdabcab";
char brr[] = "ef";
printf("%d\n",kmp(arr, brr));
return 0;
}