考研复试准备-c语言-数据结构-串-串的模式匹配算法


前言

本文主要讲述串的三种模式匹配算法(主串和模式串中字符都存放在下标1-length中)。


一、简单模式匹配算法

1.算法思想

(1)定义i和j两个指针,i指向主串,j指向模式串,i=j=1;
(2)i指向主串最后一个元素的下一个位置之前并且j指向模式串最后一个元素的下一个位置之前循环:
a.如果主串str.ch[i]==模式串substr.ch[j]:i往后移一位,j往后 移一位;
b.如果不相等的话,j指向模式串的第一位,i回到i-j+2的位置。
如图所示:
在这里插入图片描述

2.简单模式匹配算法代码

代码如下(示例):

//简单匹配算法
int index(Str str, Str substr){
	int i = 1;//i指向主串
	int j = 1;//j指向模式串
	while (i <= str.length&&j <= substr.length){
		if (str.ch[i] == substr.ch[j]){
			i++;
			j++;
		}
		else{//不相等时
			j = 1;
			i = i - j + 2;
		}
	}
	if (j > substr.length){//匹配成功
		printf("匹配成功!");
		return i - substr.length;
	}
	else{//匹配失败
		printf("匹配失败!");
		return 0;
	}
}

3.测试结果

完整版代码如下(示例):

#include<stdio.h>
#include<stdlib.h>
typedef struct{
	char *ch;
	int length;
}Str;

//初始化
void Init(Str &str){
	str.ch = NULL;
	str.length = 0;
}

//赋值
int Strassign(Str &str,char *a){
	if (str.ch){
		free(str.ch);
		str.ch = NULL;
		str.length = 0;
	}
	char *b = a;
	int len = 0;
	while (*b){
		len++;
		b++;
	}
	if (len == 0){
		return 1;
	}
	else{
		str.ch = (char *)malloc(sizeof(char)*(len + 1));//包括结束符
		if (str.ch == NULL){
			return 0;
		}
		else{
			b = a;
			for (int i = 0; i <= len; i++){
				str.ch[i] = *b;
				b++;
			}
			str.length = len;
			return 1;
		}
	}
}

//简单匹配算法
int index(Str str, Str substr){
	int i = 1;//i指向主串
	int j = 1;//j指向模式串
	while (i <= str.length&&j <= substr.length){
		if (str.ch[i] == substr.ch[j]){
			i++;
			j++;
		}
		else{//不相等时
			j = 1;
			i = i - j + 2;
		}
	}
	if (j > substr.length){//匹配成功
		printf("匹配成功!");
		return i - substr.length;
	}
	else{//匹配失败
		printf("匹配失败!");
		return 0;
	}
}



//测试
void main(){
	Str str, substr;
	Init(str);
	Init(substr);
	Strassign(str, " abcdefg");//为保证元素从下标1开始存放,最前为空格
	printf("主串为%s\n",str);
	Strassign(substr, " fg");//为保证元素从下标1开始存放,最前为空格
	printf("模式串为%s\n", substr);
	int location = index(str, substr);
	printf("模式串在主串中的位置为%d\n",location);
}

在这里插入图片描述
在这里插入图片描述


二、KMP算法

1.算法思想

(1)先求next数组:
a.模式串的第一个字符与主串i位置不匹配,应从下一个位置和模式串第一个字符继续比较。next[1]=0;
b.模式串j所指字符前的字符串为F,当F中不存在前后重合的部分时(不可将F自身视为和自身重合),则从主串中发生不匹配的字符与模式串第一个字符开始比较。next[j]=1;
c.模式串j所指字符前的字符串为F,当F中存在前后重合的部分时(不可将F自身视为和自身重合),j重新指向的位置恰好是F串中前后相重合子串的长度+1。
(2)利用next数组实现KMP算法。
如图所示:
在这里插入图片描述

2.KMP算法代码

代码如下(示例):

