`
imBa_MarlBoro
  • 浏览: 4135 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
最近访客 更多访客>>
社区版块
存档分类
最新评论

Pattern-Matching-1.KMP算法

 
阅读更多

许久之前的数据结构课上就已经学过大名鼎鼎的KMP算法,可是学一次忘一次,最近又要使用这个令人头疼的算法,于是打算把他记下来。

 

思考这样一个问题,给定了两个字符串:X=“bacbababababcaa”,Y="ababababca"。如何来判定Y是否是X的字串?

 

传统的朴素匹配方法,肯定是做一次双重循环,让Y中的每个字符与X中的每个字符一一匹配,如果刚好可以匹配上,那么Y就是X的字串了。可是这种方法有着很多的不必要的比较。于是,KMP算法的思想便是跳过这些不必要的操作。

 

KMP的关键问题是当循环中两个串当前的字符不匹配时,下一步应该比较那个字符?这个问题事实上也是算法改进的关键问题。

 

由当前不匹配字符到下一个被比较字符,我们可以看作一次“跳跃”,于是我们的问题便变成了-”跳跃“的规则是什么?

 

为了实现这种”跳跃“,我们引入了一个next数组,他的长度为匹配串pattern的长度,数组上的每个元素代表了匹配串当前字符不匹配时应该”跳跃“后进行下一次匹配的索引。

 

有了这些理论基础我们便可以写出KMP算法。

 

伪码参考算法导论,下面贴出详细代码。

/**
 * KMP算法,返回第一个字串的起始位置,如果pattern非s字串返回-1 
 * 
 */
int kmpMatcher(char* s, char* pattern)
{
    int m = strlen(pattern);
    int n = strlen(s);
    int* next = new int[m];
    computeNext(pattern,next,m);
    int q=-1;
    for(int i=0; i<n ; ++i){
        while(q>=0 && pattern[q+1]!=s[i]){
            // 不匹配情况 
            q=next[q];
        }
        if(pattern[q+1]==s[i]){
            // 匹配情况下,继续 
            q=q+1;
        }
        if(q==m-1){
            return i-m+1;
        }
    }
    return -1;  // doesn't match
}

 

接下来就是算法中的next数组获取问题。

 

假设当前我们要获取pattern串中i号位置的next值,即next[i]的值。我们知道,如果要实现”跳跃“k个元素,那么pattern串中i之前的k个元素要和pattern串中的前k个元素相同,即pattern[1...k]=pattern[i-k+1...i],此时的next[i]=k

 

由上述逻辑可得到代码如下:

/**
 *  计算next函数 
 *
 */
void computeNext(char* pattern, int* &next, int m)
{
    // 长度必须大于0 
    if(m<=0){
        return;
    }
    next[0]=-1;
    for(int i=1; i<m; i++){
        int j=next[i-1];
        while(j>=0 && pattern[j+1]!=pattern[i]){
            j=next[j];
        }
        if(pattern[j+1]==pattern[i]){
            next[i]=j+1;
        } else {
            next[i]=j;
        }
    }
}

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics