字符串匹配KMP算法
2017-10-17 12:30
316 查看
字符串匹配,应用主要在文本搜索,DNA序列中搜索特定的序列,搜索引擎查询特定网页地址等。
字符串匹配算法大概有:
1.朴素算法 (如GCC4.8 实现的 strstr 函数)
2.Rabin-Karp
3.有限自动机算法
4.Knuth-Morris-Partt
它们的预处理时间和匹配时间如下:
下面指说第1和第4中算法,其他算法可以看《算法导论》
朴素算法:
朴素算法就是以子字符串sub上的第一个字符对准字符串s上的第一个字符,然后进行匹配,如果发现不匹配,那么sub上的第一字符移动到s字符串的第二个字符进行对准继续匹配,就这样每一次不匹配,都是只移动一个字符然后继续匹配,直到匹配到或者直到字符串s的尾部结束。
(1) gcc 4.8 中 strstr 实现方法
(2) 其他写法1
(3)巧妙一点写法
KMP算法
KMP算法全称叫Knuth-Morris-Pratt算法, 因为它是由Knuth、Morris和Pratt三人设计的线性时间字符串匹配算法。
个人比较懒,就不上图了,请查看给出链接的图片:
KMP算法的核心思想就是:
在简单的一次匹配失败后,我们会想将模式串尽量的右移和主串进行匹配。右移的距离在KMP算法中是如此计算的:在已经匹配的模式串子串中,找出最长的相同的前缀和后缀,然后移动使它们重叠。
在第一次匹配过程中:
T: a b a c a a b a c a b a c a b a a b b
P: a b a c a b
在T[5]与P[5]出现了不匹配,而T[0]~T[4]是匹配的,现在T[0]~T[4]就是上文中说的已经匹配的模式串子串,现在移动找出最长的相同的前缀和后缀并使他们重叠.
伪代码:
KMP-MATCHER(T,P)
COMPUTE-PREFIX-FUNCTION(P)
KMP算法:
http://www.cnblogs.com/c-cloud/p/3224788.html (这个感觉看起来好理解一些)
KMP算法优化:
http://wiki.jikexueyuan.com/project/kmp-algorithm/define.html(这个比较长)
参考:
[1]v_JULY_v.从头到尾彻底理解 KMP[EB/OL]. http://wiki.jikexueyuan.com/project/kmp-algorithm/introduction.html.
[2]c_cloud.【经典算法】——KMP,深入讲解next数组的求解[EB/OL]. http://www.cnblogs.com/c-cloud/p/3224788.html
[3]算法导论(原书第三版).[M].(美)科尔曼(Cormen, T.H)等著;段建平等译. 北京: 机械工业出版社
[4]流云哭翠.KMP算法详解. http://blog.chinaunix.net/uid-27164517-id-3280128.html
[5]于明昊.KMP算法解析[EB/OL].http://www.ituring.com.cn/article/59881
[6]百度百科.kmp算法[EB/OL].https://baike.baidu.com/item/kmp%E7%AE%97%E6%B3%95/10951804
字符串匹配算法大概有:
1.朴素算法 (如GCC4.8 实现的 strstr 函数)
2.Rabin-Karp
3.有限自动机算法
4.Knuth-Morris-Partt
它们的预处理时间和匹配时间如下:
算法 | 预处理时间 | 匹配时间 |
---|---|---|
朴素算法 | 0 | O((n−m+1)m) |
Rabin-Karp | Θ(m) | O((n−m+1)m) |
有限自动机算法 | O(m|Σ|) | Θ(n) |
KMP算法 | Θ(m) | Θ(n) |
朴素算法:
朴素算法就是以子字符串sub上的第一个字符对准字符串s上的第一个字符,然后进行匹配,如果发现不匹配,那么sub上的第一字符移动到s字符串的第二个字符进行对准继续匹配,就这样每一次不匹配,都是只移动一个字符然后继续匹配,直到匹配到或者直到字符串s的尾部结束。
(1) gcc 4.8 中 strstr 实现方法
char *strstr(const char *s1, const char *s2) { const char *p = s1; size_t len = strlen(s2); for (; (p=strchr(p, *s2)) != NULL; ++p) if (0 == strncmp(p, s2, len)) return (char*)p; return NULL; }
(2) 其他写法1
int ViolentMatch(const char *s, const 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]) { //(1)如果当前字符匹配成功(即S[i]==P[j]), 则i++, j++ ++i; ++j; } else { //(2)当前字符匹配失败(即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; }
(3)巧妙一点写法
int VoilentMatch(char T[], char P[], int pos) { int i = pos; int j = 0; while (T[i+j] != '\0' && P[j] != '\0') { if (T[i+j] == P[j]) ++j; else { ++i; j = 0; } } if (P[j] == '\0') return i; else return -1; }
KMP算法
KMP算法全称叫Knuth-Morris-Pratt算法, 因为它是由Knuth、Morris和Pratt三人设计的线性时间字符串匹配算法。
个人比较懒,就不上图了,请查看给出链接的图片:
KMP算法的核心思想就是:
在简单的一次匹配失败后,我们会想将模式串尽量的右移和主串进行匹配。右移的距离在KMP算法中是如此计算的:在已经匹配的模式串子串中,找出最长的相同的前缀和后缀,然后移动使它们重叠。
在第一次匹配过程中:
T: a b a c a a b a c a b a c a b a a b b
P: a b a c a b
在T[5]与P[5]出现了不匹配,而T[0]~T[4]是匹配的,现在T[0]~T[4]就是上文中说的已经匹配的模式串子串,现在移动找出最长的相同的前缀和后缀并使他们重叠.
伪代码:
KMP-MATCHER(T,P)
n = T.length m = P.length π= COMPUTE-PREFIX-FUNCTION(P) q = 0 // 已匹配字符个数 for i = 1 to n // 扫描text文本 while q > 0 and P[q+1] != T[i] q = π[q] // 下一个字符不匹配 if P[q+1] == T[i] q = q +1 // 下一个字符匹配 if q == m // 是否P模式字符串都匹配完 print"Pattern occurs with shitf" i-m q = π[q] // look for the next match
COMPUTE-PREFIX-FUNCTION(P)
m = P.length let π[1..m] be a new array π[1] = 0 k = 0 for q = 2 to m while k > 0 and P[k+1] != P[q] k = π[k] if P[k+1] == P[q] k = k + 1 π[q] = k return π
KMP算法:
http://www.cnblogs.com/c-cloud/p/3224788.html (这个感觉看起来好理解一些)
KMP算法优化:
http://wiki.jikexueyuan.com/project/kmp-algorithm/define.html(这个比较长)
参考:
[1]v_JULY_v.从头到尾彻底理解 KMP[EB/OL]. http://wiki.jikexueyuan.com/project/kmp-algorithm/introduction.html.
[2]c_cloud.【经典算法】——KMP,深入讲解next数组的求解[EB/OL]. http://www.cnblogs.com/c-cloud/p/3224788.html
[3]算法导论(原书第三版).[M].(美)科尔曼(Cormen, T.H)等著;段建平等译. 北京: 机械工业出版社
[4]流云哭翠.KMP算法详解. http://blog.chinaunix.net/uid-27164517-id-3280128.html
[5]于明昊.KMP算法解析[EB/OL].http://www.ituring.com.cn/article/59881
[6]百度百科.kmp算法[EB/OL].https://baike.baidu.com/item/kmp%E7%AE%97%E6%B3%95/10951804