终于弄懂KMP算法了

1.简例弄懂KMP-点此链接查看

看了上面的文章,你肯定大概明白了KMP的运作原理,但是你可能对于文章提到的“部分匹配值”的又来还存在疑惑,那么请继续往下看:

我们先抛出两个问题,当目标字符串i指针与模式字符串j指针失配时:
1、当母串和模式串不匹配时,i指针为什么不需要回溯?
2、当母串和模式串不匹配时,i指针不回溯,那么j指针应该移动到哪?
通过解释第1个问题,我来引出第2个问题。(其实第1个问题,你不明白,不影响你研究第2个问题,你也可以理解了第2个问题后来分析第1个问题。)
对于母串S和模式串T,如果母串的指针i处与模式串的j处失配,假设母串存在回溯i到back(i) (匹配前的i < back(i) < i),有与模式串的从0开始的模式串有一段一样长的“段落”,这个母串的段落只有是S[back(i)] 至S[i-1]才有意义,如果从S[back(i)] 至S[i-1]的过程中就已经不匹配了,那回溯至这个back(i)就更没有必要了。 即S[back(i) …i-1]=T[0…x] ,x = i-1-back(i)。又因为前面失配时存在同样长度的段落,即S[back[i]…i-1] = T[ j -1-x… j-1],所以T[0…x] = T[j-1-x …j-1]

这其实就转化成了i不变,j指针移动到x+1(后面讨论用next[j] 表示 x +1 )的问题。

看到这儿,虽然我们应该已经理解了KMP算法的运作原理,那么如何求模式传T匹配失败时的指针移动值next[j]呢:

C code--
void GetNextArrayForKMP(char *sub_str, int *next)
{
  int i = 0, j = -1, len = strlen(sub_str);
  next[0] = -1;    // printf("i = 0; j = -1; next[0] = -1 \n");
  while (i < len - 1) {
    if (j == -1 || sub_str[i] == sub_str[j]) {
      ++i;         // printf("++i = %d; ", i);
      ++j;         // printf("++j = %d; ", j);
      next[i] = j; // printf("next[%d] = %d; ", i, j);
    } else {
      j = next[j]; // printf("j = next[j] = %d ; ", j);
    }              // printf("\n");
  }
}

在kmp函数中,next使用是因为出现了失配现象:即当前模式串和主串字符不等,但是他们前面的字符都匹配。失配时模式串当前位置pj,主串的当前位置si。
失配时假设模式串不进行回溯,而调到k位置,即前面的k-1个字符和主串当前位置si的前k-1个字符匹配,然而主串的k-1字符和模式串当前位置pj的k-1位置匹配。因此模式串前k-1个字符和模式串当前位置pj的前k-1个字符匹配,即:P1…Pk-1 = Pj-k+1…Pj-1
求next的函数跟kmp函数非常类似。
求next数组时候,模式串sub_str既是主串又是模式串。
代码中i指向的是主串,j指向的是模式串,当sub_str[i] != sub_str[j]时候,说明出现了失配现象,模式串需要改变位置,j = next[j];

猜你喜欢

转载自blog.csdn.net/weixin_41660162/article/details/81638750