KMP 简析

Knuth-Morris_Pratt 字符串匹配算法(参考算法导论)

预处理时间: O(m)   匹配时间:O(n)

思路:对于模式字符串P,预处理出模式字符串之间的匹配数组a;然后在文本T中根据匹配数组a进行一轮搜索。


一.预处理:

在预处理中,已知一个模式字符串P[1..m],对于a[q],找寻P_a子字符串中最长的前缀长度,同时满足此前缀也是P_a字符串的后缀。如对于“ababa”,前缀“aba”同时也是“ababa”的后缀,所以a[4]=3。

这里设定a[0]=0。

可以得到如下的模式P及其匹配数组a的对应值:

i 1 2 3 4 5 6 7 8 9 10
P[i] a b a b a b a b c a
a[i] 0 0 1 2 3 4 5 6 0 1
匹配代码如下:

int calMatcherArray(string p,int* a,int n){ //计算匹配数组a
    int i;
    a[0]=0;
    for(i=1;i<n;i++){
        if(p[i]==p[a[i-1]])a[i]=a[i-1]+1;
        else a[i]=0;
    }
    return 1;
}
二.匹配搜索:

对文本T进行 逐字符搜索,对于不匹配字符,根据匹配数组a对模式字符串P当前搜索位置进行调整。代码如下:

int kmpSearch(string t,string p){
    const int pLen = p.length(),tLen=t.length();
    int a[pLen],i=0,s=0;
    calMatcherArray(p,a,pLen);
    for(int j=0;j<tLen;j++){
        if(t[j]==p[i])i++;  //如果t当前字符等于p当前字符,同增1并进行下一个字符搜索
        else if(i==0)s=j+1; //如果当前字符不相等,如果i==0,从t下一个字符从p[0]重新搜索
        else if(t[j]==p[a[i-1]]){  //如果t当前字符等于匹配数组i-1所指的p字符,则下一个字符从p[a[i-1]+1]重新搜索
            i=a[i-1]+1;
            s=j-a[i-1];
        }else{  //此时说明t当前字符不符合所有匹配规则,下一个字符从p[0]重新搜索
            i=0;
            s=j+1;
        }
        cout<<i<<endl;
        if(i==pLen)return s;
    }
    return -1;
}

你可能感兴趣的:(KMP)