#include<string.h>
#include<stdio.h>
/*
一般的模式匹配算法
如主串为Z[]='abababc',模式串M[]='ababc'
ZL=strlen(Z),ML=strlen(M)
匹配时
使用i=0,j=0,则
当Z[i]==M[j]时i++,j++,否则i=i-j+1,j=0不变,这样直到确认匹配或者主串已经找完
*/
int locate(char *Z,char*M)
{
int i,j,ZL,ML;
i=0;
j=0;
ZL=strlen(Z);
ML=strlen(M);
while(i<ZL||j<ML)
{
if(Z[i]==M[j])
{
i++;
j++;
}
else
{i=i-j+1;j=0;}
}
if(j==ML)
{
printf("locate: 匹配,位置为%d,即第%d个元素;",i-ML,i-ML+1);
return j-ML;
}
else
{
printf("locate: 无匹配");
return 0;
}
}
/*
KMP算法解决的主要问题是模式匹配中的效率问题 (避免匹配过程回溯即从i++到i=i-j+1)
M[]='ababc',主串为Z[]='abababc'
比如说Z[4]='a',M[4]='c',(i=4,j=4)不匹配,按照上面的算法应该使得i=1,j=0
但是我们发现M的{M[0]==a,M[1]=b}与{M[2]=a,M[3]=b}是一样但{M[0]=a}与{M[1]=b}不一样
所以我们可以利用之前验证的结果
即{M[2],M[3]}与{Z[2],Z[3]}已经匹配了,故可以将{Z[2],Z[3]}与{M[0]==a,M[1]=b}的匹配过程跳过
即从i=4与j=2开始再进行匹配下去,
所以现在我们要解决的问题是确定当主串在匹配模式串M[j]不匹配时,我们怎么来确定
主串Z[i]应该与M[]的哪个元素开始匹配,这就是next函数的功能.
*/
int locate_next(char*Z,char *M,int next[])
{
int i,j,ZL,ML;
i=0;
j=0;
ZL=strlen(Z),ML=strlen(M);
while(j<ML||i<ZL)
{
if(j==-1 || Z[i]==M[j])
{
i++;
j++;
}
else
{j=next[j];
}
}
if(j==ML)
{
printf("locate_next: 匹配,位置为%d,即从第%d个元素开始;",i-ML,i-ML+1);
return i-ML;
}
else
{
printf("locate_next: 无匹配");
return 0;
}
}
/*
当模式串如M[]='aaaab',匹配M[3]不成功时本来主串要再分别与M[2],M[1],M[0]进行匹配
但实际上M[3],M[2],M[1],M[0]均相等,故主串的Z[x+0],Z[x+1],Z[x+2],在判断Z[x+3]与
M[3]时已经确认了,所以可直接跳过进行Z[x+4]与M[0]的比较
*/
/*
改进的next_val
*/
void impro_next_val(char* M,int next[])
{
int i,j,ML;
i=0;j=-1;
next[0]=-1;//用来表示第一个就不匹配的情况
ML = strlen(M);
while(i<ML)
{
if(j==-1 || M[i]==M[j])
{
i++;
j++;
if(M[i]!=M[j])
next[i]=j;
else
next[i]=next[j];/*模式串中连续相同的子串*/
}
else
{
j=next[j];
}
}
printf("/n next[]: ");
for(i=0;i<ML;i++)
printf(" %d ",next[i]);
printf("/n");
}
int main()
{
char *M="aaaac";
char *Z="baaacaaaac";
int next[6];
locate(Z,M);
impro_next_val(M,next);
locate_next(Z,M,next);
return 0;
}
/*
参考资料清华大学出版社 <<数据结构 C语言版>>
上面是我整理的,不过课本的算法更清楚一点,她使字符串从1开始,而0表示字符串的长度
愿你生活愉快!!!
王怀宗
2007-11-08
**/