您的位置:首页 > 其它

字符串匹配KMP算法

2017-10-17 12:30 260 查看
字符串匹配,应用主要在文本搜索,DNA序列中搜索特定的序列,搜索引擎查询特定网页地址等。

字符串匹配算法大概有:

1.朴素算法 (如GCC4.8 实现的 strstr 函数)

2.Rabin-Karp

3.有限自动机算法

4.Knuth-Morris-Partt

它们的预处理时间和匹配时间如下:

算法预处理时间匹配时间
朴素算法0O((n−m+1)m)
Rabin-KarpΘ(m)O((n−m+1)m)
有限自动机算法O(m|Σ|)Θ(n)
KMP算法Θ(m)Θ(n)
下面指说第1和第4中算法,其他算法可以看《算法导论》

朴素算法:

朴素算法就是以子字符串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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息