字符串匹配KMP算法

字符串匹配算法在文本搜索、DNA序列分析等领域有广泛应用。KMP算法是一种线性时间复杂度的高效算法,通过计算模式串的最长相同前后缀避免无效匹配。本文介绍了KMP算法的基本思想、伪代码及优化,并提供了多个学习资源。
摘要由CSDN通过智能技术生成

字符串匹配,应用主要在文本搜索,DNA序列中搜索特定的序列,搜索引擎查询特定网页地址等。
字符串匹配算法大概有:
1.朴素算法 (如GCC4.8 实现的 strstr 函数)
2.Rabin-Karp
3.有限自动机算法
4.Knuth-Morris-Partt

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

算法预处理时间匹配时间
朴素算法0 O((nm+1)m)
Rabin-Karp Θ (m) O((nm+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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值