kmp算法

本文深入讲解KMP算法,一种改进的字符串匹配算法,避免了传统方法中重复匹配的问题,显著提高了搜索效率。通过实例和代码解析,帮助读者理解KMP算法的工作原理及其实现过程。

今天刚听学长讲了这个算法,听完感觉懂了又不是很懂,所以自己就赶紧跑来总结一下子。

首先要理解,朴素的单模式串匹配大概就是枚举每一个文本串元素,然后从这一位开始不断向后比较,每次匹配失败之后都要从头开始重新匹配,但是之前可能存在已经匹配好了的字符却还要再匹配一遍,感觉超级麻烦。
所以就有了kmp这个算法
对于每次匹配之后,我都不会从头重新开始枚举,而是根据我已经得知的数据,从某个特定的位置开始匹配;而对于模式串的每一位,都有唯一的“特定变化位置”,这个在匹配之后的特定变化位置可以帮助我们利用已有的数据不用从头匹配,从而节约时间。

这里有两个字符串a和b,a是文本串,b是模式串,b串的字符数量要远远小于a串
我们定义两个指针i、j,i是a串的指针,j是b串的指针
当匹配到j == blen时,结束

那么,如果按照平常的办法处理,一位一位的匹配,不匹配就再从i+1开始,明明b串里有匹配的字符却还要再重新匹配一遍
就好比:
ababababe
ababe
匹配到e的时候你会发现不匹配了,但是这时候前四位是匹配的,难道还要再匹配一遍的吗…
我们完全可以这样:
ababababe
…ababe
所以这时候就要预处理相同的部分
定义一个kmp数组,用模式串自己匹配自己来处理kmp数组
我们用j来表示模式串匹配到了第几位
如果匹配,相对应的j++

下面来看看代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000010;
int kmp[maxn];
char a[maxn],b[maxn];
int alen,blen,j;
int main()
{
	cin >> a+1;	cin >> b+1;
	alen = strlen(a+1);
    blen = strlen(b+1);
    for(int i=2;i<=blen;i++)
	{     
    	while(j && b[i] != b[j+1])//判断j是否为0是因为,如果回跳到第一个字符就不用了再回跳了 
    		j = kmp[j];//通过自己和自己匹配来得出每一个点的kmp值 
    	if(b[i] == b[j+1])	j++; 
        	kmp[i] = j;
    }//b串自己处理自己 
    j=0;
    for(int i=1;i<=alen;i++)
    {
    	while(j>0 && a[i] != b[j+1])//如果失配,那么就不断向回跳,直到可以继续匹配 
        	j = kmp[j];//记录此刻kmp[j]的位置,下一次从这里开始 
        if(a[i] == b[j+1])	j++;//如果匹配成功,对应模式串位置j++ 
        if(j == blen)
		{
			cout<< i-blen+1 << endl;//此刻在a串出现的位置就是i-blen+1 
			j = kmp[j];
		}
    }
    for(int i=1;i<=blen;i++)
   		cout << kmp[i] << " ";//输出kmp数组 
    return 0;
}
### KMP算法的实现与原理 KMP(Knuth-Morris-Pratt)算法是一种高效的字符串匹配算法,其核心思想是通过构建部分匹配表(也称为`next`数组或`failure`函数),避免在模式串匹配失败时对文本串进行回溯,从而降低时间复杂度[^1]。 #### 一、KMP算法的核心原理 KMP算法的关键在于利用模式串的部分匹配信息,构建一个最长公共前后缀表(通常称为`next`数组)。当匹配失败时,算法根据`next`数组中的值跳转到适当的位置继续匹配,而不是简单地将文本串指针回退。这种方法确保了文本串只需被扫描一次,时间复杂度为 \(O(n + m)\),其中 \(n\) 是文本串长度,\(m\) 是模式串长度[^3]。 #### 二、部分匹配表(`next`数组)的构造 `next`数组记录了模式串中每个位置对应的最长公共前后缀长度。例如,对于模式串 `"ABABC"`,其`next`数组为 `[0, 0, 1, 2, 0]`。以下是构造`next`数组的步骤: ```python def compute_next(pattern): n = len(pattern) next_array = [0] * n j = 0 # 前缀末尾索引 for i in range(1, n): # 后缀末尾索引从1开始 while j > 0 and pattern[i] != pattern[j]: j = next_array[j - 1] if pattern[i] == pattern[j]: j += 1 next_array[i] = j return next_array ``` #### 三、KMP算法的实现 基于上述`next`数组,可以实现高效的字符串匹配。以下是完整的KMP算法实现代码: ```python def kmp_search(text, pattern): next_array = compute_next(pattern) # 构造next数组 n, m = len(text), len(pattern) j = 0 # 模式串指针 for i in range(n): # 遍历文本串 while j > 0 and text[i] != pattern[j]: j = next_array[j - 1] if text[i] == pattern[j]: j += 1 if j == m: # 匹配成功 return i - m + 1 # 返回匹配起始位置 return -1 # 匹配失败 ``` #### 四、示例分析 假设文本串为 `"ABABABCABABC"`, 模式串为 `"ABABC"`,则通过KMP算法可以快速找到模式串在文本串中的首次出现位置。具体过程如下: 1. 初始化文本串指针 `i = 0` 和模式串指针 `j = 0`。 2. 依次比较字符,若匹配失败,则根据`next`数组调整模式串指针 `j`。 3. 当模式串完全匹配时,返回匹配起始位置。 #### 五、C语言实现示例 除了Python,KMP算法也可以用C语言实现。以下是一个简单的C语言版本: ```c #include <stdio.h> #include <string.h> void computeNext(const char* pattern, int* next, int m) { int j = 0; next[0] = 0; for (int i = 1; i < m; i++) { while (j > 0 && pattern[i] != pattern[j]) { j = next[j - 1]; } if (pattern[i] == pattern[j]) { j++; } next[i] = j; } } int kmpSearch(const char* text, const char* pattern) { int n = strlen(text); int m = strlen(pattern); int next[m]; computeNext(pattern, next, m); int j = 0; for (int i = 0; i < n; i++) { while (j > 0 && text[i] != pattern[j]) { j = next[j - 1]; } if (text[i] == pattern[j]) { j++; } if (j == m) { return i - m + 1; } } return -1; } int main() { const char* text = "ABABABCABABC"; const char* pattern = "ABABC"; int result = kmpSearch(text, pattern); printf("Pattern found at index: %d\n", result); return 0; } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你数过天上的星星吗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值