11 串 BF算法和KMP算法

串的定义

(string)即字符串,是由零个或多个字符组成的有限序列。一般记作:
s = “ a 1   a 2   . . .   a n ”   ( n ≥ 0 ) s=“a_1 \ a_2 \ ...\ a_n ” \ (n \geq 0) s=a1 a2 ... an (n0)
串中字符的数目n称为串的长度。零个字符的串称为空串,其长度为0。

串中任意个连续的字符组成的字符组成的子序列称为该串的子串。字串在主串的位置则以字串的第一个字符正在主串中的位置表示。

由1个或多个空格“ ”组成的串,称为空格串,(注意和空串区分),其长度为串中空格字符的个数。

串的存储结构

串也有两种基本存储结构:顺序存储和链式存储。

考虑到存储效率和算法的方便性,多采用顺序存储结构。

  1. 串的顺序存储
//串的定长顺序存储结构
#define MAXLEN 255  //串的最大长度
typedef struct{
	char ch[MAXLEN+1];
	int length;  //串的当前长度
}SString;

//串的堆式顺序存储结构
typedef struct{
	char *ch; //非空串按串长分配 否则为NULL
	int length; //串的当前长度
}HString;
  1. 串的链式存储
#define CHUNKSIZE 80  //块大小
typedef struct Chunk{
	char ch[CHUNKSIZE];
	struct Chunk *next;
}Chunk;
typedef struct{
	Chunk *head,*tail; //串的头和尾
	int length; //串的当前长度
}LString;
串的模式匹配算法

字串的定位运算称为串的模式匹配或者串匹配。串的模式匹配设有两个字符串S和T,设S为主串,也称正文串;设T为字串,也称为模式。

著名的模式匹配有BF算法和KMP算法。

  1. BF算法

最简单直观,但是算法的时间复杂度高。

算法描述:
模式匹配从主串中查找的起始位置为pos。
1.分别利用计数指针i和j指示主串S和模式T中当前待比较的字符位置,i初始值为pos,j初值为1。
//字符串从1开始
2.如果两个串均未到达串尾,即i和j均小于等于S和T的长度时,则循环执行以下操作:
	·S[i].ch和T[j].ch比较,若相等,则i和j分别指示串中下个位置,继续比较后续的字符。
	·若不等,指针后退重新开始匹配,从主串的下一个字符(i=i-j+2)起再重新和模式的第一个字符(j=1)比较。
	·如果j>T.length,说明模式T中的每个字符依次和主串S中的一个连续的字符序列相等,则匹配成功。返回和模式T中第一个字符相等的字符在主串S中的序列号(i-T.length);否则称匹配失败,返回0。
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

//串的定长顺序存储结构
#define MAXLEN 255  //串的最大长度
typedef struct{
	char ch[MAXLEN+1];
	int length;  //串的当前长度
}SString;

int Index_BF(SString S,SString T,int pos){
	//返回模式T在主串S中第pos个位置开始第一次出现的位置,不存在,返回0
	//其中T非空
	printf("%s\n",S.ch);
	printf("%s\n",T.ch);
		int i=pos,j=0; //初始化 这里是从0开始的
		//两个串均为比较到串尾
		while(i<S.length&&j<T.length){
			if(S.ch[i]==T.ch[j]){
				++i;
				++j;
			}else{
				i=i-j+1; //指针后退重新开始匹配
				j=0;
			}
		}
		if(j>=T.length)
				return i-T.length;  //匹配成功
			else
				return 0;  //匹配失败
}
int main(){
	SString S,T;
	strncpy(S.ch,"ababcabcacbab",sizeof(S.ch));
	strncpy(T.ch,"abcac",sizeof(T.ch));
	S.length=13;
	T.length=5;
	int ans=Index_BF(S,T,0);
	printf("%d\n",ans);
	return 0;
}
  1. KMP算法

算法复杂度O(m+n).相比于BF算法的改进:每当一趟匹配过程中出现字符比较不等时,不需要回溯i指针,而是利用已经得到的“部分匹配”的结果将模式向右“滑动”尽可能远的一段距离,继续进行比较。从当前位置j滑动到的位置就是next[j]中存的数。所以重中之重就是求next数组。并且next数组只和模式串有关。

为了便于记忆,这里不从理论讲解,只将一个简单的例子,并给出具体的实现代码。通常字符数组从0开始计数。

假设模式串为abcca

next[j]通常是看位置j前面,即(0~j-1)的字符串的前缀后缀的匹配情况。规定next[0]=-1。

next[1]看第0个字符串的前后缀的匹配情况(前缀和后缀补不包含本身。)第0个子符串匹配为0。所以next[1]=0。

next[2]看0~1字符串即ab,前后缀匹配长度为0,所以next[2]=0.

同理,next[3]=0 ,next[4]=1。

#include<iostream>
#include<cstring>
using namespace std;
//串的定长顺序存储结构
#define MAXLEN 255  //串的最大长度
typedef struct{
	char ch[MAXLEN];
	int length;  //串的当前长度
}SString;

//这个数组中村存放的是匹配字符串的next值
int Next[254];
//这个next数组是KMP的重点
void GetNext(SString T,int next[]){
	//求模式串T的next值并存入到数组next中
	int len=T.length;  //串长
	int i=0,j=-1;
	next[0]=-1;
	while(i<len-1){
		if(j==-1||T.ch[i]==T.ch[j]){
			++i;
			++j;
			next[i]=j;
		}else{
			j=next[j];
		}
	}
}

int Index_KMP(SString S,SString T,int pos){
	//利用模式串T的next函数求T在主串S中第pos个字符之后的位置
	//T非空
	int i=pos-1,j=0;
	while(i<S.length&&j<S.length){
		if(S.ch[i]==T.ch[j]){
			++i;
			++j;
		}else{
			j=Next[j];
		}
	}
	if(j>=T.length)
		return i-T.length; //匹配成功
	else
		return 0; //匹配失败
}
int main(){
	SString S,T; //S主串  T模式串
	strncpy(S.ch,"ababcabcacbab",sizeof(S.ch));
	strncpy(T.ch,"abcac",sizeof(T.ch));
	S.length=13;
	T.length=5;
	GetNext(T,Next);
	int ans=Index_KMP(S,T,1);
	printf("%d\n",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

xuhuimingc

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

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

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

打赏作者

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

抵扣说明:

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

余额充值