KMP算法

KMP算法

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n)

#include<string>
#include<iostream>
using namespace std;

//改进后的next数组求解
void get_nextval(string T, int next[])
{
	int i = 0;
	int j = -1;
	next[0] = -1;
	int len = T.length();
	while (i < len - 1)
	{
		if (j == -1 || T[i] == T[j])
		{
			i++;
			j++;
			if (T[i] != T[j])//当前字符与前缀字符不同
			{
				next[i] = j; //字符不匹配时回溯的字符位置,next在i的位置为j
			}
			else
			{
				next[i] = next[j]; //如果当前字符与前缀字符相同,字符的next值赋值给next在i位置的值
			}
		}
		else
		{
			j = next[j]; //j值回溯
		}
	}
}


//标准next求解
void get_next(string T, int next[]) //求模式串T的next数组
{
	int len = T.length();
	int i = 0;
	int j = -1;
	next[0] = -1; //第一个字符前无字符串,给值-1
	while (i < len-1)
	//next数组中i的最大值为T.length -1,对next数组赋值是在i++之后,
	//所以while循环的最后i应该为 T.length -2
	{
		if (j == -1 || T[i] == T[j])
		{
			i++;
			j++;
			next[i] = j;
			//字符串匹配时,同步后移
		}
		else
		{
			j = next[j];
			//我们现在知道next[i]的值代表的是下标为i的字符前面的字符串最长相等前后缀的长度
			//也表示该处字符不匹配时应该回溯到的字符的下标
			//这个值给i后又进行while循环判断,此时T.data[k]即指最长相等前缀后一个字符
		}
	}
}

//KMP求解 匹配字符串索引位置
int index_kmp(string S, string T, int pos)
{
	int j = 0;
	int i = pos; //从主串的那一位开始
	int next[255];
	int lens = S.length();
	int lent = T.length();
	get_next(T, next);		 //next = {-1, 0, 0, 1, 2, 3, 1, 1, 2}
	//get_nextval(T, next);	//next = {-1, 0, -1, 0, -1, 3, 1, 0, -1}
	while (i < lens && j < lent)
	{
		if (j == -1||S[i] == T[j])
		{
			i++;
			j++; //i,j自增
		}
		else
		{
			j = next[j]; //i不变,j回溯
		}
	}
	if(j >= lent) // >=
		return i - lent; //返回匹配模式串的首字符下标
	return -1;	//未匹配,返回不匹配标志
}

int main()
{
	string a = "ABABAABCDABABAAABAEA";
	string b = "ABABAAABA";

	cout << index_kmp(a, b, 0) << endl; //KMP算法

	system("pause");
	return 0;
}

代码注意点:

  • 所求解next数组是从-1开始的;
  • 求解next数组的while循环判断条件是小于字符长度-1,T.length()-1
  • 改进后的求解next数组,在T[i] == T[j]时进行字符回溯
  • 求解next时,i表示next的下标,j多数表示next数组的值
  • i值一直增加,j值需要回溯
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值