
大话KMP算法(原创)
最近在学习数据结构。遇到KMP算法的时候,研究了好几天,终于弄明白了算法的思想。
今天心情很不爽(因为被二叉树给难住了,哎!)。就写一下KMP算法吧。望编程高手给予指点。
请注意,在看这篇文章之前,请务必先看看严蔚敏老师的《数据结构》中的串的模式匹配算法(P79)这一节,在看不
懂KMP算法的时候再看下面这篇文章。当然,基本的模式匹配算法请务必先看懂。
KMP算法思想:1.设S为主串(目标串),T为模式串,以i和j分别指示主串和模式串中正待比较的字符,若Si=Tj,则i
和j分别加1,继续比较Si和Tj(其实,这个时候是比较Si+1和Tj+1了);否则,i不变,而j退回到j=next[j]的位置,
继续比较Si和Tj(其实,这个时候是比较Si和Tnext[j])。以上两种情况是,若新的Si=Tj,则i和j分别加1,继续往后
比较,若不相等,则j接着退到下一个j=next[j]的位置,再比较新的Si和Tj。直到下列两种情况之一:一是j退回到某
个j=next[j]的位置时,有Si=Tj,则i和j各加1继续往后比较;二是j退回到j=0时(即模式串的第1个字符失配),则将
从Si+1和T1重新开始往后比较。
1.KMP算法//利用模式串中的next函数求Tj!=Si是,指针j应退回的位置
int Index_KMP(SString S,SString T,int pos)
{
int i,j;
i=pos;
j=1;
while(i<=S[0] && j<=T[0])
{
if(j==0 || j<=T[j])//j==0表示模式串中第一个字符即和Si失配,则应从Si+1和T1开始重新比较
{
++i;
++j;
}
else
{
j=next[j];//即next[j]=k,j应退回到k的位置,即从Si和Tk开始重新比较
}
}
if(j>T[0])
return i-T[0];
else
return 0;
}
2.接下来就是如何求next[j]了。因为已知next[1]=0,之一找出next[j+1]与next[j]之间的关系,就可以求出模式串中
所有的next[j]。
初始算法:
(1)初值next[1]=0;
(2)设next[j]=k,于是有"T1......Tk-1"="Tj-k+1......Tj-1";
(2-1)若Tj=Tk,则有"T1......Tk-1Tk"="Tj-k+1......Tj-1Tj";故此时有next[j+1]=k+1=next[j]+1。
(2-2)若Tj!=Tk,设next[k]=k',则有"T1......Tk'-1"="Tj-k'+1......Tj-1"。
(2-1-1)若Tj=Tk',则next[j+1]=k'+1=next[k]+1=next[next[j]]+1;
(2-1-2)若Tj!=Tk',则重复(2-2)直到不存在kn为止,则此时有next[j+1]=1。
2.求next函数的算法(求模式串T的next函数值并存入数组next中)
void get_next(SString T,int next[])//因为形参是数组,故不需要引用类型
{
int j,k;
j=1;
next[j]=k=0;//写成这样是因为我觉得更好理解一点
while(j<T[0])
{
if(k==0 || T[j]==T[k])没有重叠真子串或有重叠真子串但T[j]==T[k]时,都可求出next[j+1]的值
{
++j;
++k;
next[j]=k;//其实,这三句等价于next[++j]=++k;即next[j+1]=next[j]+1
}
else //否则(即有重叠真子串,但此时T[j]!=T[k]),则此时无法求出next[j+1]的值,那么此时
k=next[k];子串T应再跳到k'= next[k]去匹配,直到kn=0或者T[j]=T[kn]
}
}
//k==0表示没有重叠真子串(next[j]=k=0),此时应该从Si+1与T1开始比较。那么当Tj+1与Si'不匹配时,next[j+1]
=1.即i'不变,子串从T1开始一Si'开始向后比较。
//T[j]==T[k]表示有重叠真子串,但此时亦有T[j]=T[k].则此时有next[j+1]=next[j]+1
3.但是,上面的思想还有一个缺陷,在求出next[j]=k时,若T[j]=T[k],则由于T[j]!=S,必然有T[k]也不会等于S
,此时就要继续k'=next[k],直到T[j]!=T[kn].此即nextval[]数组的求法。
3.求nextval函数的算法
void get_nextval(SString T,int nextval[])
{
j=1;
nextval[j]=k=0;
while(j<T[0])
{
if(k==0 || T[j]==T[k])
{
++j;
++k;
if(T[j]!=T[k])
nextval[j]=k;//这时T[j]实际上是T[j+1],T[k]实际上是T[k+1]
else
nextval[j]=nextval[k];
}
else
k=next[k];//否则,j不变,k退回到next[k]的位置
}
}
在实际运用时,只需要1和3即可。即只需要Index_kmp和get_nextval两个即可。
注:不是我不注重编程规范,而是文本格式的限制,我也没办法。先凑合着吧,反正算法注重的是思想。一点格式问题也不要紧了哈...
转载请注明出自暗组信息安全论坛 http://forum.darkst.com/,本贴地址:http://forum.darkst.com/viewthread.php?tid=56082