KMP算法详细解析(C/C++)

本文深入讲解了KMP算法的工作原理及实现过程,包括如何构建公共前后缀数组,以及如何利用这些信息来提高文本搜索的效率。通过具体示例,详细说明了算法在遇到不匹配时的处理方式,使读者能够理解并掌握这一高效字符串匹配算法。

从文本中找出匹配的单词或者字符串,使用kmp算法,效率提升很多,可以防止多次重复比较,浪费时间;前提是需要找到该字符串的公共前后缀,不至于从头比较:

大致思路如下:

如:
T : a a a a a a a a b
P  : a a a a b
找出P的公共前后缀:

  0: a
  1 : a a
  2 : a a a
  3 : a a a a
    : a a a a b  //总共五个字符,所以将前面的数组下移:

 -1  : a
  0 : a a
  1 : a a a
  2 : a a a a
  3 : a a a a b
所以:
T : a a a a a a a a b

p[]  0 1 2 3 4
P  : a a a a b
前缀-1 0 1 2 3

然后对比T与P,发现在T(a) &P(b)处不同,此时P(b)对应前缀表为3,找出上标p[3]处的字符移动到
匹配T(a)错误的地方,继续从匹配失误的地方开始比较
             *
T : a a a a a a a a b
       a a a a b
p[]  0 1 2 3 4
P :   a a a a b
前缀 -1 0 1 2 3
从匹配失误的地方开始比较,此时还是不匹配,在此处继续根据前后缀找出p[3],继续移动:
T : a a a a a a a a b
         a a a a b
然后继续从匹配失误的地方进行比较,直到匹配或者对比完数组:
T : a a a a a a a a b
           a a a a b
T : a a a a a a a a b
             a a a a b

可以先写出前后缀数组的解法:

void profix_table(char pattern[], int profix[], int n)
{
  profix[0] = 0;
  int len =0; i = 1;
  while(i < n){
  if(pattern[i] == pattern[len] //对比前后两个指针指向的值进行对比,如果相等则更新prefix[],继续移动指针
  {
     len++;
     profix[i] = len; //len 为i 位置的前后缀长度
     i++;
  }else{
     if(len > 0)//如果不相等,则分len是否大于0讨论
      {
         len = prefix [ len-1 ];  //len回退一位,找对应的prefix[len- 1],此时len也会指向p[ prefix[len-1] ]的位置
       }
       else{
         prefix[i] = len;
         }

      }

}
void move_profix( int profix[], int n)
{
   int i;
   for( i = n-1 ; i > 0; i--)
   {
      profix[i] = profix [i-1];
    }
    profix[0] = -1;
}

void kmp(char text[], char pattern)
{
  int n = strlen(pattern);
  int* prefix = malloc(sizeof(int) * n);
  prefix_table(pattern, prefix, n);
  move_profix(prefix, n);
  int m = strlen(text);
  int i = 0, j = 0;
  while(i < m)
  {
     if(j == n-1 && text[i] == pattern[j])
     {
       printf("pattern found at %d\n", i - j);
       j = prefix[j];//此处是找到一组后可以继续找下一组
      }
      if(text[i] == pattern[j])
      {
        i++; j++;
      }else
      {
         j = prefix[j]; //匹配失误,则回退pattern[j],根据prefix[j]找出对应的pattern[]
         if(j == -1)
         {
           i++; j++;
         }
       }
}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值