KMP算法(prefix table)

注意这里是采用prefix table实现kmp算法

首先谈谈prefix_table
例如字符串ch[]=ababc
可以先将其的子串列出
a -------------前缀为0,后缀为0
ab------------前缀为a,后缀为b,最长相同前后缀为0
aba-----------最长相同前后缀为1(a)
abab---------最长相同前后缀为2 (ab)
ababc-------因为结尾是c所以最长相同前后缀为0
这样得到的prefix table 为 {0、0、1、2、0};
为了后续处理将全部数右移并将prefix[0]设为-1;
新的prefix为{-1、0、0、1、2};

如何生成prefix_table数组
因为我们先将prefix[0]设为-1,同时第一位的最长前后缀为0,所以从prefix[2]开始。
从上面aba子串到abab子串可以看出prefix_table之间是有联系的, 因为前一个的prefix是最优情况,所以下一个prefix想要延长就要尾字符等于它所对映prefix的字符(dp)

例如:aba --------------prefix={-1、0、0}
a去对应ch[prefix[0]]即a;
然后prefix={-1、0、0、1};
相等的情况则在前一个的基础上加一;
否则等于零。
这里讲一下为什么需要右移
ch[]=abcaba;
如果用原来的方式在最后一位会有问题
prefix={0、0、0、1、2}
最后一位是a不匹配ch[2]即不等于c
但是a=ch[0],应该填1;
正确prefix为{0、0、0、1、2、1}
将全体右移能避免,同时空出来的首位加上标记-1便于后续操作

void kmp_PrefixTable(int *k,int len)
{
		int i;
		k[0]=-1;
		k[1]=0;
		for(i=1;i<len-1;i++)
		{
			if(ch[i]==ch[k[i]])
			{
				k[i+1]=k[i]+1;
			}
			else
			{
				k[i+1]=0;
			}
		}
}

接下来讲怎么利用prefix_table实现kmp
例子:
m[]=“aaaaaaaaaaaaaab”
n[]=“aaaab”
先生成prefix_table={-1、0、1、2、3}
匹配需要两个指针(代指)i,j;
当i=4,j=4时不匹配了就将j指向prefix中的位置(3)
则就相当于n[]整体向后移了一位,然后i和j继续向后匹配;
这里可以发现向后移位的时候不用继续比较前面的字符串从而提升匹配速度,相比朴素模式算法从头比较就更快了。
如果j指向prefix中的-1,就说明第一位都没有匹配上则i和j同时++
贴上用kmp查找不重叠子串的代码

#include<stdio.h>
#include<string.h>
char  str[10000007];
char ch[10000007];
void kmp_PrefixTable(int *k,int len);
int main()
{
	
	while(scanf("%s",str),strcmp(str,"#")!=0)
	{  
	    int len2=strlen(str);
		
		scanf("%s",ch);
		int len=strlen(ch);
		int k[len+1];
		int i;
		kmp_PrefixTable(k,len);
		int j=0;
		int ans=0;
		for(i=0;i<len2;)
		{
		if(str[i]==ch[j])
		{
		if(j==len-1)
		{
			ans++;
			j=0;
		}
		else
		j++;
		i++;
		}
		else
		{
		j=k[j];	
		if(j==-1)
		{
			i++;
			j++;
		}
		}
	}
	printf("%d\n",ans);
 } 
 }
void kmp_PrefixTable(int *k,int len)
{
		int i;
		k[0]=-1;
		k[1]=0;
		for(i=1;i<len-1;i++)
		{
			if(ch[i]==ch[k[i]])
			{
				k[i+1]=k[i]+1;
			}
			else
			{
				k[i+1]=0;
			}
		}
}

你可能感兴趣的:(KMP算法(prefix table))