KMPアルゴリズム(C言語の実装)

ここに画像の説明を挿入

KMPアルゴリズム-文字列照合アルゴリズム

アイデア

従来の文字列照合では、文字が一致しなかった場合、一致の開始後に文字に戻ります。これにより、効率が低下します。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;
}

おすすめ

転載: blog.csdn.net/m0_60598323/article/details/123696693