kmp算法
KMP,主要的思想是求next[]数组,next数组只与模式串有关,与主串无关,作为字符串匹配时出现不匹配的跳转之用,严 的书上next[1]=0,还是很不习惯这种表达方式,数组还是习惯从next[0]开始!
严书上说,一串字符串p1.p2.p3...pn的next数组next[i]=j,表示p1..pj-1=p(i-j+1).....p(i-1),意思就是比如说字符串s1=acbcaac中(以1为下标开始)s[6]=a,s[7]=c,那么与s[6]对应的next[6]=2,表示的意思就是S[1]=S[5],假如
s:abcdabcef,那么s[6]=b,next[7]=3(s[1].s[2]=s[5].s[6]),就从这种情况看吧,如果继续有s[3]==s[7],那么next[8]=4了吧!
还可以用写出前缀和后缀找出相等的串的方法求next数组,比如:s=abcdabc
a: : next[1]=0
ab: : 前缀:a 后缀:b 没有相等项next[2]=1
abc {a ,ab} {c,bc} 0 next[3]=1
abcd {a,ab,abc} {bcd,cd,d} 0 next[4]=1
abcda {a,ab,abc,abcd} {bcda,cda,da,a} 1 next[5]=2
abcdab {a,ab,abc,abcd,abcda} {bcdab,cdab,dab,ab,a} 2 next[6]=2 s[1]=s[5]
abcdabc 3 next[7]=3 s[1].s[2]=s[5]s[6]
在主串T1与模式串T2的匹配过程中如果某时刻T1[i]!=T2[j],但是此时T2前面与T1肯定完全匹配,要不,不会匹配到这里来,然后再根据next[]数组找出与T2前面匹配的最大串长,即此时的next[j],与T2前面匹配了最大串长,那么毫无疑问与T1也匹配了吧,
举个例子:T1:acbcabacbcad T2:acbcaacd next[]={0,1,1,1,1,2,2,3}
(字符串的下标也从1开始吧) 在T1与T2匹配到T1[6]和T2[6]时不等了,那么T2要回溯,查next数组,next[6]=2,那么用T1[6]与T2[2]
继续比较,如果不等,继续以上面方式向前回溯,回溯到T2[1]时,继续向后比较,
如next数组和字符下标都是从0开始
void get_next(char *str,int next[])
{
int i=0;
int j=-1;
next[0]=-1;//数组首元素置为-1,
while(*(str+i)!='\0')//字符串遍历不为空时
{
if(j==-1||*(str+i)==*(str+j)){//回溯到next[0]或者相等时进入if
i++;j++;
next[i]=j;//next数组就是一个模式串的自我前缀和后缀匹配,
}/
j=next[j];//不等,继续回溯
}
一种优化方法:
void get_next(char *str,int next[])
{
int i=0;
int j=-1;
next[0]=-1;//数组首元素置为-1,
while(*(str+i)!='\0')//字符串遍历不为空时
{
if(j==-1||*(str+i)==*(str+j)){//回溯到next[0]或者相等时进入if
i++;j++; //1.j==-1时,j=0,str[j]再与str[i]比较,相等则next[i]=j,否则next[i]=next[j]
if(str[i]!=str[j]) next[i]=j;//后移后如果此次相等,那么在和主串匹配不相等时,跳转next数组有两种情况
else next[i]=next[j];//1.跳转后相等,那么此过程是多余,此处的值等于跳转之前的值,肯定不匹配,在此优化继续回溯next
}//后移不相等的,就有可能和主串匹配上,后移的值不等于刚才的值,那么就有可能等于主串此处的值
else j=next[j];//不相等时回溯
}
}