【数据结构】串的简单模式匹配算法、KMP算法(C语言)

1. 串的简单模式匹配算法

简单模式匹配 Brute-Force(布鲁斯-福斯)算法是一种带回溯的匹配算法,算法的基本思想是:从主串 s 的第一个字符开始,和模式串 t 的第一个字符开始比较,如果相等,就继续比较后续字符,如果不等,则回溯到主串 s 的第2个字符开始重新和模式串 t 比较,直到模式串 t 中的每一个字符和主串 s 中的一个连续字符子序列全部相等,则称匹配成功,返回和 t 中第一个字符相等的字符在主串 s 中的位置;或者主串中没有和模式串相等的字符序列,则匹配不成功。
实现时设三个指示器:i,j,start;i 指向主串 s 中当前比较的字符,j 指向子串 t 中当前比较的字符,start 记录每趟比较时在主串 s 中的起点。

1.1 简单模式匹配算法

/*简单模式匹配算法(有回溯)*/
int StrIndex(SString* s, SString* t) {
    
    
	int i, j, start = 0;
	if (t->len == 0) 					//模式串为空时是任意串的匹配串
		return 0;
	i = start, j = 0;
	while (i < s->len && j < t->len) {
    
    
		if (s->ch[i] == t->ch[j]) {
    
    		//当前对应字符相等时向前推进
			i++;
			j++;
		}
		else {
    
    
			start++;					//当前对应字符不相等时回溯
			i = start;					//主串从start+1开始
			j = 0;						//模式串从0开始
		}
	}
	if (j >= t->len) 
		return start;					//匹配成功时,返回匹配起始位置
	else
		return -1;						//匹配不成功,返回-1
}

1.2 完整实现代码

# include<stdio.h>
# define MAXLEN 40

/*顺序串的存储结构*/
typedef struct {
    
    
	char ch[MAXLEN];
	int len;
}SString;

/*顺序串初始化*/
void StrInit(SString* s) {
    
    
	s->len = 0;
}

/*顺序串赋值*/
void StrAssign(SString* s, char* tval) {
    
    
//将字符串常量tval的值赋值给串s
	int len, i = 0;
	while (tval[i] != '\0')
		i++;
	len = i;
	for (i = 0; i < len; i++)
		s->ch[i] = tval[i];
	s->len = len;
}

/*简单模式匹配算法(有回溯)*/
int StrIndex(SString* s, SString* t) {
    
    
	int i, j, start = 0;
	if (t->len == 0) {
    
    					//模式串为空时是任意串的匹配串
		printf("模式串为空!\n");
		return 0;
	}
	i = start, j = 0;
	while (i < s->len && j < t->len) {
    
    
		if (s->ch[i] == t->ch[j]) {
    
    		//当前对应字符相等时向前推进
			i++;
			j++;
		}
		else {
    
    
			start++;					//当前对应字符不相等时回溯
			i = start;					//主串从start+1开始
			j = 0;						//模式串从0开始
		}
	}
	if (j >= t->len)					//匹配成功
		printf("匹配成功!起始位置为:%d\n", start + 1);
	else
		printf("匹配失败!\n");			//匹配不成功
}

int main() {
    
    
	char tval_s[14] = {
    
     'a','b','a','b','c','a','b','c','a','c','b','a','b' };
	char tval_t[6] = {
    
     'a','b','c','a','c' };
	SString s, t;
	StrAssign(&s, tval_s);
	StrAssign(&t, tval_t);
	StrIndex(&s, &t);
	return 0;
}

1.3 运行结果

简单模式匹配算法运行结果

2. KMP算法

KMP算法详解见 @哈顿之光 的博客:https://blog.csdn.net/weixin_46007276/article/details/104372119?spm=1001.2014.3001.5502

2.1 完整实现代码

# include<stdio.h>
# define MAXLEN 40

/*顺序串的存储结构*/
typedef struct {
    
    
	char ch[MAXLEN];
	int len;
}SString;

/*顺序串初始化*/
void StrInit(SString* s) {
    
    
	s->len = 0;
}

/*顺序串赋值*/
void StrAssign(SString* s, char* tval) {
    
    
//将字符串常量tval的值赋值给串s
	int len, i = 0;
	while (tval[i] != '\0')
		i++;
	len = i;
	for (i = 0; i < len; i++)
		s->ch[i] = tval[i];
	s->len = len;
}

int next[MAXLEN];

/*求next[]数组*/
/*next[j]表示模式串t的第j-1个字符前的字符串的最大前后缀*/
void GetNext(SString* t, int* next) {
    
    
	int j, k;
	j = 0; k = -1;
	next[0] = -1;							//第一个字符前无字符串,赋值-1
	while (j < t->len - 1){
    
    
		if (k == -1 || t->ch[j] == t->ch[k]){
    
    
			j++; 
			k++;
			next[j] = k;
		}
		else
			k = next[k];
	}
}

/*KMP算法*/
int KMPIndex(SString* s, SString* t){
    
    
	int i = 0, j = 0;
	while (i < s->len && j < t->len){
    
    
		if (j == -1 || s->ch[i] == t->ch[j]){
    
    
			i++; 
			j++;
		}
		else 
			j = next[j];
	}
	if (j >= t->len)
		return(i - t->len + 1);  			//返回匹配模式串的首字符下标+1
	else
		return(-1);        					//返回不匹配标志
}

int main() {
    
    
	char tval_s[14] = {
    
     'a','b','a','b','c','a','b','c','a','c','b','a','b' };
	char tval_t[6] = {
    
     'a','b','c','a','c' };
	SString s, t;
	StrAssign(&s, tval_s);
	StrAssign(&t, tval_t);
	GetNext(&t, next);
	printf("%d\n", KMPIndex(&s, &t));
	return 0;
}

2.2 运行结果

KMP算法运行结果
更多数据结构内容关注我的《数据结构》专栏:https://blog.csdn.net/weixin_51450101/category_11514538.html?spm=1001.2014.3001.5482

猜你喜欢

转载自blog.csdn.net/weixin_51450101/article/details/122684649