KMP算法的实现

4 篇文章 0 订阅
1 篇文章 0 订阅

概念:

Knuth-Morris-Pratt 字符串查找算法,简称为 “KMP 算法”,常用于在一个文本串 S 内查找一个模式串 P 的出现位置,这个算法由 Donald Knuth、Vaughan Pratt、James H. Morris 三人于 1977 年联合发表,故取这三人的姓氏命名此算法。

下面先直接给出 KMP 的算法流程:

  • 假设现在文本串 S 匹配到 i 位置,模式串 P 匹配到 j 位置:
    • 如果 j = -1,或者当前字符匹配成功(即 S[i] == P[j]),都令 i++,j++,继续匹配下一个字符;
    • 如果 j != -1,且当前字符匹配失败(即 S[i] != P[j]),则令 i 不变,j = next[j]。此举意味着失配时,模式串 P 相对于文本串 S 向右移动了 j - next [j] 位。
现在我们关系的是next数组,那next数组是如何求得呢?
     

举例:给定字符串“ABCDABD”,可求得它的 next 数组如下:

实现原理:计算 next 数组的方法可以采用递推:

  • 1.如果对于值 k,已有 p0i,p1, ..., pk-1 = pi-k,pi-k+1, ..., pi-1,相当于 next[i] = k。 可以理解为next[i] = k 代表 p[i] 之前的模式串子串中,有长度为 k 的相同前缀和后缀

  • 2.下面的问题是:已知 next [0, ..., i],如何求出 next [i + 1] 呢?
    • 若p[k] == p[i],则 next[i+ 1 ] = next [i] + 1 = k + 1;
    • 若p[k ] ≠ p[i],如果此时 p[ next[k] ] == p[i ],则 next[ i + 1 ] = next[k] + 1,否则继续递归前缀索引 k = next[k],而后重复此过程。
#include<iostream>
using namespace std;

//求next值
void CalNext(const char *sub, int n, int *next)
{
	int i=0,k=-1;
	next[0] = -1;

	while(i<n-1)//注意是n-1,否则会越界
	{
		if(k==-1||sub[i] == sub[k])
		{
			next[++i] = ++k;
		}
		else
		{
			k = next[k];
		}
	}
	for(int i=0; i<n; i++) //打印测试
	{
		cout<<next[i]<<" ";
	}
	cout<<endl;
}
int KMP(const char *str, const char *sub)
{
	if(str == NULL || sub == NULL) return -1;

	int i=0,j=0;
	int len1 = strlen(str);
	int len2 = strlen(sub);
	
	int *next = new int[len2];
	CalNext(sub, len2, next);
	///
	while(i<len1&&j<len2)
	{
		if(j==-1 || str[i] == sub[j])
		{
			i++;
			j++;
		}
		else
		{
			j = next[j];
		}
	}
	//
	delete [] next;
	if(j == len2) return i-j;
	return -1;
}
int main()
{
	char *str = "aaaaaaaaaaaaabbb";
	char *sub = "aaaaabb";
	int index = KMP(str, sub);
	cout<<index<<endl;
	return 0;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值