字符串匹配与kmp算法

在C语言中,字符串匹配可以使用strstr()函数实现。返回指向str1中第一个出现的str2的指针,如果str2不是str1的一部分,则返回空指针。

char* strstr(const char* string ,const char* strCharSet);
//在一个字符串里查找所求字符串
1.strstr()函数的使用
#include<iostream>
using namespace std;

//字符串匹配
int main(){
	char* str = "hello world";
	char* t = "llo";
	char* st=strstr(str,t);
	cout << st << endl;
}
2.模拟strstr()函数

在字符串里查找所给字符串,我们称之为模式匹配。
1.朴素的模式匹配
a.模拟实现字符串匹配,返回所查询字符串的下标

//模拟实现字符串匹配,返回所查询字符串的下标
int my_strstr(const char* str1, const char* str2){
	assert(str1!=NULL&&str2!=NULL);
	int i, j;
	i = j = 0;
	while (str1[i]!='\0'&&str2[j]!='\0'){
		if (str1[i]==str2[j]){
			i++;
			j++;
		}
		else
		{
			i = i - j + 1;
			j = 0;
		}
	}
	if (str2[j] == '\0')
		return  i - j;
	return -1;
}

b.模拟实现字符串匹配,返回所查询字符及之后的字符串

char* my_strstr(const char* str1, const char* str2){//模拟实现字符串匹配,返回所查询字符及之后的字符串
	assert(str1 != NULL&&str2 != NULL);
	int i, j;
	i = j = 0;
	while (str1[i] != '\0'&&str2[j] != '\0'){
		if (str1[i] == str2[j]){
			i++;
			j++;
		}
		else
		{
			i = i - j + 1;
			j = 0;
		}
	}
	if (str2 [j]== '\0')
		return (char*)str1+i-j;
	return NULL;
}
int main()
{
	char* str1 = "abababcabab";
	char* str2 = "abc";
	char* str=my_strstr(str1,str2);
	if (str!=NULL)
		cout << str;
	else
		cout << "不存在";
}

运行结果:
在这里插入图片描述

c.kmp算法
在上面程序中,从比较规则上来说,在一次比较中没有匹配,在下一次比较中,又要重新再一次比较前面重复的字符。从这个角度而言,已经比较过的重复的字符没有比较的意义的,因为回溯的次数太多次。
kmp算法的作用是在已知的字符串中查找字串的位置,也叫做串的模式匹配。KMP算法字符串移位的关键就在于最长相等前后缀的长度。
实现next数组:

int *get_next(char* str,int next[],int size){//求解next[]数组,得到前缀表
	int i = 0;//指向前缀的末尾端
	int j = 1;//指向后缀的起始段
	next[0] = 0;
	while (size--){
		if (str[i] == str[j]){
			next[j] = next[j - 1] + 1;
			i++;
			j++;
		}
		else{
			next[j] = 0;
			i = 0;
			j++;
		}
	}
	return next;
}

实现KMP算法:

int KMP(char* str1, char* str2, int next[]){
	int i, j;
	i = 0; j = 0;
	while (str1[i] != '\0'&&str2[j] != '\0'){
		if (str1[i] == str2[j]){
			i++;
			j++;
		}
		else
		{
			if (j > 0)//考虑到如果如果当j跳到0时,那么在进行j-1会出现溢出
				j = next[j - 1];
			else{
				j = 0;
				if (str1[i] != str2[j])
					i++;
			}
		}
			
	}
	if (str2[j] == '\0')
		return i - j + 1;
	else
		return -1;
}

最终代码及结果:

#include<iostream>
using namespace std;
int *get_next(char* str,int next[],int size){//求解next[]数组,得到前缀表
	int i = 0;//指向前缀的末尾端
	int j = 1;//指向后缀的起始段
	next[0] = 0;
	while (size--){
		if (str[i] == str[j]){
			next[j] = next[j - 1] + 1;
			i++;
			j++;
		}
		else{
			next[j] = 0;
			i = 0;
			j++;
		}
	}
	return next;
}
int KMP(char* str1, char* str2, int next[]){//利用前缀表进行匹配,总感觉自己写到好冗余啊
	int i, j;
	i = 0; j = 0;
	while (str1[i] != '\0'&&str2[j] != '\0'){
		if (str1[i] == str2[j]){
			i++;
			j++;
		}
		else
		{
			if (j > 0)//考虑到如果如果当j跳到0时,那么在进行j-1会出现溢出
				j = next[j - 1];
			else{
				j = 0;
				if (str1[i] != str2[j])
					i++;
			}
		}
			
	}
	if (str2[j] == '\0')
		return i - j + 1;
	else
		return -1;
}
int main(){
	char str1[] = "abcabcabcdefg";
	char str2[] = "defg";
	int size = sizeof(str2) / sizeof(str2[0]) - 1;
	int* next =(int*)malloc(sizeof(int)*size);
   
	get_next(str2, next, size);//利用get_next()函数,求出next[]数组
	int n = KMP(str1,str2,next);
	if (n != -1)
		cout << "存在所求字符串" <<"在字符串的"<<n<<"位置"<< endl;
	else
		cout << "不存在" << endl;
}

在这里插入图片描述
以上都是我个人所思所得,如果有错误,欢迎在评论区指正。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值