代码cover:小白也能看懂的KMP算法
KMP算法代码:
#include#include #include using namespace std; //暴力匹配算法 int ViolentMatch(char *s, char *p) { int sLen = strlen(s); int pLen = strlen(p); int i = 0; int j = 0; while (i < sLen && j < pLen) { if (s[i] == p[j]) { //①如果当前字符匹配成功(即S[i] == P[j]),则i++,j++ i++; j++; } else { //②如果失配(即S[i]! = P[j]),令i = i - (j - 1),j = 0 i = i - j + 1; j = 0; } } //匹配成功,返回模式串p在文本串s中的位置,否则返回-1 if (j == pLen) return i - j; else return -1; } //KMP算法 int KmpSearch(char *s, char *p, int *next) { int i = 0; int j = 0; int sLen = strlen(s); int pLen = strlen(p); while (i < sLen && j < pLen) { //①如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++ if (j == -1 || s[i] == p[j]) { i++; j++; } else { //②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j] //next[j]即为j所对应的next值 j = next[j]; } } if (j == pLen) return i - j; else return -1; } //得到next数组 void GetNext(char *p, int next[]) { int pLen = strlen(p); next[0] = -1; int k = -1; int j = 0; while (j < pLen - 1) { //p[k]表示前缀,p[j]表示后缀 if (k == -1 || p[j] == p[k]) { ++k; ++j; next[j] = k; } else { k = next[k]; } } } int main() { string p = "ababaaaba"; int next[200] = {0}; int len = p.length(); GetNext(&p[0], next); for (int i = 0; i < len; i++) { cout << next[i] << " "; } cout << endl; string s = "aaabbbababaaaba"; int index = KmpSearch(&s[0], &p[0], next); cout << index << endl; return 0; } // 备注: // 特别说明 在本例(暴力搜索)中 如果失配 是文本串当下被匹配到的坐标减下去模式串已经匹配了的位数 // 这样拿到了文本串此次被匹配部分的第一个坐标i-j, // 然后为了从它的下一位开始重新与模式串匹配+1,也就是i-j+1 // 注意:有的博客代码示例会把写为i-j+2,那是因为他们采取的字符串存储方式是 // 用s[0]来存放传的长度,串值放在s[1]到s[max] 例如Pascal语言就是这样 //那有没有一种算法,让文本串的坐标i不往回退,只需要移动模式串即可呢? //答案是肯定的。这种算法就是本文的主旨KMP算法,它利用之前已经部分匹配这个有效信息, //保持i不回溯,通过修改j的位置,让模式串尽量地移动到有效的位置, 从而减少性能浪费 //KMP算法 //假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置 //如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++,继续匹配下一个字符; //如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]。 //此举意味着失配时,模式串P相对于文本串S向右移动了j - next[j]位。 //换言之,当匹配失败时,模式串向右移动的位数为:失配字符所在位置 - 失配字符对应的next值 //即移动的实际位数为:j - next[j],且此值大于等于1。 //next数组各值的含义 //很快意识到next数组各值的含义:代表当前字符之前的字符串中,有多大长度的相同前缀后缀。 //例如如果next[j] = k,代表j之前的字符串中有最大长度为k的相同前缀后缀。 //此也意味着在某个字符失配时,该字符对应的next值会告诉你下一步匹配中,模式串应该跳到哪个位置(跳到next[j]的位置)。 //如果next [j] 等于0或-1,则跳到模式串的开头字符,若next [j] = k 且 k > 0, //代表下次匹配跳到j 之前的某个字符,而不是跳到开头,且具体跳过了k 个字符。 //要想更深入了解KMP算法,可参考上面的博客链接



