#include<stdio.h>
#include<string.h>
#define N 100
typedef struct Strings
//定義結構體包含string字符串和length長度屬性
{
char string[100];
int length;
} sq;
//GetNext裏面是關於next數組的
void GetNext(sq q,int next[])
{
int i=0;
int j=-1;
next[0]=-1;
while(i<q.length)
//匹配上限約束,小於傳入的長度
{
if(j==-1||q.string[i]==q.string[j])
//當j=-1時,爲第一個,不需要匹配跳過分別ij++;進行下一個的匹配
//自匹配,ij匹配相同則進行下一個匹配,若相同,此時next[i]就是當前最大匹配前後綴,就是j=i-1;
{
i++;
j++;
next[i]=j;
}
else
{
//如果自匹配失敗,說明,當前string[i],string[j]的值不一致,則i前一個的爲next[j],是當前滿足的最大的匹配前後綴
//此時,需要後移,而有個最大匹配前後綴的長度不需要再進行比較,在這一步可以賦給j,達到向右移動的目的;就是跳過前面的最大匹配量
j=next[j];
}
for(i=0; i<q.length; i++)
{
printf("%2d",next[i]);
}
}
}
int Kmp(sq s,sq p,int next[])
//傳入三個參數,兩個結構體字符串
{
int c=0;
int d=0;
while(c<s.length&&d<p.length)
//最大長度約束
{
if(d==-1||s.string[c]==p.string[d])
//當前匹配成功則加一匹配下一項
{
c++;
d++;
}
else
{
//若匹配失敗,則獲取當前的next[],即最大的相同前後綴的長度,將d實現移動,若next[d]=0;進行下一輪時可能會發生繼續匹配失敗
//此時的d=next[0]=-1;就是第一個字符;所以考慮這種情況時,同樣++;
d=next[d];
}
}
if(d==p.length)
//成功,因爲s,p相同時才++:不同的時候next[d]肯定小於d;當d能達到p.length時說明已經有成功的完成匹配了
return c-p.length;
else
return -1;
//失敗
}
int main (void)
{
int next[N];
int a;
sq s;
sq p;
printf("Please input S string :\n");
scanf("%s",s.string);
printf("Please input p string :\n");
scanf("%s",p.string);
s.length=strlen(s.string);
p.length=strlen(p.string);
GetNext(p,next);
printf("\n");
if(Kmp(s,p,next)!=-1)
{
printf("KMP匹配成功\n");
for(a=Kmp(s,p,next); a<Kmp(s,p,next)+p.length; a++)
{
//kmp不爲-1時返回的是c-p.length,所以a=c-p.lenght,a<c;a++
printf("%c",s.string[a]);
}
}
else
{
printf("失敗\n");
}
return 0;
}
難點在於next數組如何設計,自匹配,和兩個之間的匹配,需要考慮最大相同前後綴來提高效率,個人理解尚淺薄,只能get到優化的點,具體實現邏輯未弄懂。