文章目录
一、什么是KMP算法
- KMP算法是一种改进的字符串匹配算法,KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。相较于暴力算法来说能够极大程度地节约时间。
二、KMP算法的运行原理
1、主串不回退
- 就如上图这个例子,我们要判断主串中是否存在子串。按照通常的算法,我们会很容易想到用主串的每一位与子串比较。在这个例子中我们可以发现主串的第四个字母与子串的第四个字母不同。所以这一次查找就失败了,需要进行下一次查找。
- 在这个基础上,一般的算法需要把主串回退到第二个字母,子串回退到第一个字母处再进行下一次查找。但在KMP算法中,主串不会回退,它会继续停留在原来的位置上,然后子串回退到特定位置,进行下一次查找。
子串回退到特定位置
通过之前两个字符串,我们当发现主串的第四个字母与子串的第四个字母不同之后,主串不会退,子串回退到特定的位置。那么,这个特定位置是如何找到的呢?
这里我们重新设立两个字符串进行查找,并对它们标上相应的下标。
- 当主串下标为5时,子串下标也为5。此时匹配便失败了。但我们可以发现,子串下标为5的字符前面还有5个字母,这五个字母是与主串下标为5之前的5个字母相对应的。这样也就表明我们可以直接通过子串自身来判断这个所谓的特定位置。 比如在子串2中,当5号位断开后我们发现3,4号位于0,1号位的字符一样,所以子串就可以跳到二号位,然后把子串的二号位与主串的5号位相比较。
- 通过上面的了解,我们可以得出子串能自己决定自己的回退位置。那么我们就可以设置一个next()数组用来表示子串的回退。
三、next()数组的实现
1、next()数组的原理
- 通过上文我们可以知道next()的关键就是在子串中找到能够重复的部分,且其中一部分一定是从0开始的。 为了方便函数设计,我们假设在第一个字母就不匹配时会回退到-1号位,在第二个字母不匹配时,我们回退到第0个位置。然后设立一个p指针和一个k指针来查找子串中的重复部分。
- 每当不匹配时,p指针会按照已有的next()回退,然后p为-1时或者p对应位置字母与k-1对应字母相同时,k对应位置值为p + 1,然后p和k同时向右移动一位继续上述动作。
- 以上图为例,在最开始的位置时,p下标为0,k下标为2。此时开k - 1对应字母与p对应字母不相等,p回退到-1,然后-1处不再回退,且没法比较,则next[k]为p + 1即0,然后k + 1, p + 1;然后依次重复上述操作,当k来到k1处时,p依旧在0的位置。此时我们可以大仙k1 - 1对应的字母与p对应字母相同,则next[k]就等于p1 + 1即1,然后p1 + 1, k1 + 1,p来到了p2位置,k来到了k2位置。同样能发现k2 - 1对应字母与p2对应字母相等,则next[k2]为p2 + 1即2,然后p2移动到p3,k2移动到k3。但是这时k3 - 1对应字母与p3对应字母不相等了,所以k3保持不动,p3通过p = next[p3]回退到p1的位置, 然后发现p1对应的字母与k3 - 1对应的字母相等p不用继续回退了,所以next[k3]就为p1 + 1即1;
2、#代码实现(C语言)
void getnext(int* next,</