1.KMP算法 是用来处理一对一的匹配的。
朴素的匹配算法,或者说暴力匹配法,就是将两个字符串从头比到尾,若是有一个不同,那么从下一位再开始比。这样太慢了。所以KMP算法的思想是,对匹配串本身先做一个处理,得到一个next数组。这个数组是做什么用的呢?next [j] = k,代表j之前的字符串中有最大长度为k 的相同前缀后缀。记录这个有什么用呢?对于ABCDABC这个串,如果我们匹配ABCDABTBCDABC这个长串,当匹配到第7个字符T的时候就不匹配了,我们就不用直接移到B开始再比一次,而是直接移到第5位来比较,岂不美哉?所以求出了next数组,KMP就完成了一大半。next数组也可以说是开始比较的位数。
计算next数组的方法是对于长度为n的匹配串
如何去求next数组呢?k是匹配下标。这里没有从最后一位开始和第一位开始分别比较前缀后缀,而是利用了next[i-1]的结果。而且我觉得这样理解起来会好一点。求出next就完成了一半了。
void getnext()//获取next数组
{
int i,n,k;
n=strlen(ptr);
memset(next,0,sizeof(next));
k=0;
for(i=1;i<n;i++)
{
while(k>0 && ptr[k]!=ptr[i])//在无子串的时候不会到这里
k=next[k];//如果不匹配就回溯到next[k]
if(ptr[k]==ptr[i]) k++;//匹配到之后就k++
next[i+1]=k;//将匹配到的字符个数存入
//next表示的是匹配长度
}
}
算法导论算法循环是从1到n而不是从0到n-1,所以在下面匹配的时候需要j=next[j+1]。
int kmp(char *a,char *b)//匹配ab两串,a为父串
{
int i=0,j=0;
int len1=strlen(a);
int len2=strlen(b);
getnext();
while(i<len1&&j<len2)
{
if(j==0||a[i]==b[j])
{ i++;j++; }
else j=next[j+1];//到前一个匹配点
}
if(j>=len2)
return i-j;
else return -1;
}
这里next数组的作用就显现出来了。最后返回的是i-j,也就是说,是从i位置前面的第j位开始的,也就是上面说的,next数组也可以说是开始比较的位数。也就是说,在父串的i位比的时候已经是在比子串
的第j位了