关于kmp算法:本人参考了很多博客和书籍,没找到很好的方法去理解它。
被搜索字符串T:ababdaababcd
需要查找的字符串P:ababc
kmp算法的next数组,首先它是储存的字符串P中的相应位置之前的前缀和后缀中前缀和后缀匹配的最大缀字符串的长度。
例如:
P字符串中: a b a b c 下标分别是0,1,2,3,4
在下标为0时,即P[0]=a,在P[0]前面没有字符串,故其没有前缀和后缀。
在下标为1时,即P[1]=b,在P[1]前面有P[0],但是只有P[0],故没有前缀和后缀
在下标为2时,即P[2]=a,在P[2]前面有ab,故子字符串为:ab,前缀分别是a,b没有相同的前缀和后缀。
依次类推:
P[3]的前面的字符串为:aba,前缀为,a,ab.后缀为:a,ba。相同的前缀后缀为a.
P[4]的前面的字符串为:abab,前缀为,a,ab,aba.后缀为:b,ab,bab。相同的前缀后缀为ab.
故可得next数组为
-1,0,0,1,2
现在我们得到了next数组。但是next数组怎么用,思想是什么呢?
假设:我们匹配P[j+1]和T[i+j+1]的时候匹配不成功了。//下表从0算,i表示第i次循环T字符串匹配
T[i+j+1]和p[j+1]不匹配了
如果P[j+1]之前没有相同的前缀和后缀,
那么直接进行下次循环匹配T[i+1+j+1]和P[0]匹配一个个匹配。//退回到暴力匹配。
如果有相同的前缀和后缀呢?
假设P[j]之前的相同的前缀后缀的长度为x,j=x+m+x+1;//m表示相同的前缀和后缀之间的字符串长度
那么也就是说T[i+x+m+x+1]和P[x+m+x+1]不匹配
但是T[i+x+m+x]和P[x+m+x]是匹配的.
我们这时候就只需要在T[i+x+m+x+1]处即T[i+j+1]和P[x+1]匹配了不用回溯P到P[0].//也就是前缀的后一位开始匹配
因为T[x+m]到T[x+m+x]处正好是的前缀P[0]到P[x],这是我们已经匹配过的信息。
例如:P=ababc匹配到T=ababdaababcd是P[4]和T[4]时不匹配了//i=0
next数组中记录P的next[4]为2,相同的缀长度为2.
此时j=2+0+2+1;//m=0,x=2
故下次匹配T[4]和P[2]处。//P[2]就是前缀ab的后一位.
这就是P字符串next数组的用处所在。
代码参考的数据结构,周彦军,王玉茹,关伟洲版。
代码如下:
#include <stdio.h>
#include <string.h>
typedef struct st_StrType StrType;
struct st_StrType {
int length;
char ch[1024];
};
int next[50];
void GetNext( StrType P, int next[ ] ) {
int j = 0, k =- 1;
next[ 0] =- 1;
while ( j< P. length- 1)
{
if(( k ==- 1)||( P. ch[ k]== P. ch[ j]))
{
k++;
j++;
next[ j] = k;
}
else
{
k = next[ k];
}
printf("next[%d]=%d \n",j,next[j]);
}
//printf("\n");
}
int KMPSearch( StrType T, StrType P, int pos) {
int i = pos, j = 0;
while ( ( i< T. length) && ( j< P. length) )
if (( j ==- 1) || (T. ch[ i] == P. ch[ j]))
{
i++;
j++;
}
else
j = next[ j];
if ( j >= P. length)
return i- P. length;
else
return - 1;
}
int main(void)
{
StrType test,test1;
test.length=12;
test1.length=5;
memcpy(test.ch,"ababdaababcd",12);
memcpy(test1.ch,"ababc",5);
GetNext(test1,next);
printf("%d \n",KMPSearch(test,test1,1));
return 0;
}