KMP算法

KMP算法

    看了一下网上的KMP算法,发现讲的都不大适合我,个人觉得还是严蔚敏的书上讲的比较简单明了清晰,适合我理解,所以就整理了一下。

    KMP算法之所以叫做KMP算法是因为这个算法是由三个人共同提出来的,就取三个人名字的首字母作为该算法的名字。其实KMP算法与BF算法的区别就在于KMP算法巧妙的消除了指针i的回溯问题,只需确定下次匹配j的位置即可,使得问题的复杂度由O(mn)下降到O(m+n)。

    假设主串为's1s2s3...sn',模式串为'p1p2p3...pm',当主串中第i个字符与模式中第j个字符失配时,主串中第i个字符(i指针不回溯)应与模式中那个字符再比较。

    假设此时应与模式中第k(kk满足下列关系式

'p1p2p3...p(k-1)' = 's(i-k+1)s(i-k+2)...s(i-1)'

而已经得到的"部分匹配"的结果是

'p(j-k+1)p(j-k+2)...p(j-1)' = 's(i-k+1)s(i-k+2)...s(i-1)'

由上述两式可得:

'p1p2p3...p(k-1)' ='p(j-k+1)p(j-k+2)...p(j-1)'

令next[j] = k 则

next[j] = 0 当j = 1 时

= Max{k | 1 < k < j 且 'p1...p(k-1)' = 'p(j-k+1)...p(j-1)'}当此集合不为空时

= 1 其他情况

next函数值 j |1 2 3 4 5 6 7 8

    模式串 |a b a a b c a c

  next[j] |0 1 1 2 2 3 1 2

int Index_KMP(SString S, SString T, int pos){
     //利用模式串T的next函数求T在主串S中第pos个字符之后的位置的KMP算法。其中,T非空,1<=pos<=StrLength(s).
    i = pos;  j = 1;
    while(i <= S[0] && j <= T[0]){
        if(j == 0 || S[i] == T[j]){i++;j++}	//继续比较后续字符串
        else j = next[j];		//模式串向右移动
    }
    if(j > T[0]) return i - T[0];	//匹配成功
    else return 0;
}

 
  
 上面的next尚有缺陷例如 
  

j | 1 2 3 4 5 

模式  | a a a a b

       next[j] | 0 1 2 3 4

  nextval[j] | 0 0 0 0 4

改进的算法为:

void get_nextval(SString T, int next[]){
    //求模式串T的next函数值并存入数组nextval[]
    i = 1; nextval[1] = 0; j = 0;		//i存储的匹配到哪,j为匹配的数值
    while(i < T[0]){
        if(j == 0 || T[i] == T[j]){
            ++i; ++j;
            if(T[i] != T[j]) nextval[i] = j;
            else nextval[i] = nextval[j];
        }else j = nextval[j];
    }
}




你可能感兴趣的:(算法,算法)