//得到next数组
void GetNext(Str substr,int next[]){
	int i = 1;//i指向模式串第一个字符
	int j = 0;
	next[1] = 0;
	while (i < substr.length){
		if (j==0||substr.ch[i] == substr.ch[j]){
			i++;
			j++;
			next[i] = j;
		}
		else{
			j = next[j];
		}
			
	}
	for (int i = 1; i < substr.length; i++){
		printf("第%d个字符对应的next数组元素值为%d\n",i, next[i]);
	}
}

//KMP算法
int KMP(Str str, Str substr,int next[]){
	int i = 1;//i指向主串中的第一个字符
	int j = 1;//j指向模式串中第一个字符
	while (i <= str.length - 1 && j <= substr.length - 1){
		if (j == 0 || str.ch[i] == substr.ch[j]){
			i++;
			j++;
		}
		else{
			j = next[j];
		}
	}
		if (j >= substr.length){
			printf("匹配成功!\n");
			return i - substr.length+1;
		}
		else{
			printf("匹配失败!\n");
			return 0;
		}
}

3.测试结果

完整版代码如下(示例):

#include<stdio.h>
#include<stdlib.h>
typedef struct{
	char *ch;
	int length;
}Str;

//初始化
void Init(Str &str){
	str.ch = NULL;
	str.length = 0;
}

//赋值
int Strassign(Str &str,char *a){
	if (str.ch){
		free(str.ch);
		str.ch = NULL;
		str.length = 0;
	}
	char *b = a;
	int len = 0;
	while (*b){
		len++;
		b++;
	}
	if (len == 0){
		return 1;
	}
	else{
		str.ch = (char *)malloc(sizeof(char)*(len + 1));//包括结束符
		if (str.ch == NULL){
			return 0;
		}
		else{
			b = a;
			for (int i = 0; i <= len; i++){
				str.ch[i] = *b;
				b++;
			}
			str.length = len;
			return 1;
		}
	}
}

//得到next数组
void GetNext(Str substr,int next[]){
	int i = 1;//i指向模式串第一个字符
	int j = 0;
	next[1] = 0;
	while (i < substr.length){
		if (j==0||substr.ch[i] == substr.ch[j]){
			i++;
			j++;
			next[i] = j;
		}
		else{
			j = next[j];
		}
			
	}
	for (int i = 1; i < substr.length; i++){
		printf("第%d个字符对应的next数组元素值为%d\n",i, next[i]);
	}
}

//KMP算法
int KMP(Str str, Str substr,int next[]){
	int i = 1;//i指向主串中的第一个字符
	int j = 1;//j指向模式串中第一个字符
	while (i <= str.length - 1 && j <= substr.length - 1){
		if (j == 0 || str.ch[i] == substr.ch[j]){
			i++;
			j++;
		}
		else{
			j = next[j];
		}
	}
		if (j >= substr.length){
			printf("匹配成功!\n");
			return i - substr.length+1;
		}
		else{
			printf("匹配失败!\n");
			return 0;
		}
}



//测试
void main(){
	Str str, substr;
	Init(str);
	Init(substr);
	Strassign(str, " abcdefg");//为保证元素从下标1开始存放,最前为空格
	Strassign(substr, " de");//为保证元素从下标1开始存放,最前为空格
	printf("主串为%s\n",str);
	printf("模式串为%s\n", substr);
	int *next;
	next = NULL;
	next = (int *)malloc(sizeof(int)*(substr.length));
	GetNext(substr, next);
	int location = KMP(str,substr,next);
	printf("模式串在主串中的位置为%d\n",location);
}

在这里插入图片描述
在这里插入图片描述

三、

1.算法思想

(1)先求nextval数组:
a.第一个字符的nextval为0;
b.当下标为j的字符==下标为k(k=next[j])的字符时,nextval[j]=nextval[k];
c.当下标为j的字符!=下标为k(k=next[j])的字符时,nextval[j]=k。
(2)利用nextval数组实现改进的KMP算法。

如图所示:
在这里插入图片描述

2.算法代码

