KMP算法NEXT數組計算方法

KMP算法:

關鍵是利用匹配失敗後的信息,儘量減少模式串與主串的匹配次數以達到快速匹配的目的。具體實現就是實現一個next()函數,函數本身包含了模式串的局部匹配信息。時間複雜度O(m+n)。


個人對於Next()函數的理解:

一:思路概括:我語文不太好可以忽略,可以先看手工實現

1,把將要進行next計算的字符串S分成 k ,j 前後兩串,k代表前串開頭所在的序號,j代表後串開頭所在的序號,起始的時候j=1,k=0。

2,我們比較一下前串 後串是否相等,要怎麼比較呢,肯定是比較S[j]==S[k],如果相等,那麼next[j+1]=k+1,然後j++,k++。

關鍵就是理解這個next[j+1]=k+1(爲什麼k+1,由於下標是從0開始?):簡單說就是S串中的第j+1個字符的next函數值由他前面的字符與前串相等的個數來決定,就是說串中的第j+1個字符的next函數值,是由他前面的字符串決定的

3,當S[j]!=S[k],即不相等的時侯,那麼j不動,k返回到開頭(因該是next[k]位置,便於理解先假設是返回k=0處),即從頭比較S[0]與S[j],S[1]與S[j+1]

例如:第 j+1 個字符的next函數值next[j+1]等於3,意味着 他的前三個字符串,S[j-2]S[j-1]S[j] =S[0]S[1]S[2]

二:手工實現理解

例1

         

序號

0

1

2

3

4

5

6

7

8

子串

a

b

c

a

a

b

c

b

a

Next值

-1

0

0

0

1

1

2

3

0


1,第一個字符的next值令爲-1。令第二個字符b的next值爲0,初始k=0,j=1, 比較S[k] 和S[j]

2,比較S[0] !=S[1]  所以  j++ k不變 next[j=2]=0

3,比較S[0] !=S[2]  所以  j++ k不變 next[3]=0

4,比較S[0]  ==S[3]   所以  j++,k++, next[4]=k=1

5,k=1了 所以比較S[1] !=S[4],k返回到next[k]位置,即k=next[1]=0,然後比較S[k=0] == S[4] 所以 j++ ,k++ ,next[5]=k=1

6,比較S[1] ==S[5]   所以 j++ ,k++ ,next[6]=k=2

7,比較S[2] ==S[6]   所以 j++ ,k++ ,next[7]=k=3

8,比較S[3] !=S[7]     所以k返回到next[k=3]位置,即k=next[3]=0,然後比較S[k=0] != S[7] 所以 j++ ,不變k=0不變,next[8]=k=0

完畢

可以輕鬆的發現,S[j]的比較,決定了字符 S[j+1 ] 的next函數值


例二:在例一中,每次不相等時返回的都是k=next[k]=0,都是返回到了開頭,我們看一個不是返回到開頭0的情況:

序號

0

1

2

3

4

5

6

7

8

9

10

子串

a

a

b

c

a

a

a

b

a

a

c

Next值

-1

0

1

0

0

1

2

2

3

1

2



從 j=5,k=1的時候開始

5,比較 S[1] == S[5] 所以 j++,k++,next[j+1=6]=k=2

6,比較S[2] != S[6] 所以 k返回到next[k=2]位置,即k=next[2]=1,然後比較S[k=1]  == S[6] 所以 j++ ,k=1+1=2,next[7]=k=2

…………

因此,我們發現K的退回 是退回到next[k]的位置 即S[j]!=S[k]時,k=next[k]


二:getNext函數實現代碼如下


void getNext(char *p,int *next)  
{  
    int j,k;  
    next[0]=-1;  
    j=0;  //後串起始位置,一直增加 
    k=-1;  //k==-1時,代表j++進入下一輪匹配,k代表前串起始位置,匹配失敗回到-1 
    while(j<strlen(p)-1)  
    {  
        if(k==-1||p[j]==p[k])    //匹配的情況下,p[j]==p[k],next[j+1]=k+1;  
        {  
            ++j;  
            ++k;  
            next[j]=k;  
        }  
        else                   //p[j]!=p[k],k=next[k]  
            k=next[k];  
    }  
}  


KMP算法那完整實現代碼如下


#include<stdio.h>
#include<string.h>
	int next[30];
void getNext(char *p,int *next)  
{  
    int j,k;  
    next[0]=-1;  
    j=0;  //後串起始位置,一直增加 
    k=-1;  //k==-1時,代表j++進入下一輪匹配,k代表前串起始位置,匹配失敗回到-1 
    while(j<strlen(p)-1)  
    {  
        if(k==-1||p[j]==p[k])    //匹配的情況下,p[j]==p[k],next[j+1]=k+1;  
        {  
            ++j;  
            ++k;  
            next[j]=k;  
        }  
        else                   //p[j]!=p[k],k=next[k]  
            k=next[k];  
    }  
}  

int my_kmp(char* s1,char* key){
	int i=0;
	int j=0;
	int l1=strlen(s1);
	int l2=strlen(key);
	while((i<l1)&&(j<l2)){
		if(j==-1||s1[i]==key[j]){
			i++;
			j++;
		}
		else{
			//i=i-j+1;j=0;
			j=next[j];
		}
	}
	if(j>=l2)return i-l2;
	else return 0;
} 
int main(){
	char* s="aabcaaabaac";

	getNext(s,next);

	printf("%d",1+my_kmp("aabaabbccaabbaaccaaabccbcaacccb",s));
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章