KMP算法(各种模板)

xiaoxiao2021-02-28  89

转载自 http://blog.csdn.net/starstar1992/article/details/54913261#comments

用于解决字符串匹配的问题

求next数组

void cal_next(char *str, int *next, int len) { next[0] = -1;//next[0]初始化为-1,-1表示不存在相同的最大前缀和最大后缀 int k = -1;//k初始化为-1 for (int q = 1; q <= len-1; q++) { while (k > -1 && str[k + 1] != str[q])//如果下一个不同,那么k就变成next[k],注意next[k]是小于k的,无论k取任何值。 { k = next[k];//往前回溯 } if (str[k + 1] == str[q])//如果相同,k++ { k = k + 1; } next[q] = k;//这个是把算的k的值(就是相同的最大前缀和最大后缀长)赋给next[q] } } KMP

int KMP(char *str, int slen, char *ptr, int plen) { int *next = new int[plen]; cal_next(ptr, next, plen);//计算next数组 int k = -1; for (int i = 0; i < slen; i++) { while (k >-1&& ptr[k + 1] != str[i])//ptr和str不匹配,且k>-1(表示ptr和str有部分匹配) k = next[k];//往前回溯 if (ptr[k + 1] == str[i]) k = k + 1; if (k == plen-1)//说明k移动到ptr的最末端 { //cout << "在位置" << i-plen+1<< endl; //k = -1;//重新初始化,寻找下一个 //i = i - plen + 2;//i定位到找到位置处的下一个位置(这里默认存在两个匹配字符串可以部分重叠) return i-plen+1;//返回相应的位置 } } return -1; }另一种模板(更加好记的模板) http://blog.csdn.net/v_july_v/article/details/7041827

void makeNext() { int q,k; int m = strlen(p); nextt[0] = 0; for (q = 1,k = 0; q < m; ++q) { while(k > 0 && p[q] != p[k]) k = nextt[k-1]; if (p[q] == p[k]) { k++; } nextt[q] = k; } } void kmp() { int n,m; int i,q; n = strlen(t); m = strlen(p); makeNext(); for (i = 0,q = 0; i < n; ++i) { while(q > 0 && p[q] != t[i]) q = nextt[q-1]; if (p[q] == t[i]) { q++; } if (q == m) { cnt++; //return i-m+1; } } }

关于next数组未优化过的

void getnext(string x){ int j = -1; int k = 0; NEXT[k] = -1; int l = x.length(); while(k != l){ if(j == -1 || x[j] == x[k]) NEXT[++k] = ++j; else j = NEXT[j]; } } int KmpSearch(char* s, char* p) { int i = 0; int j = 0; int sLen = strlen(s); int pLen = strlen(p); while (i < sLen) { //①如果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; //cnt++; //k = 0, i++; } } return -1; }

优化过的

void getnext(const char *p) //前缀函数(滑步函数) { int i = 0, j = -1; nextval[0] = -1; while(i != len) { if(j == -1 || p[i] == p[j]) //(全部不相等从新匹配 || 相等继续下次匹配) { ++i, ++j; if(p[i] != p[j]) //abcdabce nextval[i] = j; else //abcabca nextval[i] = nextval[j]; } else j = nextval[j]; //子串移动到第nextval[j]个字符和主串相应字符比较 } }

转载请注明原文地址: https://www.6miu.com/read-80781.html

最新回复(0)