KMP算法next函数?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了KMP算法next函数?相关的知识,希望对你有一定的参考价值。

这个 next函数具体指的是什么?它是怎么求的?原理是什么?
请大家不要复制粘贴

设主串为S = "s1s2 ... sn",模式为T = "t1t2 ... tm"
当“失配”(si <> tj)时,模式串T “向右滑动” 的可行距离有多远? 或者说,下一步si 应该与模式串中的哪个字符比较,这完全取决于模式串,与主串无关

因此,可以预先为模式串设定一个数组next[j],当“失配” (si <> tj)时,i 不变,j 改为next[j]

0 当j = 1时,不比较
next[j] = maxk, 1 <= k < j 且"t1 … tk-1" = "tj-(k-1) … tj-1"
1 其他情况

next[j] 函数表征着模式T 中最大相同首子串和尾子串(真子串)的长度
相似部分越多,则next[j] 函数越大
既表示模式T 字符间的相关度越高,也表示j 位置以前与主串部分匹配的字符数越多
next[j] 越大,模式串向右滑动得越远
参考技术A next函数是0123。
那个滑动不是那么滑的吧。
因为next[4]=3,所以
主串的第四个值和子串的第三个值对应。也就是向右滑动1个字

KMP算法NEXT数组计算方法

KMP算法:

关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息。时间复杂度O(m+n)。


个人对于Next()函数的理解:

一:思路概括:我语文不太好可以忽略,可以先看手工实现

1,把将要进行next计算的字符串S分成 k ,j 前后两串,k代表前串开头所在的序号,j代表后串开头所在的序号,起始的时候j=1,k=0。

2,我们比较一下前串 后串是否相等,要怎么比较呢,肯定是比较S[j]==S[k],如果相等,那么next[j+1]=k+1,然后j++,k++。

关键就是理解这个next[j+1]=k+1(为什么k+1,由于下标是从0开始?):简单说就是S串中的第j+1个字符的next函数值由他前面的字符与前串相等的个数来决定,就是说串中的第j+1个字符的next函数值,是由他前面的字符串决定的

3,当S[j]!=S[k],即不相等的时侯,那么j不动,k返回到开头(因该是next[k]位置,便于理解先假设是返回k=0处),即从头比较S[0]与S[j],S[1]与S[j+1]

例如:第 j+1 个字符的next函数值next[j+1]等于3,意味着 他的前三个字符串,S[j-2]S[j-1]S[j] =S[0]S[1]S[2]

二:手工实现理解

例1

         

序号

0

1

2

3

4

5

6

7

8

子串

a

b

c

a

a

b

c

b

a

Next值

-1

0

0

0

1

1

2

3

0


1,第一个字符的next值令为-1。令第二个字符b的next值为0,初始k=0,j=1, 比较S[k] 和S[j]

2,比较S[0] !=S[1]  所以  j++ k不变 next[j=2]=0

3,比较S[0] !=S[2]  所以  j++ k不变 next[3]=0

4,比较S[0]  ==S[3]   所以  j++,k++, next[4]=k=1

5,k=1了 所以比较S[1] !=S[4],k返回到next[k]位置,即k=next[1]=0,然后比较S[k=0] == S[4] 所以 j++ ,k++ ,next[5]=k=1

6,比较S[1] ==S[5]   所以 j++ ,k++ ,next[6]=k=2

7,比较S[2] ==S[6]   所以 j++ ,k++ ,next[7]=k=3

8,比较S[3] !=S[7]     所以k返回到next[k=3]位置,即k=next[3]=0,然后比较S[k=0] != S[7] 所以 j++ ,不变k=0不变,next[8]=k=0

完毕

可以轻松的发现,S[j]的比较,决定了字符 S[j+1 ] 的next函数值


例二:在例一中,每次不相等时返回的都是k=next[k]=0,都是返回到了开头,我们看一个不是返回到开头0的情况:

序号

0

1

2

3

4

5

6

7

8

9

10

子串

a

a

b

c

a

a

a

b

a

a

c

Next值

-1

0

1

0

0

1

2

2

3

1

2



从 j=5,k=1的时候开始

5,比较 S[1] == S[5] 所以 j++,k++,next[j+1=6]=k=2

6,比较S[2] != S[6] 所以 k返回到next[k=2]位置,即k=next[2]=1,然后比较S[k=1]  == S[6] 所以 j++ ,k=1+1=2,next[7]=k=2

…………

因此,我们发现K的退回 是退回到next[k]的位置 即S[j]!=S[k]时,k=next[k]


二:getNext函数实现代码如下


void getNext(char *p,int *next)  
  
    int j,k;  
    next[0]=-1;  
    j=0;  //后串起始位置,一直增加 
    k=-1;  //k==-1时,代表j++进入下一轮匹配,k代表前串起始位置,匹配失败回到-1 
    while(j<strlen(p)-1)  
      
        if(k==-1||p[j]==p[k])    //匹配的情况下,p[j]==p[k],next[j+1]=k+1;  
          
            ++j;  
            ++k;  
            next[j]=k;  
          
        else                   //p[j]!=p[k],k=next[k]  
            k=next[k];  
      
  


KMP算法那完整实现代码如下


#include<stdio.h>
#include<string.h>
	int next[30];
void getNext(char *p,int *next)  
  
    int j,k;  
    next[0]=-1;  
    j=0;  //后串起始位置,一直增加 
    k=-1;  //k==-1时,代表j++进入下一轮匹配,k代表前串起始位置,匹配失败回到-1 
    while(j<strlen(p)-1)  
      
        if(k==-1||p[j]==p[k])    //匹配的情况下,p[j]==p[k],next[j+1]=k+1;  
          
            ++j;  
            ++k;  
            next[j]=k;  
          
        else                   //p[j]!=p[k],k=next[k]  
            k=next[k];  
      
  

int my_kmp(char* s1,char* key)
	int i=0;
	int j=0;
	int l1=strlen(s1);
	int l2=strlen(key);
	while((i<l1)&&(j<l2))
		if(j==-1||s1[i]==key[j])
			i++;
			j++;
		
		else
			//i=i-j+1;j=0;
			j=next[j];
		
	
	if(j>=l2)return i-l2;
	else return 0;
 
int main()
	char* s="aabcaaabaac";

	getNext(s,next);

	printf("%d",1+my_kmp("aabaabbccaabbaaccaaabccbcaacccb",s));


以上是关于KMP算法next函数?的主要内容,如果未能解决你的问题,请参考以下文章

求出子串(模式串)的next函数值,利用kmp算法实现模式与主串的匹配算法

KMP算法NEXT数组计算方法

KMP算法NEXT数组计算方法

KMP算法next函数?

KMP字符串匹配算法

KMP算法