代码如下(示例):

//得到nextval数组
void GetNextval(Str substr, int nextval[]){
	int i = 1;//i指向模式串第一个字符
	int j = 0;
	nextval[1] = 0;
	while (i < substr.length){
		if (j == 0 || substr.ch[i] == substr.ch[j]){
			i++;
			j++;
			if (substr.ch[i] == substr.ch[j])
				nextval[i] = nextval[j];
			else{
				nextval[i] = j;
			}
		}
		else{
			j = nextval[j];
		}

	}
	for (int i = 1; i < substr.length; i++){
		printf("第%d个字符对应的next数组元素值为%d\n", i, nextval[i]);
	}
}

//改进的KMP算法
int KMP(Str str, Str substr, int nextval[]){
	int i = 1;//i指向主串中的第一个字符
	int j = 1;//j指向模式串中第一个字符
	while (i <= str.length - 1 && j <= substr.length - 1){
		if (j == 0 || str.ch[i] == substr.ch[j]){
			i++;
			j++;
		}
		else{
			j = nextval[j];
		}
	}
	if (j >= substr.length){
		printf("匹配成功!\n");
		return i - substr.length + 1;
	}
	else{
		printf("匹配失败!\n");
		return 0;
	}
}

3.测试结果

完整版代码如下(示例):

#include<stdio.h>
#include<stdlib.h>
typedef struct{
	char *ch;
	int length;
}Str;

//初始化
void Init(Str &str){
	str.ch = NULL;
	str.length = 0;
}

//赋值
int Strassign(Str &str, char *a){
	if (str.ch){
		free(str.ch);
		str.ch = NULL;
		str.length = 0;
	}
	char *b = a;
	int len = 0;
	while (*b){
		len++;
		b++;
	}
	if (len == 0){
		return 1;
	}
	else{
		str.ch = (char *)malloc(sizeof(char)*(len + 1));//包括结束符
		if (str.ch == NULL){
			return 0;
		}
		else{
			b = a;
			for (int i = 0; i <= len; i++){
				str.ch[i] = *b;
				b++;
			}
			str.length = len;
			return 1;
		}
	}
}

//得到nextval数组
void GetNextval(Str substr, int nextval[]){
	int i = 1;//i指向模式串第一个字符
	int j = 0;
	nextval[1] = 0;
	while (i < substr.length){
		if (j == 0 || substr.ch[i] == substr.ch[j]){
			i++;
			j++;
			if (substr.ch[i] == substr.ch[j])
				nextval[i] = nextval[j];
			else{
				nextval[i] = j;
			}
		}
		else{
			j = nextval[j];
		}

	}
	for (int i = 1; i < substr.length; i++){
		printf("第%d个字符对应的next数组元素值为%d\n", i, nextval[i]);
	}
}

//改进的KMP算法
int KMP(Str str, Str substr, int nextval[]){
	int i = 1;//i指向主串中的第一个字符
	int j = 1;//j指向模式串中第一个字符
	while (i <= str.length - 1 && j <= substr.length - 1){
		if (j == 0 || str.ch[i] == substr.ch[j]){
			i++;
			j++;
		}
		else{
			j = nextval[j];
		}
	}
	if (j >= substr.length){
		printf("匹配成功!\n");
		return i - substr.length + 1;
	}
	else{
		printf("匹配失败!\n");
		return 0;
	}
}



//测试
void main(){
	Str str, substr;
	Init(str);
	Init(substr);
	Strassign(str, " abcdefg");//为保证元素从下标1开始存放,最前为空格
	Strassign(substr, " fuh");//为保证元素从下标1开始存放,最前为空格
	printf("主串为%s\n", str);
	printf("模式串为%s\n", substr);
	int *nextval;
	nextval = NULL;
	nextval = (int *)malloc(sizeof(int)*(substr.length));
	GetNextval(substr, nextval);
	int location = KMP(str, substr, nextval);
	printf("模式串在主串中的位置为%d\n", location);
}

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值