字符串模式匹配之KMP算法图解与 next 数组原理和实现方案 (2)

那么通过观察来思考:每当临时匹配串(已知的)前后有重复的时候,那么只需 把模式串 T 直接移动到后缀刚刚开始有重复的位置(设移动距离为 d),i 不回溯。也就是j 直接反向的回溯距离 d,亮着等价的。为什么这样?

因为,在字符串搜索和匹配的时候,经常有前后重复的时候,前缀和后缀重复!如倒数第3图的已知的临时匹配串abca,前后缀 a 重复!此时没必要再用模式串的首位a去和S 的 b 比较了,直接和前后缀子串第一次有重复的位置比较(设子串右移距离 d),也就是 a 处。如果还那么顺次比较,是做无用功!此时思考如何实现这个逻辑,找到对应的j 回溯的距离 d。这个距离 d 就是前后重复的字符串的距离。

设置一个数组next来返回模式串的 j 应该回溯的位置

若令数组next[j]=k,则next[j]表明当模式中第j个字符与主串中相应字符失配时,在模式中需要重新和主串中该字符进行比较的字符的位置。

得到 KMP 模式匹配算法的实现思路(区别就是 next 函数)

那么问题来了,如何实现 next数组 ,生成对于的 j回溯的位置,从前面的讨论可知,next数组值仅取决于模式串本身,而与主串无关。

j 的回溯距离d 等于模式串中临时匹配串长(也就是j) 减去 相同的前后缀子串中的最大子串长度S(两个最大子串的距离),next 的值就是 j - j + S =S因此要计算next函数的返回值,就要找出前缀和后缀相同的最大子串的长度。

这个查找过程实际上仍然是模式匹配,只是匹配的模式与目标在这里是同一个串S。(这里遵守 c 的规定,数组都是默认下标0开始存储)

//计算 next 数组:根据待匹配的字符串,求出对应每一位的最大相同前后缀的长度 void computeNext(char *str, int next[]) { } int strKMPCompare(char *strMain, char *strSub, int index, int next[]) { int iMain = index; int jSub = 0; int lenMain = getLength(strMain); int lenSub = getLength(strSub); while ((iMain >= 0 && iMain <= lenMain - 1) && ((jSub >= 0 && jSub <= lenSub - 1))){ if (strMain[iMain] == strSub[jSub]) { iMain++; jSub++; }else{ //主串的 i 不回溯! //计算 next 数组 computeNext(strSub, &next[0]); jSub = next[jSub]; } } //如果匹配 ok,肯定子串先比完。 if (jSub > lenSub - 1) { return iMain - lenSub;//得到的就是匹配 ok 后,主串里第一个和模式串第一个字符匹配的字符的位置 }else{ return 0;//匹配失败 } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgzxdz.html