KMP算法之next函数值序列求解法,不会的进来看看,学不会你找我

目录

一、前言

二、KMP算法

三、试题

四、解题方法


一、前言

在最近做软考题的时候用到了KMP算法的题,刚开始感觉很难,不会做,所以在网上查了很多方法,在查的过程中发现了一个很高效的方法,分享给需要的人。

二、KMP算法

KMP算法是一种改的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,因此人们称它为克努特——莫里斯——普拉特操作(简称KMP算法)。KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息。时间复杂度O(m+n)。

大多数据结构课本中,串涉及的内容即串的模式匹配,需要掌握的是朴素算法、KMP算法及next值的求法。

三、试题

1.试题

在KMP模式匹配算法中,需要求解模式串p的next函数值,其定义如下(其中,j 是字符在模式串中的序号)。对于模式串“abaabaca”,求其next函数值序列。

此题是一道软考题,我们就以这道题为例看看他们解法。

2.公式

四、解题方法

1.先将这个字符串写出来。

a

 b

a

a

 b

a

c

 a

2.写出这些字符串前缀式和后缀式,当他们前缀和后缀一样的数有几个就写几个,没有就写0.

从以上图可以看出,将他们相同的字母找出来了,有相同的用直线表示,不相同的用0表示,这些也是求出来的最长串的数字。

3.为这些字符串标下标。

1

2

3

4

5

6

7

8

a

 b

a

a

 b

a

c

 a

4.接下来就是就要把上图中求出来的最长串的数字写在这个模式串下面。此时下面这一串数字并不是我们所要求的next函数值序列

0

0

1

1

2

3

0

1

5.接下来就是最重要的部分了。将求出来的最长串数字复制到模式串下面。

1

2

3

4

5

6

7

8

a

 b

a

a

 b

a

c

 a

0

0

1

1

2

3

0

1

然后去掉最后一个值。去掉之后就剩00112301了。

6.接下来在在开头加上一个-1,将整个数字序列后移一位,得到得值如下表格。

1

2

3

4

5

6

7

8

a

 b

a

a

 b

a

c

 a

-1

0

0

1

1

2

3

0

7.此时也是最后一步了,每个值+1

1

2

3

4

5

6

7

8

a

 b

a

a

 b

a

c

 a

0

1

1

2

2

3

4

1

到这里就完成整个题的解了,感觉这中方法挺高效的,我也是刚开始学习,如果有错还请指出,进行改进。在这里就只是说了一下next函数值序列的求解法,具体的思想和方法就不说了,此方法只适合简单的做题

### KMP字符串匹配算法的改进版本及其C语言实现 #### 改进版KMP算法概述 传统的KMP算法已经能够有效地处理大多数字符串匹配问题,但在某些特定情况下仍存在优化空间。一种常见的改进步骤是在构建`next`数组时引入更高效的方法来跳过不可能成功的比较位置。 对于传统KMP中的`next`数组,在遇到不匹配情况时可以提供跳跃指导,使得模式串不必回溯到起始位置重新尝试匹配。然而,当面对大量重复字符或周期性结构较强的模式串时,标准方法可能不是最优解法[^1]。 为了进一步提升性能,可以在初始化阶段对`next`数组做额外预处理,创建所谓的“增强型”或“优化过的”`nextval`数组。这个新数组不仅记录了前缀长度信息,还考虑到了当前位之后是否存在相同的子序列,从而允许更大的步幅前进[^2]。 #### `nextval` 数组的构建逻辑 在构造`nextval[]`的过程中,除了遵循常规`next[]`规则外,还需检查当前位置j处与其对应的最长相等前后缀结尾k是否一致;如果两者相同,则令`nextval[j]=nextval[k]` ,否则保持不变即`nextval[j]=next[j]` 。这种调整有助于消除冗余移动并加快搜索速度[^3]。 下面是基于上述描述的一个完整的改进KMP算法C语言实现: ```c #include <stdio.h> #include <string.h> void get_next_val(const char* pattern, int* nextVal){ int length = strlen(pattern); int i = 0; int j = -1; nextVal[0]=-1; while (i<length-1){ if(j==-1 || pattern[i]==pattern[j]){ ++i; ++j; // 当前字符与对应最大公共前后缀最后一个字符不同则直接赋值 if(pattern[i]!=pattern[j]) nextVal[i]=j; else// 否则取其之前的最大公共前后缀的位置 nextVal[i]=nextVal[j]; } else{ j=nextVal[j]; } } } int kmp_search(const char* text, const char* pattern,int* nextVal){ int n=strlen(text),m=strlen(pattern); int i=-1,j=-1; while(i<n && j<m){ if(-1==j||text[i]==pattern[j]){ i++; j++; }else{ j=nextVal[j]; } if(m<=j) break; } return ((n-i+m)>n)?-1:(i-m); } int main(){ const char str[]="abcxabcdabcdabcy"; const char pat[]="abcdabcy"; int nextVal[strlen(pat)]; memset(nextVal,-1,sizeof(int)*strlen(pat)); get_next_val(pat,nextVal); printf("Pattern found at index %d\n",kmp_search(str,pat,nextVal)); } ``` 此程序首先定义了一个辅助函数`get_next_val()`用于生成经过改良后的`nextVal[]`数组,接着实现了核心的`kmp_search()`函数来进行实际的字符串查工作。最后,在`main()`入口点展示了如何调用这两个功能完成一次具体的匹配操作[^4]。
评论 87
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值