算法设计--串匹配问题:BF算法、KMP算法、BM算法

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

/*
* BF算法
* 基本思想:
*从主串S的第一个字符开始和模式T(子串)的第一个字符进行比较,若相等,则继续比较两者的后续字符;
*若不相等,则从主串S的第二个字符开始和模式T的第一个字符进行比较,重复上述过程,若T中的字符全部比较完毕,则说明本趟匹配成功;
*若最后一轮匹配的起始位置是n-m(n为主串的长度,m为模式T的长度),则主串S中剩下的字符不足够匹配整个模式T,匹配失败。
*这个算法称为朴素的模式匹配算法,简称BF算法。
*/

int BF(string &s, string &t)
{
	int i=0,j=0,count=0;		//i指向主串s,j指向子串t,count计算匹配的字符长度
	while(i < s.size())
	{
		if(s.at(i) == t.at(j))	//如果匹配
		{
			i++;	//指针后移
			j++;
			count++;
		}
		else {		//匹配失败
			i++;
			j = 0;
			count = 0;
		}
		if(count == t.size())
		{
			cout<<"字符串匹配成功,起始位置为:"<<i - count + 1<<endl;
			return (i - count + 1);
		}
		
	}
	cout<<"字符串匹配失败!"<<endl;
	return 0;
}


//KMP算法中求next数组
void GetNext(string &t, int *next)
{
	next[1] = 0;
	int j = 1; 
	int k = 0;
	while(j < t.size())
	{
		if((k == 0) || (t[j] == t[k])){
			j++;
			k++;
			next[j] = k;
		}
		else k = next[k];
	}
}

//KMP算法实现
/*
*伪代码:
* 1.在串S和串T中分别设比较的起始下标i和j
* 2.循环直到S中所剩字符长度小于T的长度或T中所有字符均比较完毕
*	2.1 如果S[i] = T[j],则继续比较S和T的下一个字符,否则
*   2.2 将j向右滑动到next[j]位置,即j=next[j];
*   2.3 如果j = 0,则将i和j分别加1,准备下一趟比较
*  3.如果T中的所有字符均比较完毕,则返回匹配的起始下标,否则返回0
*/

int KMP(string &s, string &t)
{
	int i = 0,j = 0;
	int n = t.size();		//子串的长度
	int *next = new int[n];
	GetNext(t, next);		//求出每一个j对应的next[j]
	while(i < s.size() && j < t.size())
	{
		if(j == 0 || (s.at(i) == t.at(j)))
		{
			i++;
			j++;
		}
		else {
			j = next[j];
		}
		if(j == t.size())
		{
			int index = i - t.size() + 1;
			cout<<"字符串匹配成功,起始位置为:"<<index<<endl;
			return index;
		}
	}
	cout<<"字符串匹配失败!"<<endl;
	return 0;
}

//BM算法中的dist函数(滑动距离函数)
int dist(string &t, char ch)	//t为子串,ch为主串中的任意字符
{
	int len = t.size();
	int i = len - 1;
	if(ch == t.at(i))
		return len;
	i--;
	while(i >= 0)
	{
		if(ch == t.at(i))
		{
			return len - 1 - i;	//返回滑动距离
		}
		else {
			i--;
		}
	}
	return len;
}

//BM算法
/*基本思想:有
*假设将主串中自位置i起往左的一个子串与模式进行从右到左的匹配过程中,若发现不匹配
*,则下次应从主串的i+dist(Si)位置开始重新进行新一轮的匹配,其效果相当于把模式和主串均向右
* 滑过一段距离dist(Si),即跳过dist(Si)个字符而无需进行比较。
*/
int BM(string &s, string &t, int n, int m)
{
	//主串的长度为n,模式串的长度为m,主串和模式的数组下标从0开始
	int i = m - 1;
	while(i <= n)
	{
		int j = m - 1;
		while(j > 0 && s.at(i) == t.at(j)){
			j--;
			i--;
		}
		if(j == 0) 
		{
			cout<<"字符串匹配成功,起始位置:"<<i + 1<<endl;
			return i+1;
		}
		else i = i + dist(t,s.at(i));
	}
	return 0;
}


int main()
{
	string s,t;
	cout<<"请输入主串S:"<<endl;
	cin>>s;
	cout<<"请输入子串T:"<<endl;
	cin>>t;

	//调用BF算法进行字符串匹配
	cout<<"BF算法:"<<endl;
	cout<<BF(s,t)<<endl;

	//调用KMP算法进行字符串匹配
	cout<<"KMP算法:"<<endl;
	cout<<KMP(s,t)<<endl;

	//调用BM算法进行字符串匹配
	cout<<"BM算法:"<<endl;
	cout<<BM(s,t,s.size(),t.size())<<endl;

	system("pause");
	return 0;
}


  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小巫技术博客

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

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

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

打赏作者

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

抵扣说明:

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

余额充值