KMP算法

 

目录

一、KMP思路:

汇总:

二、代码实现:

三、求next数组

四、求next数组练习

五、计算next数组代码

 六、KMP优化

1、方法

2、求nextval代码

七、小结

下一篇:树的基本概念 


朴素的模式匹配算法指针每次需要前进m步再后退m-1。。。

也就是:当某些子串与模式串能部分匹配时,主串的扫描指针i经常回溯,导致时间开销增加

 

一、KMP思路:

主串指针不回溯,只有模式串指针回溯

匹配失败时如何回溯?

从主串从左往右扫描,若子串的指针j与主串的指针i匹配则i++,j++

若不匹配则让i++而j指向1

以下的情况j指向2

 

汇总:

简单来说就是要为模式串设置一个数组next告诉指针j当匹配失败时回到哪个下标才最省时

如果j=k时才发现匹配,说明1~k-1都匹配成功

需要将模式串映射为一个数组

例如google

 

二、代码实现:

int Index_KMP(SString S,SString T,int next[]){

int i=1,j=1;

while(i<=S.length&&j<=T.length){

if(j==0||S.ch[i]==T.ch[j]){//如果匹配或j刚置为0则往后

i++;

j++;

}

else

j=next[j];//模式串向右移动

}

if(j>T.length)//匹配成功

return i-T.length;

else

return 0;

}

 

 

 

 

三、求next数组

串的前缀:包含第一个字符,且不包含最后一个字符的子串

串的后缀:包含最后一个字符,且不包含第一个字符的子串

例子:

a

b

a

b

a

b

?   i的位置

?

?

?

?

?

 

 

a

b

a

b

a   j的位置

b

c

d

e

f

这里的模式串匹配到c时发生了不匹配

我们取该不匹配位置前的串的后缀和串的前缀进行对比,找到前后缀相同的最大长度,最后再+1就是next[j]的值

这里就是取ababab的前缀和后缀进行对比

 

(说明:这里不难看出串的后缀再多取一个就是babab显然与串前缀多取一个的ababa不同,所以最长为4则next[7]=5)

 

特别的:当第一个就匹配失败时就应该从模式串的头开始匹配

也就是next[1]=0

 

一般来说模式串的第一个和第二个字符也就是next[1],next[2]无脑填0和1就行了

 

另一种描述

 

四、求next数组练习

练习1:

序号j

1

2

3

4

5

6

模式串

a

b

a

b

a

a

next[j]

无脑0

无脑1

1

2

3

4

被比较的串

a

ab

aba

abab

ababa

练习2:

序号j

1

2

3

4

5

模式串

a

a

a

a

b

next[j]

0

1

2

3

4

 

五、计算next数组代码

 

void get_next(SString T,int next[]){

int i=1,j=0;

next[1]=0;

while(i<T.length){

if(j==0||T.ch[i]==T.ch[j]){

i++;

j++;

//若pi=pj,则next[j+1]=next[j]+1

next[i]=j;

}

else{

//否则j=next[j],循环遍历

j=next[j];

}

}

}

 六、KMP优化

1、方法

将next数组优化为nextval数组

序号j

1

2

3

4

5

6

模式串

g

o

o

g

l

e

next[j]

0

1

1

1

2

1

nextval

0

1

1

0

2

1

在该模式串的next数组中会发现当j=4时发生匹配失败时,会跳转到1但是4和1都是g,就平白无故多了一次比较

所以不妨直接将4设为1

 

 

为了更直观,我们用一个特殊的模式串

序号j

1

2

3

4

5

模式串

a

a

a

a

b

next[j]

0

1

2

3

4

nextval[j]

0

0

0

0

4

一种优化方法:从左向右检测,若右边的字符与左边的字符相同则把左边的nextval值赋给右边

 

2、求nextval代码

//nextval数组求法

int nextval[T.length+1];

for(int j=2;j<T.length;j++){

if(T.ch[next[j]]=T.ch[j])

nextval[j]=nextval[next[j]];//因为前面一定先被赋值,所以nextval[next[j]]一定是有值的

else

nextval[j]=next[j];

}

 

七、小结

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值