KMP-看毛片算法 c++

!!!这篇文章有错误,日后更新,推荐立即关闭该网页。

--2020/4/30

 

kmp算法包括两步

1,计算next数组,即对要寻找的字符串标记值,例如abcabc,这边有六个字符,从a开始,将每一个字符与这个字符串开头开始匹配,第一个字符标记为0,第二个字符为b,明显与字符串开头a不相等,因此标记为0。第四个字符为a,与字符串开头a相等,因此标记为1,第五个字符为b,但他前面的字符被标记为1,因此第五个字符要与第1+1个字符相比较,如果相似,则标记为前一个字符标记的值+1.

贴代码

 

void cal_next(int *next,char tstr[100],int tlen)//这边传递了next数组的地址,要标记的字符串以及用于遍历的字符串长度;
{
	next[0] = 0;//对第一个字符标记为0;
	for (int i = 1; i < tlen; i++)//遍历,先查看前一个字符的标记值,如果为0,则将字符与第一个字符相比较,如果不为0,假设为x,则与第x+1个字符比较;
	{
		if (next[i - 1] == 0)
		{
			if (tstr[i] == tstr[0])
				next[i] = 1;
			else
				next[i] = 0;
		}
		else
		{
			if (tstr[i] == tstr[next[i - 1]])
				next[i] = next[i - 1] + 1;
			else
				next[i] = 0;
		}
	}
}

2.进行匹配,如果匹配到目标数组中间发现后面不匹配,就访问最后一个匹配字符的标记值,例如主串abcabbbbbb,目标串abcabc假设匹配到第二个b的时候后面不匹配了,根据之前的求next数组方法,可以得到目标串。第二个b的标记值为2,这个b在目标串位置为第5个,因此下次要移动5-2次,即移动三个单位,此时目标串的a刚好对上主串第二个a。

 

贴代码

 

int kmp(char sstr[], char tstr[], int next[], int slen, int tlen)
{
	int i = 0, j = 0;
	while (i < slen)//遍历主串
	{
		bool flag = true;//立个flag,循环一下如果倒了,说明不匹配。
		while (j < tlen)//遍历目标串
		{
			if (sstr[i] == tstr[j])//判断是否匹配
			{
				i++;
				j++;
				continue;
			}
			else
			{
				flag = false;
				break;
			}
		}
		if (flag == true)//看flag有不有倒。
			return i - j + 1;
		else
		{
			if (j == 0)//这个if语句之前没用,产生了bug,当j=0的时候,next[j-1]是next[-1],这时就会得到意外的值。
				i = i + 1;
			else
			{
				i = i + (j - next[j - 1]);
				j = 0;
			}
		}
	}
	return -1;//如果匹配失败,则返回-1;
}

-------------------------------------------切割-----------------下面是完整代码-----------------------------------------------------------

 

 

#include <iostream>
#include <string>
using namespace std;
void cal_next(int *next,char tstr[100],int tlen)
{
	next[0] = 0;
	for (int i = 1; i < tlen; i++)
	{
		if (next[i - 1] == 0)
		{
			if (tstr[i] == tstr[0])
				next[i] = 1;
			else
				next[i] = 0;
		}
		else
		{
			if (tstr[i] == tstr[next[i - 1]])
				next[i] = next[i - 1] + 1;
			else
				next[i] = 0;
		}
	}
}
int kmp(char sstr[], char tstr[], int next[], int slen, int tlen)
{
	int i = 0, j = 0;
	while (i < slen)
	{
		bool flag = true;
		while (j < tlen)
		{
			if (sstr[i] == tstr[j])
			{
				i++;
				j++;
				continue;
			}
			else
			{
				flag = false;
				break;
			}
		}
		if (flag == true)
			return i - j + 1;
		else
		{
			if (j == 0)
				i = i + 1;
			else
			{
				i = i + (j - next[j - 1]);
				j = 0;
			}
		}
	}
	return -1;
}
int main()
{
	char sstr[100], tstr[100], ch = 0;
	int slen, tlen;
	cout << "Please enter the sstr:" << endl;
	cin >> sstr;
	again:
	cout << "Please enter the ttstr:" << endl;
	cin >> tstr;
	slen = strlen(sstr);
	tlen = strlen(tstr);
	int next[100];
	cal_next(next, tstr, tlen);
	cout << "The next array is:";
	for (int i = 0; i < tlen; i++)
		cout << next[i];
	cout << endl;
	int situ;
	situ = kmp(sstr, tstr, next, slen, tlen);
	cout << "These two strings are matched in No." << situ << endl;
	goto again;
	system("pause");
	return 0;
}

 

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值