Kmp算法的两种写法

两种写法的基本思想是一直的。只是求next数组的方式不同,next数组所得的值也有所不同,代表的含义也不同。

原理不多说,网上讲的很多,这里只贴出完整的实现代码。

一般网上讲解的求next数组的都是针对方法二的。


第一种优化写法。next[i]表示匹配串在i处如果匹配失败下次移到的位置.

const int N = 100;
int next[N];
int pattern_len, str_len;
char pattern[N];
char str[N];

//求next数组的值. 即预处理
void getNext1()
{
	int i = 0, j = -1;
	next[0] = -1;
	while (i < pattern_len - 1)
	{
		//cout << i << " " << j << endl;
		if (j == -1 || pattern[i] == pattern[j])
		{
			++i;
			++j;
			if (pattern[i] != pattern[j])
				next[i] = j;
			else
				next[i] = next[j];
		}
		else
			j = next[j];
	}
}

int kmp1()
{
	int i = 0, j = 0;
	str_len = strlen(str);
	while (i < str_len && j < pattern_len)
	{
		if (j == -1 || str[i] == pattern[j])
		{
			++i;
			++j;
		}
		else
			j = next[j];
	}
	if (j >= pattern_len)
		return i - pattern_len;
	else
		return -1;
}


第二种,经典写法.next[i]表示的最远匹配到的位置,已ABCDABD为例:-1 -1 -1 -1 0 1 -1

abcbabc :-1 -1 -1 -1 0 1 2

void getNext2()
{
	next[0] = -1;
	int pre; //注,此处的i是从1开始的
	for (int i = 1; i < pattern_len; ++i)
	{
		pre = next[i - 1];

		//向前回溯 pre
		while (pre >= 0 && pattern[pre + 1] != pattern[i])
		{
			pre = next[pre];
			// cout << i << "  index: " << pre << "  back " << endl ;
		}

		// cout << "i:" <<i << "   " << pre << endl;
		if (pattern[pre + 1] == pattern[i])
			next[i] = pre + 1;
		else
			next[i] = -1; //由于前面已经回溯,这里可直接赋值为-1
	}
}

int kmp2()
{
	int p_index = 0, t_index = 0;
	while (p_index < pattern_len && t_index < str_len)
	{
		if (str[t_index] == pattern[p_index])
		{
			++t_index;
			++p_index;
		}
		else if (p_index == 0)
			++t_index;
		else
			p_index = next[p_index - 1] + 1;
	}

	if (p_index == pattern_len)
		return t_index - pattern_len;
	else
		return -1;
}


int main()
{
	freopen("in.txt", "r", stdin);
	while(gets(str))
	{
		gets(pattern);
		pattern_len = strlen(pattern);
		//if(str[0] == '#') continue;
		getNext1();
		int ans = kmp1();
		cout << "next1: ";
		for(int i=0; i<pattern_len; i++) cout << next[i] << " ";
		cout << endl;
		cout << ans << endl;
		getNext2();
		cout << "next2: ";
		for(int i=0; i<pattern_len; i++) cout << next[i] << " ";
		cout << endl;
		 ans = kmp2();
		cout << ans << endl;
	}
}


测试数据:

/*
abadfabaabacd
abac
ababcbabcbaca
abcbabc
*/


打印结果:

next1: -1 0 -1 1 
8
next2: -1 -1 0 -1 
8
next1: -1 0 0 0 -1 0 0 
2
next2: -1 -1 -1 -1 0 1 2 
2


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值