KMP算法

1.KMP算法是什么

  • 由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现的一种改进的字符串匹配算法KMP算法。关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息。时间复杂度O(m+n)。
  • 用于查找串S中含串T的个数count

2.KMP算法的核心

KMP算法是BF算法改进而来的,下边说下BF算法的以及为什么要改成KMP算法

  • 一般我们设模式串或匹配串数组元素下标都是从1开始,然后下标0就拿去存放元素个数(为了简便运算),以下边为例来介绍下next数组的获取。

  • 下边这个匹配串和模式串在匹配的过程中会发现到第五个元素的时候就不匹配了
  •   所以呢就对匹配串右移一个,让匹配串的第一个元素和模式串的第二个元素进行匹配,如果第二个元素匹配就匹配第三个元素,但是恰巧这个匹配串的第一个元素和模式串的第二个元素不匹配,因此直接跳转,让匹配串从模式串的第三个开始匹配,以此类推。

但是 这样的话就会发现每一次都要回溯,重新匹配,那要改进就是要避免这样的回溯使得效率变高,所以KMP算法的核心就是解决问题的核心就是避免不必要的回溯,问题由模式串决定,不是由目标决定。

3.KMP算法的原理

(1)如何避免上边这个回溯?

  • 通过观察上边,发现S[i]=T[j](当i和j在1-4间的时候)并且这四个都不相等,所以T[1]和S中前四项都不匹配,由此,我们就可以直接跳转到第和S中的第五项匹配。
  •  当匹配数组有重复的时候,那就要匹配的就要考虑重复的,像下边这个

(2)next数组

  • 当模式匹配串T失配的时候,next数组对应的元素指导应该用T串的那个元素进行下一轮匹配。
  • 一般next数组第一个元素是0,第二个是1(因为前边没有相同的);
  • 然后比较数组2 3元素的,发现他们不一样,所以就又向前比较,比较元素1 3,发现他们是一样的,此时就可以记录next的值了,后边的也同理

4.KMP算法代码的原理理解

(1)next数组

typedef char *string;
j是前缀,i是后缀
void get_next(string T,int *next)
{
j=0;
i=1;
next[1]=0;

while(i<T[0]) //当i<模式串元素个数时
{
   if(j==0||T[i]==T[j])    //当前缀为0或者前缀对应的元素和后缀对应的元素相同时(或者利用 
                             //j=next[j]让前缀向前)
   {
      i++;                 //i和j都加1,因为两个元素相同,所以比较下一个
      j++;
      next[i]=j;          //然后把后缀对应的元素赋予给next数组第i个位置
   }
   else
   {
      j=next[j];        //当前缀和后缀不相同的时候,就利用next数组指导j应该
   }
}
}

下边是对代码的前5个的运行演示

(2)KMP算法代码的实现

#include<stdio.h>
#include<stdlib.h>
#include <string.h>

typedef char * string;
 
void get_next(string T,int * next)
{
int j=0;
int i=1;
next[1]=0;
 while(i<T[0]) //当i<模式串元素个数时
 {
   if(j==0||T[i]==T[j])    //当前缀为0或者前缀对应的元素和后缀对应的元素相同时(或者利用 
                             //j=next[j]让前缀向前)
   {
      i++;                 //i和j都加1,因为两个元素相同,所以比较下一个
      j++;
      next[i]=j;          //然后把后缀对应的元素赋予给next数组第i个位置
   }
   else
   {
      j=next[j];        //当前缀和后缀不相同的时候,就利用next数组指导j应该
   }
 }
}

//返回字符串T在字符串S中的第pos个字符之后的位置
//若不存在,则返回0
int index_kmp(string S,string T,int pos)
{
   int i=pos;
   int j=1;
   int next[255];
   get_next(T,next);
   while(i<=S[0]&&j<=T[0])//这个和BF是一样的,就是前边都是匹配的情况
   {
	   if(S[i]==T[j]||j==0)
	   {
         i++;
         j++;
	   }
        else //这个就是和BF算法有区别的地方,如果遇到不匹配的,就利用next进行回溯,避免不必要的回溯
		{
          j=next[j];
		}
   }
   if(j>T[0])
   {
     return i-T[0]; //如果找得到,就返回i-T[0]的值
   }
   else
   {
     return 0;   //如果不符合,就返回0
    }
}

int main()
{
   char  str1[255]="ababaaaba";
   int  next[255];
   char  str2[255]="bac";
   int i,p,m; 
   //next[0]=next[0]-48;
   str1[0]=str1[0]-48;
   str2[0]=str2[0]-48;
   p=strlen(str1);
   get_next(str1,next);
   printf("获取的next[]数组为:");
   for(i=1;i<p;i++)
   {
      printf("%d",next[i]);
   }
   printf("\n");
   m=index_kmp(str1,str2,1);
   printf("返回的值为:%d\n",m);
    return 0;
}

 

### KMP算法的实现 KMP算法是一种高效的字符串匹配算法,它通过构建部分匹配表(也称为`next`数组)来减少不必要的回溯操作[^2]。以下是基于Python语言的KMP算法实现: ```python def compute_next_array(pattern): next_arr = [-1] * len(pattern) i, j = 0, -1 while i < len(pattern) - 1: if j == -1 or pattern[i] == pattern[j]: i += 1 j += 1 next_arr[i] = j else: j = next_arr[j] return next_arr def kmp_search(text, pattern): m, n = len(text), len(pattern) next_arr = compute_next_array(pattern) i, j = 0, 0 while i < m and j < n: if j == -1 or text[i] == pattern[j]: i += 1 j += 1 else: j = next_arr[j] if j == n: return i - j # 返回匹配起始位置 return -1 # 表示未找到匹配项 ``` 上述代码分为两部分: - `compute_next_array()` 函数用于计算模式串的部分匹配表(即`next`数组)。这部分的核心在于利用已知的最大公共前后缀长度来优化后续匹配过程[^5]。 - `kmp_search()` 函数则负责执行具体的字符串匹配逻辑。 --- ### KMP算法的应用场景 #### 文本编辑器中的查找功能 在文本编辑器中,当用户输入一段文字并希望快速定位某个关键词时,可以采用KMP算法完成这一任务。相比传统的暴力匹配方法,KMP能够在更短的时间内返回结果,尤其适用于大规模文档环境下的搜索需求[^1]。 #### 数据清洗与预处理 在大数据领域,经常需要对海量日志文件或其他形式的数据集进行过滤或提取特定字段的操作。此时如果目标子串固定不变,则可预先生成对应的`next`数组,在多次查询过程中显著提升效率[^3]。 #### 生物信息学研究 DNA序列由四种碱基组成(A,T,C,G),因此对于某些基因片段的研究工作而言,频繁涉及相似结构单元之间的对比分析。借助于KMP技术,研究人员能够更加便捷地识别出感兴趣的区域及其分布规律[^4]。 --- ### 性能优势总结 总体来看,由于引入了额外的信息存储机制——即所谓的“失败指针”,使得整个流程无需反复跳转至初始状态重新尝试;从而大幅降低了最坏情况下的时间开销,并保持相对稳定的内存占用水平[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值