您的位置:首页 > 编程语言

KMP算法(代码+图解证明)

2016-09-08 17:09 281 查看
        KMP算法用于字符串匹配,是相较于朴素字符串匹配。所谓朴素字符串匹配就是从头到尾开始一个位置一个位置匹配,当前位置匹配失败则会从下一个位置开始继续匹配。

        KMP算法则是可以跳,能往前跳多远就往前跳多远。我们知道算法尽量要简化计算、去冗余、记忆搜索。KMP就是利用了去冗余的思想往前跳到某一位置继续匹配。而中间未匹配的丝毫不会有影响,这要归结于我们next数组的定义。

       所谓next数组中next[i]就是记录如果当前位置位置不匹配,字符串可以往前跳多远进行重新匹配。所以next[i]就是计算i之前字符串的最大回文长度(就是前缀和后缀相等的最大长度)。中间跳跃的点都是不用匹配的点,这个可以证明。



       如图,我们中间跳过的位置,如果存在有用的,即b'>b的长度。这种情况反证了我们b计算错误,也即我们next数组没求最长的,也就是没求对。故而,跳过的就是没用的。
       那么指导跳跃的next数组的求法如下图所示。



       上图演示的是next[i]这一位的计算方法,使用到了递归。这些说明白了,直接上代码。
#include<iostream>
#include<string>
using namespace std;

int * getNextArray(string ms) {
if (ms.length() == 1) {
int *a=new int[1];
a[0]=-1;
return a;
}
int* next = new int[ms.length()];
next[0] = -1;
next[1] = 0;
int pos = 2;
int cn = 0;
while (pos < ms.length()) { //next数组从2之后大于等于0
if (ms[pos - 1] == ms[cn]) {
next[pos++] = ++cn;
} else if (cn > 0) {
cn = next[cn];
} else {
next[pos++] = 0;
}
}
return next;
}

//s是原串,m是模式串
int getIndexOf(string s, string m) {
if (s == "" || m == "" || m.length() < 1 || s.length() < m.length()) {
return -1;
}

int si = 0;
int mi = 0;
int* next = getNextArray(m);
while (si < s.length() && mi < m.length()) {
if (s[si] == m[mi]) {
si++;
mi++;
} else if (next[mi] == -1) {
si++;
} else {
mi = next[mi];
}
}
return mi == m.length() ? si - mi : -1;
}

      KMP算法其实不难,仔细研究下就可以理解了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  KMP next 递归